Material Design(二)动画实现上

写在前面的几句话


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

分类


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

Touch Feedback (触摸反馈)

Reveal Effect (揭露效果)

Curved Motion (曲线运动)

View State Changes (视图状态改变)

Animate View Drawables (可绘矢量动画)

Activity Transitions ( Activity 切换效果 )

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

一.Touch Feedback (触摸反馈)


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

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

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

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

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

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

ripple_button.xml




    

    
    
    
    
    
    

    
    
    
    
    
    

    

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

Material Design(二)动画实现上_第1张图片
图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内部的控件点击都具有这种涟漪效果

Material Design(二)动画实现上_第2张图片
图2 5.0以下实现触摸反馈的效果

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

二.Reveal Effect (揭露效果)


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

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);
Material Design(二)动画实现上_第3张图片
图3 5.0的揭露效果

三.Curved Motion (曲线运动)

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

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

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


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 xProperty, Property 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();
Material Design(二)动画实现上_第4张图片
图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);
Material Design(二)动画实现上_第5张图片
图4 PathMeasure的曲线运动

第二种为是TypeEvaluator实现方式

public class BezierEvaluator implements TypeEvaluator{
    //途径的两个点
    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);
    }
}
Material Design(二)动画实现上_第6张图片
图5 TypeEvaluator的曲线运动

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


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

1.定义一个XML资源的StateListAnimator

anim_statelistanimater



    
        
            

            
        
    
    
        
            
            
        
    

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

(1)静态配置

(2)动态配置

StateListAnimator stateLAnim = AnimatorInflater.loadStateListAnimator(this, R.anim.anim_statelistanimator);
button3.setStateListAnimator(stateLAnim);
Material Design(二)动画实现上_第7张图片
图6 5.0的视图状态改变效果

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

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

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

anim_statechange.xml




    

    


anim = AnimatorInflater.loadAnimator(this, R.anim.anim_state);
anim.setTarget(view);
anim.start();
Material Design(二)动画实现上_第8张图片
图7 5.0以下视图状态改变效果

写在后面的几句


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

你可能感兴趣的:(Material Design(二)动画实现上)