layout: post
title: 属性动画的研究——多级菜单展开
date: 2017-07-26 16:33:11
tags:
- Android开发
categories: - Android开发
很久都没有更新博客了,之前一直忙着参加挑战杯,然后就是期末考试,再然后在室友的乱带节奏下准备找实习。现在找到了一份实习工作,老大还在给新项目打框架,让我先研究下动画,说是后面会用到,就忙里偷闲玩demo
- 是看imooc上面的一个大神的课程-http://www.imooc.com/learn/263。讲的很nice,然后我就继续深入了一点点,完善了demo而已。
效果图
[外链图片转存失败(img-DYBKk8KJ-1562312416902)(https://pic.sorgs.cn/属性动画_菜单展开.gif)]https://pic.sorgs.cn/属性动画_菜单展开.gif)
分析
- 首先是采用了属性动画的方式
- 在x和y上面做手脚去变化坐标
PropertyValuesHolder Y, X;
//设置动画
Y = PropertyValuesHolder.ofFloat("translationY", y);
X = PropertyValuesHolder.ofFloat("translationX", x);
//添加动画集合
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(imageViewList.get(i), X, Y);
- 然后是两个动画一起
- 使用抖动效果(使用了BounceInterpolator)[可能gif有些看不出来]
//为控件增加自由落体动画效果
animator.setInterpolator(new BounceInterpolator());
计算坐标
我们的展开是一个半圆的扇形,那么肯定就是利用数学函数来进行计算,如图
[外链图片转存失败(img-rvcOlo1I-1562312480703)(https://pic.sorgs.cn/属性动画_菜单展开说明.jpg)]
从上面到下面,x是从最大到0,y是从0到最大
每一个点的坐标就是根据圆心角来计算
//需要扩散的角度 以180度为例
float angle = (float) (Math.PI * 180 / 180);
//计算偏移的x,y坐标
x = (float) (n * Math.sin(angle / (res.length - 1) * count));
y = (float) (n * Math.cos(angle / (res.length - 1) * count));
完整代码
- 布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<ImageView
android:id="@+id/iv_h"
style="@style/ImageView"
android:src="@mipmap/h"/>
<ImageView
android:id="@+id/iv_g"
style="@style/ImageView"
android:src="@mipmap/g"/>
<ImageView
android:id="@+id/iv_f"
style="@style/ImageView"
android:src="@mipmap/f"/>
<ImageView
android:id="@+id/iv_e"
style="@style/ImageView"
android:src="@mipmap/e"/>
<ImageView
android:id="@+id/iv_d"
style="@style/ImageView"
android:src="@mipmap/d"/>
<ImageView
android:id="@+id/iv_c"
style="@style/ImageView"
android:src="@mipmap/c"/>
<ImageView
android:id="@+id/iv_b"
style="@style/ImageView"
android:src="@mipmap/b"/>
<ImageView
android:id="@+id/iv_a"
style="@style/ImageView"
android:src="@mipmap/a"/>
</RelativeLayout>
- 抽取的属性
<style name="ImageView">
<item name="android:layout_width">50dp</item>
<item name="android:layout_height">50dp</item>
<item name="android:paddingLeft">5dp</item>
<item name="android:paddingTop">5dp</item>
</style>
- 逻辑
package com.sorgs.animtest;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.BounceInterpolator;
import android.widget.ImageView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private int[] res = {R.id.iv_a, R.id.iv_b, R.id.iv_c, R.id.iv_d, R.id.iv_e, R.id.iv_f, R.id.iv_g, R.id.iv_h};
private List<ImageView> imageViewList = new ArrayList<>();
/**
* 菜单打开或者关闭的标志
*/
private boolean flag = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
for (int re : res) {
//循环添加每个控件
ImageView imageView = (ImageView) findViewById(re);
//为每个控件添加点击事件
imageView.setOnClickListener(this);
//将每个控件添加到List中
imageViewList.add(imageView);
}
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.iv_a:
if (flag) {
startAnim();
} else {
emdAnim();
}
break;
default:
//点击其他按钮,弹出toast
Toast.makeText(getApplication(), "click" + view.getId(), Toast.LENGTH_SHORT).show();
break;
}
}
/**
* 关闭菜单动画
*/
private void emdAnim() {
for (int i = 1; i < res.length; i++) {
PropertyValuesHolder Y, X;
//X Y 都回归原点
Y = PropertyValuesHolder.ofFloat("translationY", 0);
X = PropertyValuesHolder.ofFloat("translationX", 0);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(imageViewList.get(i), X, Y);
//设置动画执行时间
animator.setDuration(500);
//每个控件之间的延时,形成每个按钮依次出现
animator.setStartDelay(i * 300);
//为控件增加自由落体动画效果
animator.setInterpolator(new BounceInterpolator());
//执行动画
animator.start();
//重置flag
flag = true;
}
}
/**
* 打开菜单动画
*/
private void startAnim() {
//扩散的距离,获取控件的高度的2倍
float x, y, n = imageViewList.get(0).getMeasuredHeight() * 2;
for (int i = 1; i < res.length; i++) {
int count = res.length - i;
//需要扩散的角度 以180度为例
float angle = (float) (Math.PI * 180 / 180);
//计算偏移的x,y坐标
x = (float) (n * Math.sin(angle / (res.length - 1) * count));
y = (float) (n * Math.cos(angle / (res.length - 1) * count));
PropertyValuesHolder Y, X;
//设置动画
Y = PropertyValuesHolder.ofFloat("translationY", y);
X = PropertyValuesHolder.ofFloat("translationX", x);
//添加动画集合
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(imageViewList.get(i), X, Y);
//设置动画执行时间
animator.setDuration(500);
//每个控件之间的延时,形成每个按钮依次出现
animator.setStartDelay(i * 300);
//为控件增加自由落体动画效果
animator.setInterpolator(new BounceInterpolator());
//执行动画
animator.start();
//重置flag
flag = false;
}
}
}