美文网首页Android开发那些事
面试准备(九)-- 补间动画、逐帧动画、属性动画

面试准备(九)-- 补间动画、逐帧动画、属性动画

作者: 你的益达233 | 来源:发表于2020-01-15 17:18 被阅读0次

    动画

    参考:https://www.jianshu.com/p/2412d00a0ce4
    分为三种:补间动画、逐帧动画、属性动画

    一、补间动画(Tweened Animation)

    作用对象:视图控件View
    原理: 通过确定开始的视图样式以及结束的视图样式,中间的动画变化过程有系统补全来确定一个动画
    优点:简单、方便,已封装好基础动画效果
    缺点:仅控制整体实体效果,无法控制属性
    动画样式: 平移动画(Translate)缩放动画(scale)旋转动画(rotate)透明度动画(alpha)
    应用场景:视图中,标准、基础的动画效果。Activity,Fragment的切换效果。ViewGroup中子元素的出场效果

    1.平移动画(Translate)

    TranslateAnimation类
    示例代码:

    <translate xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration = "3000"
        android:fromXDelta="0"
        android:toXDelta="300"
        android:fillBefore = "false"
        android:fillAfter = "true"
    />
    

    如上代码中,虽然通过fillBefore,fillAfter设置了停留在动画之后,但是控件还是在原来位置,点击动画后的位置无反应。如果不设置fillBefore,fillAfter,动画结束后会还是显示在动画前的位置
    Java代码中使用

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)
    
        var translateAnim = AnimationUtils.loadAnimation(this,R.anim.view_anim)
    
        tv_content.startAnimation(translateAnim)
    
        tv_content.setOnClickListener {
             Toast.makeText(this, "好的", Toast.LENGTH_SHORT).show()
        }
    }
    

    纯Java代码:

    var translateAnim = TranslateAnimation(0f,500f,0f,0f)
    
    translateAnim.duration = 3000
    
    tv_content.startAnimation(translateAnim)  
    

    2.缩放动画(Scale)

    ScaleAnimation类
    xml定义

    <?xml version="1.0" encoding="utf-8"?>
    <scale xmlns:android="http://schemas.android.com/apk/res/android"
        android:fromXScale="0.0"
        android:toXScale="1.4"
        android:fromYScale="0.0"
        android:toYScale="1.4"
        android:pivotX="50%"
        android:pivotY="50%"
        android:duration = "3000">
    
    </scale>
    

    注意:fromXScale和fromYScale都要写,pivotX只是改变开始缩放的始点,不加缩放的始点是view的左上角,
    android:pivotX="50"是控件view的x方向上加50像素
    android:pivotX="50%"是控件view的x方向上加view控件宽的50%
    android:pivotX="50%p"是控件view的x方向上加父布局控件宽的50%

    3.旋转动画(Rotate)

    RotateAnimation类

    <?xml version="1.0" encoding="utf-8"?>
    <rotate xmlns:android="http://schemas.android.com/apk/res/android"
        android:fromDegrees="0"
        android:toDegrees="180"
        android:duration = "2000"
        android:pivotX="50%"
        android:pivotY="50%"
    />
    

    android:fromDegrees="0" // 动画开始时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针)

    4.透明度动画(Alpha)

    AlphaAnimation类

    <?xml version="1.0" encoding="utf-8"?>
    <alpha xmlns:android="http://schemas.android.com/apk/res/android"
        android:fromAlpha="1.0"
        android:toAlpha="0.0"
        android:duration = "2000">
    
    </alpha>
    

    Activity的切换效果

    实现效果从右向左滑动
    in_from_right.xml

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration = "500"
        android:fromXDelta="100%p"
        android:toXDelta="0%p"
    />
    </set>  
    

    out_to_left.xml

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <translate
        android:duration="500"
        android:fromXDelta="0%p"
        android:toXDelta="-100%p"
     />
    </set>
    

    一般用在Activity的成对出现,但至少保持动画时间是一样的
    首先要了解Activity的位置
    x = 0%p是代表Activity刚好在屏幕中间
    x = 100%p是代表Activity在屏幕的右侧
    x = -100%p是代表Activity在屏幕的左侧

    Fragment的切换效果(几乎用不到)

     // 采用`FragmentTransavtion`的 setCustomAnimations()进行设置
    
    FragmentTransaction fragmentTransaction = mFragmentManager
    .beginTransaction();
    
    fragmentTransaction.setCustomAnimations(
    R.anim.in_from_right,
    R.anim.out_to_left);
    
    // 此处的自定义动画效果同Activity,此处不再过多描述
    

    组合动画

    采用< Set/>标签

    监听动画

    anim.addListener(new AnimatorListenerAdapter() {  
        // 向addListener()方法中传入适配器对象AnimatorListenerAdapter()
        // 由于AnimatorListenerAdapter中已经实现好每个接口
        // 所以这里不实现全部方法也不会报错
        @Override  
        public void onAnimationStart(Animator animation) {  
            // 如想只想监听动画开始时刻,就只需要单独重写该方法就可以
        }  
    });  
    

    二、逐帧动画(Frame Animation)

    作用对象:视图控件View
    原理:将动画拆分为帧的形式,且定义每一帧是一张图片,按顺序播放
    特点:优点:简单、方便
    缺点:容易引起OOM,因会用大量以及尺寸较大的图片资源
    应用场景: 较为复杂的个性化动画效果

    三、属性动画(Property Animation)

    作用对象:任意Java对象
    原理: 在一定时间间隔内,通过不断改变值以及赋值给对象的属性,从而实现该对象在该属性上的动画效果
    特点:优点:作用对象进行了拓展:不只是View对象,甚至无对象也可以,不只是4种基本变换,还有其他动画效果
    缺点:用起来稍微复杂点
    应用场景: 与属性相关、更加复杂的动画效果,比如通过改变View的颜色属性达到的动画效果

    逐帧动画和补间动画存在一定的缺点:

    1:作用对象局限于View
    即补间动画只能作用View上,没法对非View的对象进行操作。有些情况的动画效果只是视图的某个属性,比如通过视图的颜色动态变化,从而实现动画效果,而不是针对整个View视图进行动画操作
    2:没有改变View的属性,只是改变视觉效果
    如移动View,虽然看起来View的位置变了,但实际没变,还是原来的
    3:动画效果单一
    补间动画只能实现平移、旋转、缩放 & 透明度这些简单的动画需求,一旦遇到相对复杂的动画效果,即超出了上述4种动画效果,那么补间动画则无法实现

    ValueAnimator类

    原理:通过不断控制值的变化,再不断手动赋给对象的属性,从而实现动画效果
    Java代码:正常流程

    Log.i("tv_content",tv_content.width.toString()+"\t"+tv_content.layoutParams.width)
        //value动画
        val valueAnimator = ValueAnimator.ofInt(tv_content.layoutParams.width,500)
    
        valueAnimator.duration = 2000
    
        valueAnimator.addUpdateListener {
    
            val currentValue:Int = it.animatedValue as Int
            println(currentValue)
            //获取不断改变的值给view相应的属性
            tv_content.layoutParams.width = currentValue
            tv_content.requestLayout()
        }
        valueAnimator.start()  
    

    在xml中定义

    <animator xmlns:android="http://schemas.android.com/apk/res/android"
    android:valueFrom="0"
    android:valueTo="100"
    android:valueType="intType"
    android:duration="2000"
    />
    

    java用xml中定义的

    //用xml的value动画
        var valueAnimator = AnimatorInflater.loadAnimator(this,R.animator.value_anim)
        valueAnimator.setTarget(tv_content)
        valueAnimator.start()
    

    注:有点坑地方补间动画xml的文件夹名是anim,属性动画是animator。第二单纯这样setTarget(view)是没用的,它不知道改变什么属性。
    所以用属性动画还是用java代码定义写方便
    对象:ValueAnimator.ofObject()
    作用:将初始值以对象的形式过渡到结束值,即通过操作对象实现动画效果
    需我们自定义TypeEvaluator来告知系统如何进行从初始对象过渡到结束对象的逻辑
    示例PointEvaluator.java

        // 实现TypeEvaluator接口
    public class PointEvaluator implements TypeEvaluator {
    
        // 复写evaluate()
        // 在evaluate()里写入对象动画过渡的逻辑
        @Override
        public Object evaluate(float fraction, Object startValue, Object endValue) {
            
            // 将动画初始值startValue 和 动画结束值endValue 强制类型转换成Point对象
            Point startPoint = (Point) startValue;
            Point endPoint = (Point) endValue;
            
            // 根据fraction来计算当前动画的x和y的值
            float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());
            float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY());
            
            // 将计算后的坐标封装到一个新的Point对象中并返回
            Point point = new Point(x, y);
            return point;
        }
    
    }
    

    估值器(TypeEvaluator)

    作用:设置动画 如何从初始值 过渡到 结束值 的逻辑

    ObjectAnimator类

    是ValueAnimator的子类
    是通过反射找到相应的set函数
    原理:通过不断控制值的变化,再不断自动赋给对象的属性,从而实现动画效果
    示例代码:

    ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotationX",0,270,0);  
    animator.setDuration(2000);  
    animator.start();  
    

    怎么知道哪些属性是能赋值改变形成动画的呢
    1、要使用ObjectAnimator来构造对画,要操作的控件中,必须存在对应的属性的set方法
    2、setter 方法的命名必须以骆驼拼写法命名,即set后每个单词首字母大写,其余字母小写,即类似于setPropertyName所对应的属性为propertyName
    简单来说:先找View的set相应属性试试,有,就把属性开头大写改为小写即可
    自定义ObjectAnimator属性

    public class MyPointView extends View {
    
    private PointRadius mPoint = new PointRadius(100);
    
    public MyPointView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mPoint != null) {
            Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setColor(Color.RED);
            paint.setStyle(Paint.Style.FILL);
            canvas.drawCircle(300, 300, mPoint.getRadius(), paint);
        }
    }
    
    void setPointRadius(int radius) {
        mPoint.setRadius(radius);
        invalidate();
    }
    }
    

    关键setPointRadius方法
    使用:

    val objectAnimator = ObjectAnimator.ofInt(my_point_view,"pointRadius",0,300,200)
        objectAnimator.duration = 2000
        objectAnimator.start()
    

    参考:https://www.jianshu.com/p/2412d00a0ce4

    相关文章

      网友评论

        本文标题:面试准备(九)-- 补间动画、逐帧动画、属性动画

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