关键词:自定义View、属性动画、CheckBox、Switch、svg、Vector、矢量图
1、效果展示:
Switch
(🕹录制工具:scrcpy + GifCam.exe )
2、实现参考:
本文所有实现基于该参考文章,是一个实现的简化版本,强烈推荐阅读此文加深对xml动画的理解🤳:
Android 开发小记:自定义点击动画的 CheckBox 实现
maronyea.me/dev/304/
CheckBok
3、素材需求:
首先需要🎨UI提供svg的矢量图片,然后再用AndroidStudio导入为vector.xml,当然同时要理解vector中各个元素的含义才能为实现动画做好基础。作为👴ui boy,手搓👌android矢量图也是必备技能之一(bushi:
Android 矢量图详解
www.cnblogs.com/sydmobile/p...
准备好checkbox的最基本的选中/未选中两种状态的vector:
ON
checkbox_on.xml
xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="55.6dp"
android:height="30.8dp"
android:viewportWidth="83"
android:viewportHeight="46">
<path
android:name="fill_unchecked"
android:pathData="M23,3L63,3A20,20 0,0 1,83 23L83,23A20,20 0,0 1,63 43L23,43A20,20 0,0 1,3 23L3,23A20,20 0,0 1,23 3z"
android:fillColor="#6F555555"/>
<path
android:name="fill_checked"
android:pathData="M23,3L63,3A20,20 0,0 1,83 23L83,23A20,20 0,0 1,63 43L23,43A20,20 0,0 1,3 23L3,23A20,20 0,0 1,23 3z"
android:fillColor="#9C27B0"
android:fillAlpha="0"/>
<group
android:name="thumb_group"
android:translateX="0">
<path
android:name="thumb"
android:pathData="M23,23m-17,0a17,17 0,1 1,34 0a17,17 0,1 1,-34 0"
android:fillColor="#ffffff"
android:fillAlpha="0.8"/>
</group>
</vector>
OFF
checkbox_off.xml
xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="55.6dp"
android:height="30.8dp"
android:viewportWidth="83"
android:viewportHeight="46">
<path
android:name="fill_checked"
android:pathData="M23,3L63,3A20,20 0,0 1,83 23L83,23A20,20 0,0 1,63 43L23,43A20,20 0,0 1,3 23L3,23A20,20 0,0 1,23 3z"
android:fillColor="#9C27B0"
android:fillAlpha="1.0"/>
<group
android:name="thumb_group"
android:translateX="40">
<path
android:name="thumb"
android:pathData="M23,23m-17,0a17,17 0,1 1,34 0a17,17 0,1 1,-34 0"
android:fillColor="#ffffff"
android:fillAlpha="0.8"/>
</group>
</vector>
4、动画分解:
有了矢量图后就可以通过android:name
属性让图的一部分动起来,需要把动画拆解为两个步骤:
- 📐thumb 平移:操控上一步得到的vector的
thumb_group
在x轴方向上移动,对应属性translateX
- ✨背景颜色渐变:操控上一步得到的vector的
fill_checked
/fill_unchecked
,把这部分的的透明度进行变化,对应属性fillAlpha
4.1、最顶层drawable.xml文件:
checkbox_ainmated_drawable.xml
:
xml
<?xml version="1.0" encoding="utf-8"?>
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
<!--勾选-->
<item
android:id="@+id/checked"
android:state_checked="true"
android:drawable="@drawable/checkbox_on" />
<!--未勾选-->
<item
android:id="@+id/unchecked"
android:drawable="@drawable/checkbox_off" />
<!--未勾选过渡到已勾选-->
<transition
android:drawable="@drawable/transition_task_unchecked_checked"
android:fromId="@id/unchecked"
android:toId="@id/checked" />
<!--已勾选过渡到未勾选-->
<transition
android:drawable="@drawable/transition_task_checked_unchecked"
android:fromId="@id/checked"
android:toId="@id/unchecked" />
</animated-selector>
4.2、动画transition_task.xml实现:
4.2.1、task1:把thumb从左向右平移,并且颜色由未选择到选择的过渡:
transition_task_unchecked_checked.xml
xml
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/checkbox_off">
<target
android:animation="@anim/task_fill_checked_a_unchecked_checked"
android:name="fill_checked"/>
<target
android:animation="@anim/task_thumb_move_x_unchecked_checked"
android:name="thumb_group" />
</animated-vector>
task_thumb_move_x_unchecked_checked.xml
xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="@integer/animation_duration"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:propertyName="translateX"
android:valueFrom="0"
android:valueTo="40"
android:valueType="floatType" />
</set>
task_fill_checked_a_unchecked_checked.xml
xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="@integer/animation_duration"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:propertyName="fillAlpha"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType" />
</set>
4.2.2、task2:把thumb从右向左平移,并且颜色由选择到未选择的过渡:
transition_task_checked_unchecked.xml
xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="@integer/animation_duration"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:propertyName="translateX"
android:valueFrom="40"
android:valueTo="0"
android:valueType="floatType" />
</set>
task_fill_checked_a_checked_unchecked.xml
xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="@integer/animation_duration"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:propertyName="translateX"
android:valueFrom="0"
android:valueTo="40"
android:valueType="floatType" />
</set>
task_fill_checked_a_unchecked_checked.xml
xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="@integer/animation_duration"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:propertyName="fillAlpha"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType" />
</set>
4.3、res目录结构如下
erlang
res
├── anim
│ ├── task_fill_checked_a_checked_unchecked.xml
│ ├── task_fill_checked_a_unchecked_checked.xml
│ ├── task_thumb_move_x_checked_unchecked.xml
│ └── task_thumb_move_x_unchecked_checked.xml
├── drawable
│ ├── checkbox_ainmated_drawable.xml
│ ├── checkbox_off.xml
│ ├── checkbox_on.xml
│ ├── transition_task_checked_unchecked.xml
│ └── transition_task_unchecked_checked.xml
...
4.4、使用方式🎉
xml
<CheckBox
android:layout_width="55.6dp"
android:layout_height="30.8dp"
android:drawableStart="@drawable/checkbox_ainmated_drawable"
android:button="@null"
android:background="@android:color/transparent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<!--
android:button="@null" 去除原生thumb-
android:background="@android:color/transparent" 去除原生水波纹
-->
5、总结
更多技巧请参考原博客实现,如果你有牛叉的建议欢迎发表锐评✔