android 自定义view如何控制view的高度_Android自定义View属性动画

属性动画

DEMO地址:https://github.com/chaozhouzhang/CustomProgressView

1、值动画 ValueAnimator

值动画具体实现步骤:

/**
 * 属性动画之值动画:
 * 1、指定动画数值区间
 * 2、指定插值器,定义动画数值的进度变化规律
 * 3、指定估值器,根据插值器的进度变化规律,计算具体的动画数值
 * 4、设置监听器,监听估值器返回的具体动画数值,然后根据此具体数值,来对控件做出属性变化的设置操作
 */

使用值动画,实现抛物动画:

ValueAnimator animator = ValueAnimator.ofObject(new FallingBallEvaluator(),new Point(0,0),new Point(500,500));
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        mPoint = (Point) animation.getAnimatedValue();
        mIvBall.layout(mPoint.x,mPoint.y,mPoint.x+mIvBall.getWidth(),mPoint.y+mIvBall.getHeight());
    }
});
animator.setDuration(2000);
animator.start();

c241db6e3a44710216fdc17095c0b15d.gif

DEMO地址:https://github.com/chaozhouzhang/CustomProgressView/blob/master/CustomProgressView/app/src/main/java/androidstack/progress/animation/property/value/FallingBallValueActivity.java

2、对象动画 ObjectAnimator

对象动画具体实现步骤:

/**
 * 属性动画之对象动画:
 * 1、指定动画数值区间以及属性和控件
 * 2、指定插值器,定义动画数值的进度变化规律
 * 3、指定估值器,根据插值器的进度变化规律,计算具体的动画数值
 * 4、系统自定调用控件的set方法,根据属性拼装set方法并反射调用,并将当前值作为参数传入
 */

自定义ImageView:

public class FallingImageView extends androidx.appcompat.widget.AppCompatImageView {

    public FallingImageView(Context context) {
        super(context);
    }

    public FallingImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FallingImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * 对象动画会使用反射自动调用此set方法
     * @param point
     */
    public void setFallingPos(Point point){
        layout(point.x,point.y,point.x+getWidth(),point.y+getHeight());
    }

    /**
     * 当指定一个动画值时,动画会通过get方法来获取初始值,否则会崩溃
     * @return
     */
    public Point getFallingPos(){
        return new Point(0,0);
    } 
}

使用值动画,实现抛物动画:

ObjectAnimator objectAnimator = ObjectAnimator.ofObject(mIvBall,"fallingPos",new FallingBallEvaluator(),new Point(0,0),new Point(500,500));
objectAnimator.setDuration(2000);
objectAnimator.start();

DEMO地址:https://github.com/chaozhouzhang/CustomProgressView/blob/master/CustomProgressView/app/src/main/java/androidstack/progress/animation/property/object/FallingBallObjectActivity.java

3、动画集合 AnimatorSet

使用动画集合实现菜单动画:

开:

private void menuOpen(View view, int currIndex, int totalIndex, int radius) {
    //每一份角度
    double degree = Math.toRadians(90) / (totalIndex - 1) * currIndex;
    //X轴移动距离
    int translationX = -(int) (radius * Math.sin(degree));
    //Y轴移动距离
    int translationY = -(int) (radius * Math.cos(degree));
    AnimatorSet animatorSet = new AnimatorSet();
    ObjectAnimator objectAnimatorTranslationX = ObjectAnimator.ofFloat(view, "translationX", 0, translationX);
    ObjectAnimator objectAnimatorTranslationY = ObjectAnimator.ofFloat(view, "translationY", 0, translationY);
    ObjectAnimator objectAnimatorScaleX = ObjectAnimator.ofFloat(view, "ScaleX", 0F, 1F);
    ObjectAnimator objectAnimatorScaleY = ObjectAnimator.ofFloat(view, "ScaleY", 0F, 1F);
    ObjectAnimator objectAnimatorAlpha = ObjectAnimator.ofFloat(view, "alpha", 0F, 1F);
    animatorSet.playTogether(objectAnimatorTranslationX, objectAnimatorTranslationY, objectAnimatorScaleX, objectAnimatorScaleY, objectAnimatorAlpha);
    animatorSet.setDuration(500);
    animatorSet.start();
}

关:

private void menuClose(View view, int currIndex, int totalIndex, int radius) {
    //每一份角度
    double degree = Math.PI * currIndex /((totalIndex-1)*2);
    //X轴移动距离
    int translationX = -(int) (radius * Math.sin(degree));
    //Y轴移动距离
    int translationY = -(int) (radius * Math.cos(degree));
    
    AnimatorSet animatorSet = new AnimatorSet();
    ObjectAnimator objectAnimatorTranslationX = ObjectAnimator.ofFloat(view, "translationX", translationX, 0);
    ObjectAnimator objectAnimatorTranslationY = ObjectAnimator.ofFloat(view, "translationY", translationY, 0);
    ObjectAnimator objectAnimatorScaleX = ObjectAnimator.ofFloat(view, "ScaleX", 1F, 0F);
    ObjectAnimator objectAnimatorScaleY = ObjectAnimator.ofFloat(view, "ScaleY", 1F, 0F);
    ObjectAnimator objectAnimatorAlpha = ObjectAnimator.ofFloat(view, "alpha", 1F, 0F);
    animatorSet.playTogether(objectAnimatorTranslationX, objectAnimatorTranslationY, objectAnimatorScaleX, objectAnimatorScaleY, objectAnimatorAlpha);
    animatorSet.setDuration(500);
    animatorSet.start();
}

62a89e3f1727a8e1e328abfce4d67fde.gif

DEMO地址:https://github.com/chaozhouzhang/CustomProgressView/blob/master/CustomProgressView/app/src/main/java/androidstack/progress/animation/property/set/MenuActivity.java

4、属性值与关键帧 PropertyValuesHolder Keyframe

/**
 * 关键帧,为了方便控制动画速率,表示某个时间点应该在某个位置上
 * 视频,1秒要播24帧图片
 * 一个关键帧的两个元素:时间点和位置
 * fraction 动画进度
 * value 对应动画进度的动画数值
 * KeyFrame可以设置插值器,默认使用线性插值器
 * 可以做电话响铃的动画,一张电话图片,11张关键帧
 */

使用属性值和关键帧实现电话铃响动画:

//旋转效果,左右震动
Keyframe keyframe1 = Keyframe.ofFloat(0f, 0);
Keyframe keyframe2 = Keyframe.ofFloat(0.1f, -20f);
Keyframe keyframe3 = Keyframe.ofFloat(0.2f, 20f);
Keyframe keyframe4 = Keyframe.ofFloat(0.3f, -20f);
Keyframe keyframe5 = Keyframe.ofFloat(0.4f, 20f);
Keyframe keyframe6 = Keyframe.ofFloat(0.5f, -20f);
Keyframe keyframe7 = Keyframe.ofFloat(0.6f, 20f);
Keyframe keyframe8 = Keyframe.ofFloat(0.7f, -20f);
Keyframe keyframe9 = Keyframe.ofFloat(0.8f, 20f);
Keyframe keyframe10 = Keyframe.ofFloat(0.9f, -20f);
Keyframe keyframe11 = Keyframe.ofFloat(1.0f, 0f);
PropertyValuesHolder propertyValuesHolder = PropertyValuesHolder.ofKeyframe("rotation",
        keyframe1, keyframe1, keyframe2, keyframe3, keyframe4, keyframe5,
        keyframe6, keyframe7, keyframe8, keyframe9, keyframe10, keyframe11);
//缩放效果 X
Keyframe keyframeScaleX0 = Keyframe.ofFloat(0,1f);
Keyframe keyframeScaleX1 = Keyframe.ofFloat(0.1f,1.1f);
Keyframe keyframeScaleX9 = Keyframe.ofFloat(0.9f,1.1f);
Keyframe keyframeScaleX10 = Keyframe.ofFloat(1f,1f);
    PropertyValuesHolder propertyValuesHolderScaleX = PropertyValuesHolder.ofKeyframe("ScaleX",
            keyframeScaleX0,keyframeScaleX1,keyframeScaleX9,keyframeScaleX10);

//缩放效果 Y
Keyframe keyframeScaleY0 = Keyframe.ofFloat(0,1f);
Keyframe keyframeScaleY1 = Keyframe.ofFloat(0.1f,1.1f);
Keyframe keyframeScaleY9 = Keyframe.ofFloat(0.9f,1.1f);
Keyframe keyframeScaleY10 = Keyframe.ofFloat(1f,1f);
PropertyValuesHolder propertyValuesHolderScaleY = PropertyValuesHolder.ofKeyframe("ScaleY",
        keyframeScaleY0,keyframeScaleY1,keyframeScaleY9,keyframeScaleY10);

ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(mIvPhone,
        propertyValuesHolder,propertyValuesHolderScaleX,propertyValuesHolderScaleY);
objectAnimator.setDuration(1000);
objectAnimator.start();

fb4ee70c0e31478478c7d353545a2957.gif

DEMO地址:https://github.com/chaozhouzhang/CustomProgressView/blob/master/CustomProgressView/app/src/main/java/androidstack/progress/animation/property/advanced/PhoneActivity.java

5、布局动画 LayoutTransition

/**
 * LayoutTransition.APPEARING;新元素在容器中出现时的动画;
 * LayoutTransition.CHANGE_APPEARING;容器中显示新元素,其他元素需要变化时的动画;
 * LayoutTransition.CHANGE_DISAPPEARING;容器中移除旧元素,其他元素需要变化时的动画;
 * LayoutTransition.CHANGING;
 * LayoutTransition.DISAPPEARING;旧元素在容器中移除时的动画;
 */

实现移除布局内控件的动画:

/**
 * 设置移除容器内图片控件时候的动画
 */
LayoutTransition layoutTransition = new LayoutTransition();
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f);
layoutTransition.setAnimator(LayoutTransition.DISAPPEARING, objectAnimator);
/**
 * 设置动画间的间隔
 */
layoutTransition.setStagger(LayoutTransition.DISAPPEARING, 1000);
mClLayoutTransition.setLayoutTransition(layoutTransition);
/**
 * 移除布局
 */
mClLayoutTransition.removeView(mIvTest);

DEMO地址:https://github.com/chaozhouzhang/CustomProgressView/blob/master/CustomProgressView/app/src/main/java/androidstack/progress/animation/property/advanced/ViewGroupAnimateActivity.java

6、估值器 Evaluator

估值器,根据插值器的数值进度变化规律,计算出具体的动画数值。
自定义估值器,实现类型估值器TypeEvaluator,并传入泛型的具体类型。
扩展:
自定义插值器,实现时间插值器TimeInterpolator后,实现获取插值Interpolation的方法,也可以直接实现插值器Interpolator,因为Interpolator继承的是时间插值器TimeInterpolator。

自定义估值器:

public class ReverseEvaluator implements TypeEvaluator {
    /**
     * @param fraction   插值器中的进度返回值
     * @param startValue 动画数值区间的起始数值
     * @param endValue   动画数值区间的结束数值
     * @return 估值器返回给监听器的具体动画数值
     */
    @Override
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {return (int) (endValue - fraction * (endValue - startValue));
    }
}

DEMO地址:https://github.com/chaozhouzhang/CustomProgressView/blob/master/CustomProgressView/app/src/main/java/androidstack/progress/animation/property/evaluator/ReverseEvaluator.java

欢迎关注微信公众号,Android技术堆栈:

449a0584d183fdd50dc7e1918469a44e.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值