1.简介
本文将着重介绍的是属性动画的学习与使用,案例比较简单,主要起一个笔记记录的作用,方便回顾。主要是学习的启航大神的自定义控件这本书,照着上面的例子自己进行实践下来的结果。学习自定义控件强烈推荐启航大神,csdn上有很多教程文章,很感谢他的分享。
2.动画案例
2.1 使用ValueAnimator 实现视图从底部平移
以下代码,分2步第一是获得底部窗体的y坐标,然后获得image的坐标长宽,值得注意的是getGlobalVisibleRect()获得的是该控件在整个窗体的,即窗口左上角为参考物获得的坐标,而使用layout是布局是向image的父亲组件申请摆放的位置,是有差异的,需要减除掉头部的标题以及状态栏的高度,这是值得注意的点。
方式1
使用getGlobalVisibleRect() 进行测量
// 主要是测量布局以及移动的物体
mImageView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
mImageView.getGlobalVisibleRect(mMeasureRect);
mImageBottom = mMeasureRect.bottom;
mImageLeft = mMeasureRect.left;
mImageRight = mMeasureRect.right;
mImageHeight = mMeasureRect.height();
mMain.getGlobalVisibleRect(mMeasureRect);
mWindowBottom = mMeasureRect.bottom;
mLinearTop = mMeasureRect.top;
mImageView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
/**
* 线性的从底部弹出
*/
private void showLinearFromBottom(){
final int distance = mWindowBottom - mImageBottom;
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1f);
valueAnimator.setDuration(2000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
// 在这个例子中 layout是在ID为main的线性布局中布局的
mImageView.layout(mImageLeft,
(int)(mWindowBottom - distance*value-mImageHeight-mLinearTop),
mImageRight,
(int)(mWindowBottom - distance*value-mLinearTop));
}
});
valueAnimator.start();
}
方式2【推荐】
使用getBottom()等进行测量,计算的是相对于父主件的上下左右长宽的距离。
mImageView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
mImageBottom = mImageView.getBottom();
mImageHeight = mImageView.getHeight();
mImageLeft = mImageView.getLeft();
mImageRight = mImageView.getRight();
mLinearBottom = mMain.getBottom();
mImageView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
/**
* 线性的从底部弹出
*/
private void showLinearFromBottom(){
final int distance = mLinearBottom - mImageBottom+mImageHeight;
mValueAnimator = ValueAnimator.ofFloat(0, 1f);
mValueAnimator.setDuration(2000);
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
// 在这个例子中 layout是在ID为main的线性布局中布局的
mImageView.layout(mImageLeft,
(int)(mLinearBottom - distance*value),
mImageRight,
(int)(mLinearBottom - distance*value+mImageHeight));
}
});
mValueAnimator.start();
}
// 注意回收 避免内存泄漏
@Override
protected void onDestroy() {
super.onDestroy();
if (mValueAnimator.isRunning()){
mValueAnimator.cancel();
mValueAnimator = null;
}
}
2.2 实现跳跃时动画
在activity中使用时,注意回收,避免造成内存泄漏问题。 使用setTop() View类中的方法完成重绘布局。
public class LoadImageView extends android.support.v7.widget.AppCompatImageView {
private int mTop;
private ValueAnimator mValueAnimator;
private int mCurrentIndex = 0;
private int mTotalImageCount = 3;
public LoadImageView(Context context) {
this(context,null);
}
public LoadImageView(Context context, AttributeSet attrs) {
this(context,attrs,0);
}
public LoadImageView(Context context, AttributeSet attrs, int defStyleAttr) {
supe