动画学习之WIFI图形绘制
Android原生动画概述:
对于APP开发中涉及到的一些动画基本上都可以用Android提供的各种原生动画类来实现,所以在学习自定义动画之前首先来对原生动画进行一个基本的了解,这里不详细对每一个原生动画进行深入学习,因为重点是学会如何自定义动画,其Android支持的原生动画主要有以下三类:
①、补间动画【View Animation】:
- 平移动画:TranslateAnimation
- 旋转动画:RotateAnimation
- 缩放动画:ScaleAnimation
- 渐变动画:AlphaAnimation
②、属性动画【Property Animation】:
这个动画在实际中用得比较多的是这两个类:ObjectAnimator和ValueAnimator,而ObjectAnimator是继承自ValueAnimator,如下:
其中ValueAnimator在之前的学习中也已经用过了,它可以对值进行变化。
对于上面两种动画其实是有一个比较大的区别的,下面来做一个小实验来直观的感受一下两者的区别:
新建一个工程,先准备布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.animationdemo.test.MainActivity"> <Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="traslate1"
android:text="点我平移补间动画" /> <Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="traslate2"
android:text="点我平移属性动画" />
</LinearLayout>
先看一下补间动画的效果:
public class MainActivity extends AppCompatActivity { private boolean isTranslate; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} //补间动画平移
public void traslate1(View view) {
if (!isTranslate) {
TranslateAnimation translateAnimation = new TranslateAnimation(TranslateAnimation.ABSOLUTE, 0, TranslateAnimation.ABSOLUTE, 100, TranslateAnimation.ABSOLUTE, 0, TranslateAnimation.ABSOLUTE, 0);
translateAnimation.setDuration(1000);
translateAnimation.setFillAfter(true);
view.startAnimation(translateAnimation);
isTranslate = true;
} else {
Toast.makeText(this, "点我了", Toast.LENGTH_SHORT).show();
}
} //属性动画平移
public void traslate2(View view) { }
}
主要是看一下事件的点击效果,编译运行:
从运行的结果来看,补间动画的平移并非真正的将View给移动了,也就是本尊未动,只是它的影子动了,接着再来看一下属性动画对于同样效果的实现,如下:
public class MainActivity extends AppCompatActivity { private boolean isTranslate;
private boolean isTranslate2; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} //补间动画平移
public void traslate1(View view) {
if (!isTranslate) {
TranslateAnimation translateAnimation = new TranslateAnimation(TranslateAnimation.ABSOLUTE, 0, TranslateAnimation.ABSOLUTE, 100, TranslateAnimation.ABSOLUTE, 0, TranslateAnimation.ABSOLUTE, 0);
translateAnimation.setDuration(1000);
translateAnimation.setFillAfter(true);
view.startAnimation(translateAnimation);
isTranslate = true;
} else {
Toast.makeText(this, "点我了", Toast.LENGTH_SHORT).show();
}
} //属性动画平移
@SuppressLint("ObjectAnimatorBinding")
public void traslate2(View view) {
if (!isTranslate2) {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, "translationX", 0, 100);
objectAnimator.setDuration(1000);
objectAnimator.start();
isTranslate2 = true;
} else {
Toast.makeText(this, "点我了2", Toast.LENGTH_SHORT).show();
}
}
}
编译运行:
很明显这次本尊和影子都一起动了,也就是真正的移动,这也就是两者之间的一个很明显的区别。
③、帧动画【Drawable Animation】:
这个就比较简单了,其实也就是动画是由系列的图片按一定的速度进行切换而实现滴,而在Android中叫AnimationDrawable。
自定义动画引入:
在上面已经介绍了Android提供的三种原生动画,这个在之后还会具体去应用到的,但是现实应用中可能会碰到原生动画满足不需求的情况,所以此时自定义动画就派上用场了,先来看一下如下系列动画效果:
它是来自于https://github.com/81813780/AVLoadingIndicatorView这个开源项目,接下来会挑几个效果进行学习,会搭配的Android的原生动画最终实现特定的效果,首先咱们要实现一个WIFI效果,如下:
而这个是通过单纯的canvas的绘制功能来实现动画效果而并未采用Android的原生动画,所以下面开始来一步步实现这个WIFI动画效果吧!
WIFI思路整理:
在正式编码实现之前,先来对效果进行一个思路整理, 先拿一个静态图来分析:
很明显该动画是由一个扇形和三个弧形组成,而且共用一个圆心,如下:
而且该圆心并非是自定义的中心点,另外需要控制绘制格数,当绘制满格信号的时候,又得回到一格信号,所以这里存在一上计数的逻辑控制,所以大概了解了之后接下来咱们就可以具体来动手将它一一实现啦。
WIFI图形绘制:
在加入动画之前先来在咱们自定义的View上绘制出一个WIFI的静态图形,所以先新建一个自定义View:
首先先画一个一格信号的扇形,而怎么绘制扇形在之前已经学习过了【http://www.cnblogs.com/webor2006/p/7341697.html】,可以用canvas.drawArc()进行,而扇形绘制需要一个外切矩形,外切矩形的大小决定了扇形的大小,如下:
而总共有四格信号,每格信号其实就都一个弧形,所以需要对应四个外切矩形,到底对应几个可以将其定义成一个常量,如下:
接着问题的焦点就回到了如何来确定每个RectF中的left、top、right、bottom的值了,那怎么确定呢?先来分析一下效果图:
再详细一点说:
所以说,咱们首先得要计算出这个总的半径长度,而这个长度应该是依赖于整个View的长宽,直径应该是取View宽高的较小值,所以:
有了直径之后,半径不就除以2嘛,这就是最大的半径,最后还得将其均分,所以:
所以每循环一次,则将这个基本半径进行成倍增加,如下:
这样就可以来确定外切距形的左、上、右、下的值啦,如下:
关于这四个参数为啥这样传,先不用过脑想,等绘出来之后再来理解,所以下面将这些矩形绘制出来看一下效果:
为了看到效果,在布局中定义这个View,如下:
编译运行:
呃~~乌黑一片~~什么鬼~~原因是得设置一下画笔的样式,如下:
编译运行:
嗯~~为了更进一步理解这个外切矩形,咱们拆解一个个来绘制,如下:
运行:
运行:
运行:
编译运行:
理解了这个外切矩形之后,下面再将这个rectF传给画布的drawArc方法中进行弧形的绘制,如下:
那为啥startAngle是-135,sweepAngle是90呢? 其中startAngle表示弧的起始角度,而我们想要绘制的起始角度应该是在坐标系中的如下位置:
而sweepAngle表示弧的弧度,那很明显咱们要绘制的弧度的结束位置应该在坐标系的如下位置:
所以这两个值为啥这样写的原因已经说明,接下来则开始运行看一下效果:
呃~未啥是长这个样子呢?其实是因为画笔样式的原因,下面修改如下:
编译运行:
嗯~~样子有了,但是弧条不够粗,所以改下画笔的粗度呗:
编译运行:
嗯~~够粗了,但是!!目前内容显示贴着顶边的,不太好看,此时应该将其往下移动一点,具体如下:
编译运行:
但是!!关于WIFI图形的绘制这块还差最后一个细节:第一格的应该是一个扇形,其它格数都是弧,而扇形与弧的决定是由这个参数来决定的:
所以此时需要加入条件判断来着情处理,如下:
编译运行:
WIFI动画实现:
有了静态图之后,接下来就是想办法将它动起来了,这里不采用任何Android提供的原生动画来弄,而是通过纯代码,所以需要解决两个问题:
1、不断的让界面重绘,那很简单,直接用invalidate();
2、得按一定的规律一格格的往上绘制,达到最大格数之后则需要又回到第一格,很显然需要用一个变量来控制当前绘制的格数,如下:
而每次绘制都是有一个for循环,所以需要通过一定的算法来控制咱们的绘制,具体如何做呢?下面直接给出:
另外每次绘制还得更改一下shouldExistSigalSize的大小,所以:
接下来得用一个定时器不断去让View重绘,有很多方法,这里直接用Handler来弄,可以这样做,如下:
此时编译运行:
嗯~~貌似不错~~但是还是存在一个小BUG的,第一次进来就绘制了两格,所以解决它很解决,只要改变初始化的格数既可,如下:
为何要将其改成4既可呢?因为:
所以,此时再编译运行就木问题了:
嗯~~不过差完美还有一步,资源的回收,此时如果将Activity退出,其刷新线程还在不断进行,如下:
所以接下来对资源进行回收,比较简单:
/**
* WIFI动画:采用自定义View的方式来实现,而非用Android提供的原生动画
*/
public class WiFi extends View { //constants
/* 总共有几格信号 */
private static final float SIGNAL_SIZE = 4F; //variables
private Paint paint;
/* 绘制的基准长度:取屏幕宽高的较少值 */
private int baseLength;
/* 当前信号存在的数量,默认从1格信号开始 */
private float shouldExistSinalSize = 4;
private Handler handler = new Handler();
private boolean isExit; public WiFi(Context context) {
this(context, null);
} public WiFi(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, -1);
} public WiFi(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
} private void init() {
paint = new Paint();
paint.setColor(Color.BLACK);
paint.setAntiAlias(true);
paint.setStrokeWidth(4);
//不断的进行绘制
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (isExit)
return;
Log.e("cexo", "handler run()...");
invalidate();
handler.postDelayed(this, 1000);
}
}, 1000);
} @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//绘制应该是在屏幕较小的长度来进行,所以先取出最小值,在绘制时需要参考该值
baseLength = Math.min(w, h);
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
shouldExistSinalSize++;
if (shouldExistSinalSize > 4) {
shouldExistSinalSize = 1;//如果已经绘制四格信号了,那么下一次则又回到一格信号状态
}
canvas.save();
canvas.translate(0, baseLength / SIGNAL_SIZE);//将画布往下移动一点,以防绘制太贴边
//根据信号的格数来进行相应的绘制
RectF rectF;
//计算出一个基准圆半径
float baseRadius = baseLength / 2 / SIGNAL_SIZE;//算出平均的半径
for (int i = 0; i < SIGNAL_SIZE; i++) {
if (i >= SIGNAL_SIZE - shouldExistSinalSize) {
float radius = baseRadius * i;
rectF = new RectF(radius, radius, baseLength - radius, baseLength - radius);
if (i < SIGNAL_SIZE - 1) {//此时需绘制一个弧形
paint.setStyle(Paint.Style.STROKE);//设置画笔样式为空心样式
canvas.drawArc(rectF, -135, 90, false, paint);
} else {//最下面则需要绘制一个扇形
paint.setStyle(Paint.Style.FILL);//设置画笔样式为实心样式
canvas.drawArc(rectF, -135, 90, true, paint);
}
}
}
canvas.restore();
} public void onDestroy() {
isExit = true;
}
}
public class MainActivity extends AppCompatActivity { private WiFi wifi; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); wifi = findViewById(R.id.wifi);
} @Override
protected void onDestroy() {
super.onDestroy();
wifi.onDestroy();
}
}
至此wifi信号的效果就完美实现,看似简单的效果其实现并非简单,可见也花的篇幅也不小。
动画学习之WIFI图形绘制的更多相关文章
- 动画学习之Music图形绘制
今天来实现一个类似于网易云音乐类似的动态效果,在用网易云音乐听歌时会有一个类似这样的效果,如下: 而咱们这次要实现的效果如下: music图形的绘制: 在实现动画之前先来将静态的图形绘制出来, 如下: ...
- [html] 学习笔记-Canvas图形绘制处理
使用Canvas API 可以将一个图形重叠绘制在另外一个图形上,也可以给图形添加阴影效果. 1.Canvas 图形组合 通过 globalCompositeOperation = 属性 来指定重叠效 ...
- cocos2d-x学习记录4——图形绘制
重写CCNode的draw函数能够绘制出各种基本图形,如点.直线.多边形.园.贝塞尔曲线等,同时还可以设置绘制的颜色和宽度. MyScene的draw函数 void MyScene::draw() { ...
- matlab学习笔记8 基本绘图命令-特殊图形绘制
一起来学matlab-matlab学习笔记8 基本绘图命令_3 特殊图形绘制 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考书籍 <matlab 程序设计与综合应用>张德丰等 ...
- Canvas学习:封装Canvas绘制基本图形API
Canvas学习:封装Canvas绘制基本图形API Canvas Canvas学习 从前面的文章中我们了解到,通过Canvas中的CanvasRenderingContext2D对象中的属性和方 ...
- HTML5图形绘制学习(1)-- Canvas 元素简介
Canvas元素是HTML5中新增的一个专门用来进行图形绘制的元素.和其名称Canvas一样,它就相当于一个画布,我们可以在其上描绘各种图形. 这里所说的绘制图型,不是指我们可以进行可视化的图形绘制, ...
- matlab学习笔记之五种常见的图形绘制功能
分类: 离散数据图形绘制 函数图形绘制 网格图形绘制 曲面图形绘制 特殊图形绘制 本文重点介绍matlab五种图形绘制方法的后三种. 一.网格图形绘制 以绘制函数z=f(x,y)三维网格图为例,下面为 ...
- iOS动画学习-视觉效果
CALayer不仅仅是iOS动画学习-CALayer中介绍的那些内容,他还有一些其他属性,比如shadowColor,borderWidth,borderColor等等,这些属性我们只需要简单点设置就 ...
- SVG 学习<一>基础图形及线段
目录 SVG 学习<一>基础图形及线段 SVG 学习<二>进阶 SVG世界,视野,视窗 stroke属性 svg分组 SVG 学习<三>渐变 SVG 学习<四 ...
随机推荐
- linux常用命令(18)find exec
find是我们很常用的一个Linux命令,但是我们一般查找出来的并不仅仅是看看而已,还会有进一步的操作,这个时候exec的作用就显现出来了.-exec 参数后面跟的是command命令,它的终止是以 ...
- 修改deploy location
在MyEclipse,如果某Web Project重命名后,项目名称有可能仍然是之前的名称. 修改路径: 第一, 路径:右击某Web Project,Properties->MyEclipse- ...
- React Native 安装
第一 :在天朝如果你可以违规上网的话便可以按 react native 中文网的文档进行安装与调试.地址为:https://reactnative.cn/docs/getting-started.ht ...
- jvm的学习笔记:二、类的初始化,代码实战(2)
常量在编译阶段,会存在调用这个常量的方法的所在的类的常量池当中 System.out.println(MyParent2.str); 输出: hello parent2 依据:在MyTest2类调用M ...
- webdriervAPI(窗口截图)
from selenium import webdriver driver = webdriver.Chorme() driver.get("http://www.baidu.co ...
- 论文阅读 | Trojaning Attack on Neural Networks
对神经网络的木马攻击 Q: 1. 模型蒸馏可以做防御吗? 2. 强化学习可以帮助生成木马触发器吗? 3. 怎么挑选建立强连接的units? 本文提出了一种针对神经元网络的木马攻击.模型不直观,不易被人 ...
- mysql5.6 多实例标准化安装
1.检查防火墙 是否关闭service iptables stopchkconfig iptables offservice iptables status 2. SELINUXvim /etc/se ...
- HDU1251 统计难题(字典树|map
Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀). Input输入数据的第一部分 ...
- 喝奶茶最大值(不能喝自己班级的)2019 Multi-University Training Contest 8--hdu杭电第8场(Roundgod and Milk Tea)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6667 题意: 有 n个班级,每个班级有a个人.b个奶茶,每个班的人不能喝自己的奶茶,只能喝别人班的奶茶 ...
- md5sum、tailf命令
一.md5sum:计算和校验文件的md5值 语法 md5sum [选项] ... [文件] ... 描述 打印或检查MD5(128位)校验和.没有FILE或FILE为 ...