自定义View学习笔记

自定义View(一)-动画- XML生成View动画

2018-01-02  本文已影响233人  g小志

前言

感觉好久没有写博客了。首先因为最近比较忙,有在学习即时通讯相关的开源项目,好不容易忙完了。有点时间就抓紧写博客。之前学习的开源项目百篮应用已经获得360+star了。当初学习的时候没有觉得什么。虽然不是我自己原创的项目。但是也是自己一点点写出来的,也学习到了很多。所以当初的2个承诺,一个是完善功能另一个写一个学习自定义View系列文章。个人觉得第二个比较重要。因为在理解后如何去完善,是仁者见仁智者见智的事情。
这里需要注意:本人只是一个Android的小白,所以对于自定义View这个部分相比之下还是比较难的,所以文本是自己学习的总结。所以部分内容会借鉴于很多优秀的文章,如果不妥。请私信联系我,我会第一时间处理。


动画介绍

在Android动画中,总共有两种类型的动画View Animation(视图动画)和Property Animator(属性动画)
区别:
1. 引入时间不同: View Animation是API Level 1就引入的。Property Animation是API Level 11引入的,即Android 3.0才开始有Property Animation相关的API。
2. 所在包名不同: View Animation在包android.view.animation中。而Property Animation API在包 android.animation中。
3. 动画类的命名不同: View Animation中动画类取名都叫XXXXAnimation,而在Property Animator中动画类的取名则叫XXXXAnimator

那么两者的使用场景和具体的区别呢?这里先留个疑问。等我们分析到属性动画的时候再去揭晓!

使用

首选,我们学习一些视图动画:

动画 释义
alpha 渐变透明度动画效果
scale 渐变尺寸伸缩动画效果
translate 画面转换位置移动动画效果
rotate 画面转移旋转动画效果

这是动画相关变换的形式,相信大家也并不陌生!他们的属性可以简单分成两类:一个是继承而来的;另一个自己独有的。
继承而来:
Animation类是所有动画(scale、alpha、translate、rotate)的基类。所这这四种动画都有一些共有的属性。如下
android:duration   动画持续时间,以毫秒为单位
android:fillAfter   如果设置为true,控件动画结束时,将保持动画最后时的状态
android:fillBefore   如果设置为true,控件动画结束时,还原到开始动画前的状态
android:fillEnabled 与android:fillBefore 效果相同,都是在动画结束时,将控件还原到初始化状态
android:repeatCount   重复次数
android:repeatMode   重复类型,有reverse和restart两个值,reverse表示倒序回放,restart表示重新放一遍,必须与repeatCount一起使用才能看到效果。因为这里的意义是重复的类型,即回放时的动作。
<font color=#006400>android:interpolator </font>   设定插值器,其实就是指定的动作效果,比如弹跳效果等。具体的插值器类型后面再详细介绍
各个动画独有属性:

alpha-透明度动画

android:fromAlpha 动画开始的透明度,从0.0 --1.0 ,0.0表示全透明,1.0表示完全不透明
android:toAlpha 动画结束时的透明度,也是从0.0 --1.0 ,0.0表示全透明,1.0表示完全不透明
在了解了共有属性和独有属性后我们具体用代码来实践一下,看下具体的效果:

alpha.gif
代码:
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
       android:repeatCount="2"
       android:repeatMode="reverse"
       android:duration="3000"
       android:fillAfter="true"
       android:fromAlpha="1.0"
       android:toAlpha="0.5">
</alpha>

这个动画我们首先来分析下:这个动画是从全透明(1.0)到半透明(0.5),动画时长3s,结束时保持动画最后的状态,倒叙回放。重复次数是两次(重复次数不算第一次)
代码:

btn_alpha.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mAnimation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.alpha_anim);
                mTextView.startAnimation(mAnimation);
            }
        });
alpha-尺寸变化

从名字上我们就可以看出这个动画主要是控制View的大小伸缩变换的。那么我们也是来看下它特有的属性:
android:fromXScale 起始的X方向上相对自身的缩放比例,浮点值,比如1.0代表自身无变化,0.5代表起始时缩小一倍,2.0代表放大一倍;
android:toXScale  结尾的X方向上相对自身的缩放比例,浮点值;
android:fromYScale 起始的Y方向上相对自身的缩放比例,浮点值。
android:toYScale 结尾的Y方向上相对自身的缩放比例,浮点值;
<font color=#006400>android:pivotX </font>  缩放起点X轴坐标,可以是数值、百分数、百分数p 三种样式,比如 50、50%、50%p,当为数值时,表示在当前View的左上角,即原点处加上50px,做为起始缩放点;如果是50%,表示在当前控件的左上角加上自己宽度的50%做为起始点;如果是50%p,那么就是表示在当前的左上角加上父控件宽度的50%做为起始点x轴坐标。
android:pivotY  缩放起点Y轴坐标,取值及意义跟android:pivotX一样。
这里面其他的属性还是比较好理解的主要是最后2个属性容易模糊。那么我们就针对后两个属性来着重看下:

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
       android:duration="3000"
       android:fillBefore="true"
       android:fromXScale="0.0"
       android:fromYScale="0.0"
       android:pivotX="50"
       android:pivotY="50"
       android:repeatCount="1"
       android:repeatMode="restart"
       android:toXScale="1.5"
       android:toYScale="1.5">
</scale>

这段代码的效果从属性上来看就是x,y轴都是从基于原图像0.0倍缩放到1.5倍然后回到初始状态(也就是1.0倍)然后起始点的坐标为(50,50),这里需要注意的是,在此处我们的原点坐标都是基于控件View的左上角而不是基于手机屏幕显示View左上角。
那么下面看下android:toXScale="0.5" android:toYScale="0.5" 的效果:

sacle.gif
android:toXScale="50%" android:toYScale="50%"
SCALE.gif
android:toXScale="50%p" android:toYScale="50%p"
sacl.gif
这里只改变了开始动画的坐标点参数,为了方便更好的理解我们从下面这幅图入手(这里只是方便理解点的位置不一定100%与实际一致。这里就不纠结这个问题了)
scale.gif
这里的A点是原点(0.0)当我们设置起始点为50,50时,这里可以理解为指的是具体的距离为50。那么起始点就为B点(50,50)
当我们设置起始点的坐标为50%,50%时,是指X,Y轴的距离是当前控件基于A点的50%,也就是D点控件的中心点。
最难理解的50%p,50%p,它的意思是距离是基于父布局(也就是应用显示的屏幕)计算他的距离然后算完后赋值给控件。那么屏幕的重点是C,那么它离X,Y轴的距离为X,Y,那么此时的开始点就是A(0,0)点加上X,Y就是F(X,Y)点,此时F点为动画起始点。 如果还不理解可以将动画时长改成30s或者更长,来观察下加深理解。
translate-位置变化

这个就太好理解了。就是将控件在原来的位置向指定方向或是指点移动。
<font color=#006400>android:fromXDelta </font> 起始点X轴坐标,可以是数值、百分数、百分数p 三种样式,比如 50、50%、50%p,具体意义与上面一样。
android:fromYDelta 起始点Y轴从标,可以是数值、百分数、百分数p 三种样式;
android:toXDelta 结束点X轴坐标
android:toYDelta 结束点Y轴坐标

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
           android:duration="100"
           android:fillEnabled="true"
           android:fromXDelta="0"
           android:fromYDelta="0"
           android:repeatCount="1"
           android:repeatMode="reverse"
           android:toXDelta="-100"
           android:toYDelta="-100">

</translate>

注意: 在Android中,我们计算坐标相关位置的时候都是:向左为负 向上为负。
这里都没有什么难点就不在说了。看下效果图:

translatel.gif
rotate-旋转变化

android:fromDegrees 开始旋转的角度位置,正值代表顺时针方向度数,负值代码逆时针方向度数
<font color=#006400>android:toDegrees</font> 结束时旋转到的角度位置,正值代表顺时针方向度数,负值代码逆时针方向度数
android:pivotX 缩放起点X轴坐标,可以是数值、百分数、百分数p 三种样式,比如 50、50%、50%p
android:pivotY 缩放起点Y轴坐标,可以是数值、百分数、百分数p 三种样式,比如 50、50%、50%p

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

效果如下:

rotate.gif
set-组合动画

这个前面没有提到,这也是一个动画属性,不过他没特殊独有属性,只有继承基类Animation的共有属性,他的特点就是可以将多个动画组合在一起。如下:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:duration="3000"
     android:fillAfter="true">

    <alpha
        android:fromAlpha="0.0"
        android:toAlpha="1.0"/>

    <scale
        android:fromXScale="0.0"
        android:toXScale="1.4"
        android:fromYScale="0.0"
        android:toYScale="1.4"
        android:pivotX="50%"
        android:pivotY="50%"/>

    <rotate
        android:fromDegrees="0"
        android:toDegrees="720"
        android:pivotX="50%"
        android:pivotY="50%"/>

</set>

效果如下:

set.gif
注意: 通常我们会把共有属性,比如:duration,repeatCount,repeatMode提取出来,如上面,当然你在每个属性中也可以单独使用,不过会很乱。而且不好控制。

Interpolator插值器

它是控制动画如何运动的一个属性。他是一个接口。那么我们来看下他的实现类有哪些


图片.png

AccelerateDecelerateInterpolator   在动画开始与介绍的地方速率改变比较慢,在中间的时候加速
AccelerateInterpolator       在动画开始的地方速率改变比较慢,然后开始加速
AnticipateInterpolator        开始的时候向后然后向前甩
AnticipateOvershootInterpolator  开始的时候向后然后向前甩一定值后返回最后的值
BounceInterpolatort        动画结束的时候弹起
CycleInterpolator        动画循环播放特定的次数,速率改变沿着正弦曲线
DecelerateInterpolator       在动画开始的地方快然后慢
LinearInterpolator          以常量速率改变
OvershootInterpolator        向前甩一定值后再回到原来位置
但是我看文档的时候发现还有一个插值器
PathInterpolator 围绕一个指定的路径做动画。
关于这个插值器先不讲解,因为他是在代码中使用,并且涉及到Path,所以我们这里先跳过。后期讲到的时候会再提一下。
这里我们简单在XML中设置BounceInterpolator(结束时弹起)插值器:

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

效果:

interpolator.gif
发现效果不是很明显(是由于FPS太低的原因,真机上比较明显) 其他效果我就不一一介绍了,大家可以自己尝试下。我这里就发一个我在学习时候完成的所有插值器的效果:
GIF.gif
这里都有名字大家可以自己对照(这里我换了一个录制软件,看起来好些),不过还是自己手动写一遍。能更好理解。

结语

本文的很多内容都是借鉴于Android自定义控件三部曲文章,这个系列文章就像一本书一样,让我在学习自定义View的时候给了我很大的帮助。所以在我写的时候会借鉴很多他的内容。不过还是想我开头说的。学习自定义View是一个漫长的路。我也是边学边总结。我觉得要学好自定义View应该这样:
动画-->画笔-->画布-->View的绘制流程-->事件分发-->自定义View-->自定义布局-->drawable...这只是一个学习的过程,还需要大量的学习好的自定义View,还需多练习。并且深入了解某一个控件的属性。所以以后的文章我会把我学习到的都总结在这里希望和我一样的小白早日进阶。
下篇就来总结下属性动画。
最后,希望和我一样在严酷的市场环境下坚持做Android的小白一起加油。

优秀博客以及文章:

Android自定义控件三部曲文章
Android开发艺术探索 这本书我现在还没看是开只是大致阅读了下 发现里面涉及到大量的自定义View知识后续会总结精华提取到文章中
程序员的自我反思 他里面有许多关于自定义View的文章
带你一步步深入了解View
Android 自定义控件之起步

上一篇下一篇

猜你喜欢

热点阅读