第一次在项目中使用属性动画来做popupWindow,遇到了一大堆问题,耽误了好久,终于完了,写个总结。
理解
什么叫属性动画呢?
我的理解就是一个控件或者多个控件在一定的范围内进行各种运动,它不会回头,而是一如既往的向前运动,与帧动画不一样。
打个比较形象的例子,一个人沿着操场跑步,帧动画是100米的往返跑,属性动画则是沿着整个操场跑,也许会经过原点,但是它没有一个折返的过程。属性动画是一个过程,它适合一个长时间的动画效果。
在popupWindow中使用的时候这里有几个问题需要注意:
1、ObjectAnimator方法的使用
2、OvershootInterpolator等补间器(插值器)的使用
3、如果需要用到overridePendingTransition,则要注意参数的理解
ObjectAnimator的使用
这里要先说一下这个PropertyValuesHolder
PropertyValuesHolder这个类拥有关于属性的信息和动画期间需要使用的值。它可以用来和ObjectAnimator或ValueAnimator一起创建可以并行操作PropertyValuesHolder不同属性的animator。
对PropertyValuesHolder的初始化:
final PropertyValuesHolder p = PropertyValuesHolder.ofFloat("translationY", 0, xF);
//final 这里是为了把方法锁定,防止任何继承类修改它的意义和实现。translationY 是沿Y轴翻转,0是起始点的位置,xF是从起始点移动到指定点的距离
然后就是对p的使用
ObjectAnimator animatorStart =ObjectAnimator.ofPropertyValuesHolder(textView, p);
//属性动画ObjectAnimation,(x,x,x)为动画效果,在PropertyValuesHolder中设置
animatorStart.setInterpolator(new OvershootInterpolator());//插值器
animatorStart.setDuration(350);//动画的速度
animatorStart.start();
//textView 为控件集合在重新定义的textView
OvershootInterpolator等补间器(插值器)的使用
这里传上一副比较常见的补间器图:
补间器:拆开来说,补——补充、间——时间。连在一起就是补充时间的一个工具,那么补充的是什么时间呢?用在这里的花就是说补充动画的时间,效果就是在原有的动画基础上再增加一些动画,这样会使得动画更有活力,更好看。
overridePendingTransition
overridePendingTransition(int, out);//()括号内的int,out是开始和结束的意思。例如
(R.anim.push_right_in,R.anim.push_right_out)。一个动画开始的效果,一个是动画结束的效果。
如果光是这样用的话,会发现滑动后会出现黑屏的问题,这个时候就要注意把第二个参数换成一个透明度,这样就好了!
R.anim.push_right_in:
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="500"
android:fromXDelta="100%p"
android:toYDelta="0"
/>
</set>
push_alpha_in.xml:
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:fromAlpha="1"
android:toAlpha="1"
android:duration="300"
/>
</set>
PopupWindow主要的几个方法:
//这里我是继承的封装的BasePopupWindow调用的布局
@Override
protected int getLayoutRes() {
return R.layout.pop_contribute;
}
@Override
protected void initPopupWindow(Activity activity, View contentView) {
//获取popupwindow的高度与宽度
int width = DisplayUtil.getScreenWidth(activity);
int height = DisplayUtil.getScreenHeight(activity);
Logger.i("width =" + width + " height =" + height);
// // 设置弹出窗体的宽
setWidth(width);
// // 设置弹出窗体的高
setHeight(height);
.............
setFocusable(true);
setOutsideTouchable(true);
setBackgroundDrawable(null);
setTouchable(true);
}
/**
* 开始动画
*/
private void startAnimation() {
for (int i = 0; i < textViewList.size(); i++) {
final View textView = textViewList.get(i);
new Handler().postDelayed(new Runnable() {//延迟发送postDelayed
@Override
public void run() {
textView.setVisibility(View.VISIBLE);
// ObjectAnimator animatorStart = ObjectAnimator.ofPropertyValuesHolder(textView, p);//属性动画ObjectAnimation,(x,x,x)为动画效果,在PropertyValuesHolder中设置
// animatorStart.setInterpolator(new OvershootInterpolator());//伸缩弹力动画
// animatorStart.setDuration(350);//进入的时间
// animatorStart.start();
int[] location = new int[2];//将屏幕分成2份,location[0]是投稿控件所占满的部分,location[1]是整个屏幕减去投稿控件的部分
textView.getLocationInWindow(location); //获取在当前窗口内的绝对坐标
textView.getLocationOnScreen(location);//获取在整个屏幕内的绝对坐标
float curTranslationY = textView.getTranslationY();
Logger.i("curTranslationY=" + curTranslationY + " " + textView.getBottom());
ObjectAnimator animator = ObjectAnimator.ofFloat(textView, "translationY", DisplayUtil.getScreenHeight(activity) - location[1], 0f);
animator.setInterpolator(new OvershootInterpolator());//伸缩弹力动画-插值器
animator.setDuration(250);
animator.start();
}
// }
}, 120 * i);//每一个控件的间隔时间
}
}
/**
* * 关闭动画
*/
private void stopAnimation() {
//PropertyValuesHolder这个类拥有关于属性的信息和动画期间需要使用的值。PropertyValuesHolder对象
// 可以用来和ObjectAnimator或ValueAnimator一起创建可以并行操作不PropertyValuesHolder同属性的animator。
// final PropertyValuesHolder p = PropertyValuesHolder.ofFloat("translationY", 0, 500F);
for (int i = textViewList.size() - 1; i >= 0; i--) {
final View textView = textViewList.get(i);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
int[] location = new int[2];
textView.getLocationInWindow(location); //获取在当前窗口内的绝对坐标
textView.getLocationOnScreen(location);//获取在整个屏幕内的绝对坐标\
float curTranslationY = textView.getTranslationY();
Logger.i("curTranslationY=" + curTranslationY + " " + textView.getBottom());
ObjectAnimator animator = ObjectAnimator.ofFloat(textView, "translationY", 0f, location[1]);
animator.setInterpolator(new OvershootInterpolator());//伸缩弹力动画-插值器
animator.setDuration(1500);
animator.start();
}
}, 100 * (textViewList.size() - 1 - i));
}
}
MainActivity:
new ContributePopupWindow(MainActivity.this).showPopupWindow(xx);
//xx为点击PopupWindow的控件
最后,这里我遇到了几个坑,
1、setAnimationStyle(android.R.style.Animation_InputMethod);
popupWindow的动画与控件动画应该是会冲突,这样会产生卡顿,毕竟是同步执行的,如有错误请见谅。
2、textViewList = new ArrayList<>();注意集合的初始化地方和其List<>中类型的设置。
3、setBackgroundDrawable(null);这个属性必须设置,不然会出现非常无语的问题。()中的参数可以自行设置。