美文网首页Android动画Android资源收录
Material Design(二)动画实现上

Material Design(二)动画实现上

作者: 前世小书童 | 来源:发表于2016-02-20 13:25 被阅读2187次

    写在前面的几句话

    <p>
    上一篇对Material Design 有简单的认识与了解了,我相信大家应该对Material Desgin有一定的认知了把,同时我相信绝大部分的童鞋应该对于其中的动画很感兴趣,那么这一篇就介绍下Material Design的动画实现,由于这些动画效果是在5.0上才提供Api的,那么如何在5.0以下的系统实现相似甚至相同的效果呢?那么本篇文章就对這方面进行详细的介绍,由于内容较多,那么我会分为上下两个文章进行说明。

    分类

    <p>
    根据动画的类别和提供的类和属性等,可以将 Material Design Animation分为 6 类

    Touch Feedback (触摸反馈)

    Reveal Effect (揭露效果)

    Curved Motion (曲线运动)

    View State Changes (视图状态改变)

    Animate View Drawables (可绘矢量动画)

    Activity Transitions ( Activity 切换效果 )

    接下来就对这6类动画进行说明,及在5.0系统下如何实现相似效果
    <p>

    一.Touch Feedback (触摸反馈)

    <p>
    触摸反馈应该很好理解,平时开发中,其实也会对触控有不同的反馈,比如变灰呀等等,但是5.0的触控反馈其实是加入了涟漪(波纹)效应,这也是与之前的触控反馈有不同的地方

    按钮的默认触摸反馈动画是使用了新的RippleDrawable类,它会是波纹效果在不同状态间变换。

    大多数情况下,我们可以使用这个功能通过在xml文件中定义背景:

    android:attr/selectableItemBackground 有界限的波纹
    android:attr/selectableItemBackgroundBorderless 可以超出视图区域的波纹 (21新添加的api)

    <Button android:layout_width="100dp" 
               android:layout_height="50dp"    
               android:background="?android:attr/selectableItemBackground"    
               android:text="有界"    
               android:textColor="@android:color/white"        
               android:colorControlHighlight="@android:color/holo_red_dark"    
              android:layout_marginTop="20dp"    />
    
    <Button android:layout_width="100dp" 
             android:layout_height="50dp"    
             android:background="?android:attr/selectableItemBackgroundBorderless" 
             android:textColor="@android:color/white"   
             android:text="无界"    
             android:layout_marginTop="20dp"    />
    

    你可以给RippleDrawable对象分配一个颜色。使用主题的android:colorControlHighlight
    属性可以改变默认的触摸反馈颜色。

    另外,也可以自定义按钮的效果,这里使用ripple元素定义RippleDrawable作为一个xml资源

    ripple_button.xml

    <?xml version="1.0" encoding="utf-8"?>
    <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="@android:color/holo_blue_light" android:radius="20dp">
    
        <item android:drawable="@android:color/holo_green_dark" />
    
        <!--<item>-->
        <!--<shape-->
        <!--android:shape="oval">-->
        <!--<solid android:color="?android:colorAccent" />-->
        <!--</shape>-->
        <!--</item>-->
    
        <!--<item>-->
        <!--<shape android:shape="rectangle">-->
        <!--<solid android:color="#FFFFFF" />-->
        <!--<corners android:radius="4dp" />-->
        <!--</shape>-->
        <!--</item>-->
    
        <!--<item android:drawable="@drawable/ic_launcher" />-->
    </ripple>
    

    xml定义了需要定义color,这个color代表按下后的涟漪效果的颜色,内部的内容则和Style样式一致

    <Button android:layout_width="100dp" android:layout_height="50dp"
        android:background="@drawable/ripple_button"
        android:textColor="@android:color/white"
        android:text="自定义1"
        android:layout_marginTop="20dp"
        />
    
    图1 5.0系统的触摸反馈

    那么如何在低版本下实现这种涟漪的效果呢?

    自然要去自定义控件来实现了

    主要的代码则是这部分

     //绘制按下后的整个背景
    canvas.drawRect(pointX, pointY, pointX + viewWidth, pointY + viewHeight, bottomPaint);
    canvas.save();
    //绘制扩散圆形背景
    canvas.clipRect(pointX, pointY, pointX + viewWidth, pointY + viewHeight);
    canvas.drawCircle(eventX, eventY, shaderRadio, colorPaint);
    canvas.restore();
    

    这里则是绘制涟漪的代码,自定义控件又分为两个方向了,第一种是自定义单个控件,这个控件有这种点击的效果,另外一种则是定义一个layout,layout内部的控件点击都具有这种涟漪效果

    图2 5.0以下实现触摸反馈的效果

    上面红色的区域为自定义的Button,下面的部分为自定义的layout,可以看到TextView也有与Button同样的效果

    <p>

    二.Reveal Effect (揭露效果)

    <p>
    揭露动画为用户提供视觉上的持续性挡显示或者隐藏一组界面元素

    Android 5.0 引入了 ViewAnimationUtils.createCircularReveal()接口来提供动画效果来揭露或者隐藏一个视图

    Animator animator;
    if (isFirst){
        animator = ViewAnimationUtils.createCircularReveal(
                v,
                cx,
                cy,
                v.getWidth(),
                0
        );
    }else {
        animator = ViewAnimationUtils.createCircularReveal(
                v,
                cx,
                cy,
                0,
                v.getWidth()
        );
    }
    animator.setInterpolator(new DecelerateInterpolator());
    animator.setDuration(500);
    
    图3 5.0的揭露效果

    <p>

    三.Curved Motion (曲线运动)

    <p>

    Material Design中,动画依赖时间插值和空间移动模式曲线。在android5.0(api 21)和更高版本,你可以为动画自定义时间曲线和移动曲线。

    PathInterpolator: 以三次 bezier 曲线中间 2 个控制点的坐标来定义动画的速率快慢

    PathInterpolator类是一个新的基于贝塞尔曲线或Path对象的插值器。这个插值器在1*1的正方形上定义了曲线运动,以(0,0)和(1,1)点作为锚点,根据够照参数控制点。你也可以使用xml文件的定义一个路径插值器,如:

    <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
        android:controlX1="0.4"
        android:controlY1="0"
        android:controlX2="1"
        android:controlY2="1"/>
    

    Material Design设计规范中,系统提供了三个基本曲线的xml资源:

    • @interpolator/fast_out_linear_in.xml
    • @interpolator/fast_out_slow_in.xml
    • @interpolator/linear_out_slow_in.xml

    我们可以给Animator.setInterpolator()传一个PathInterpolator对象来设置。

    ObjectAnimator.ofFloat(T target, Property<T, Float> xProperty, Property<T, Float> yProperty, Path path): 中间的 path参数定义位移动画的路径。

    Path path = new Path();
    path.lineTo(0,300);
    path.cubicTo(100, 0, 300, 900, 500, 600);
    
    
    PathInterpolator pathInterpolator = new PathInterpolator(0.8f, 0f, 1f, 1f);
    final ObjectAnimator mAnimator = ObjectAnimator.ofFloat(v, View.X, View.Y, path);
    mAnimator.setInterpolator(pathInterpolator);
    mAnimator.setDuration(3000);
    mAnimator.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            super.onAnimationEnd(animation);
        }
    });
    mAnimator.start();
    
    图4 5.0的曲线运动

    那么如何在低版本下实现这种曲线运动的效果呢?

    我总结了下有两种方式,一种为PathMeasure,另一种为TypeEvaluator,PathMeasure在前面的Path学习笔记中有介绍,关于TypeEvaluator会在后面动画学习笔记中进行介绍

    直接上代码,第一种为PathMeasure实现方式

    mPath = new Path();
    mPath.moveTo(0, 0);
    mPath.lineTo(0, 300);
    mPath.cubicTo(100, 0, 300, 900, 500, 600);
    
    mPathMeasure = new PathMeasure(mPath, true);
    mCurrentPosition = new float[2];
    
    ValueAnimator valueAnimator = ValueAnimator.ofFloat((float)0, mPathMeasure.getLength() - (float)Math.sqrt((double)(500*500 + 600*600)) );
    valueAnimator.setDuration(3000);
    // 减速插值器
    valueAnimator.setInterpolator(new DecelerateInterpolator());
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            float value = (Float) animation.getAnimatedValue();
            // 获取当前点坐标封装到mCurrentPosition
            mPathMeasure.getPosTan(value, mCurrentPosition, null);
            postInvalidate();
        }
    });
    valueAnimator.start();
    
    canvas.drawCircle(mCurrentPosition[0], mCurrentPosition[1], 10, mPaint);
    
    图4 PathMeasure的曲线运动

    第二种为是TypeEvaluator实现方式

    public class BezierEvaluator implements TypeEvaluator<PointF>{
        //途径的两个点
        private PointF pointF1;
        private PointF pointF2;
        public BezierEvaluator(PointF pointF1, PointF pointF2) {
            this.pointF1 = pointF1;
            this.pointF2 = pointF2;
        }
        @Override
        public PointF evaluate(float time, PointF startValue, PointF endValue) {
            float timeLeft = 1.0f - time;
            PointF point = new PointF();
            PointF point0 = (PointF)startValue;//起点
            PointF point3 = (PointF)endValue;//终点
            //代入公式
            point.x = timeLeft * timeLeft * timeLeft * (point0.x)
                    + 3 * timeLeft * timeLeft * time * (pointF1.x)
                    + 3 * timeLeft * time * time * (pointF2.x)
                    + time * time * time * (point3.x);
            point.y = timeLeft * timeLeft * timeLeft * (point0.y)
                    + 3 * timeLeft * timeLeft * time * (pointF1.y)
                    + 3 * timeLeft * time * time * (pointF2.y)
                    + time * time * time * (point3.y);
            return point;
        }
    }
    
    ObjectAnimator animator1 = ObjectAnimator.ofFloat(button,View.TRANSLATION_Y,0,300);
    animator1.setDuration(600);
    
    BezierEvaluator evaluator = new BezierEvaluator(new PointF(100,0),new PointF(300,900));
    ValueAnimator animator = ValueAnimator.ofObject(evaluator,new PointF(0,300),new PointF(500,600));//随机
    animator.addUpdateListener(new BezierListenr(button));
    animator.setDuration(2400);
    
    AnimatorSet allSet = new AnimatorSet();
    allSet.play(animator1).before(animator);
    allSet.start();
    
    private class BezierListenr implements ValueAnimator.AnimatorUpdateListener{
        private View target;
        public BezierListenr(View target) {
            this.target = target;
        }
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            PointF pointF = (PointF) animation.getAnimatedValue();
            target.setX(pointF.x);
            target.setY(pointF.y);
        }
    }
    
    图5 TypeEvaluator的曲线运动

    四.View State Changes (视图状态改变)

    <p>
    Android 5.0提供了StateListAnimator类,可以用来定义动画集

    1.定义一个XML资源的StateListAnimator

    anim_statelistanimater

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_pressed="true">
            <set>
                <objectAnimator android:propertyName="translationZ"
                    android:duration="@android:integer/config_shortAnimTime"
                    android:valueTo="10"
                    android:valueType="floatType"/>
    
                <objectAnimator android:propertyName="rotationX"
                    android:duration="@android:integer/config_shortAnimTime"
                    android:valueTo="360"
                    android:valueType="floatType"/>
            </set>
        </item>
        <item android:state_pressed="false">
            <set>
                <objectAnimator android:propertyName="translationZ"
                    android:duration="10000"
                    android:valueTo="0"
                    android:valueType="floatType"/>
                <objectAnimator android:propertyName="rotationX"
                    android:duration="@android:integer/config_shortAnimTime"
                    android:valueTo="0"
                    android:valueType="floatType"/>
            </set>
        </item>
    </selector>
    

    2.配置,配置分为两种一种为动态配置一种为静态配置

    (1)静态配置

    <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="button2"
            android:stateListAnimator="@anim/anim_statelistanimator"
            />
    

    (2)动态配置

    StateListAnimator stateLAnim = AnimatorInflater.loadStateListAnimator(this, R.anim.anim_statelistanimator);
    button3.setStateListAnimator(stateLAnim);
    
    图6 5.0的视图状态改变效果

    那么如何在低版本下实现这种视图状态改变的效果呢?

    很简单,其实XML资源的StateListAnimator就是一些Animator的集合

    所以直接对需要动画的对象设置Animator就可以了

    anim_statechange.xml

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:ordering="together" >
    
        <objectAnimator android:propertyName="translationZ"
            android:duration="@android:integer/config_shortAnimTime"
            android:valueTo="10"
            android:valueType="floatType"/>
    
        <objectAnimator android:propertyName="rotationX"
            android:duration="@android:integer/config_shortAnimTime"
            android:valueTo="360"
            android:valueType="floatType"/>
    
    </set>
    
    anim = AnimatorInflater.loadAnimator(this, R.anim.anim_state);
    anim.setTarget(view);
    anim.start();
    
    图7 5.0以下视图状态改变效果

    写在后面的几句

    <p>
    至此我们分析了Touch Feedback (触摸反馈),Reveal Effect (揭露效果),Curved Motion (曲线运动),View State Changes (视图状态改变)动画效果在5.0及5.0以下的实现效果,那么后面的两个Animate View Drawables (可绘矢量动画),Activity Transitions ( Activity 切换效果 )会在Material Design(三)动画实现下中进行分析。。

    相关文章

      网友评论

      本文标题:Material Design(二)动画实现上

      本文链接:https://www.haomeiwen.com/subject/xhkvkttx.html