Android自定义动画专题一

article/2025/10/8 13:34:32

Android自定义动画

在目前的移动端产品中,不管是app还是网页一个好看酷炫的页面总是会第一时间吸引人的眼球,那么对于android开发人员来说,要想实现一个好看的页面必然需要掌握自定义控件以及自定义动画这门技术。

1.Android原生动画

Android下已经给我们提供了几种原生动画的表现形式:

①补间动画

平移:TranslateAnimation旋转:RotateAnimation缩放:ScaleAnimation渐变:AlphaAnimation

②属性动画

ObjectAnimatior: translation(x或y),rotation(x或y),scale(x或y)
ValueAnimator:ObjectAnimatior的父类,值动画

③帧动画

AniamteDrawable
  • 注意补间动画和属性动画的最大区别:
    • 补间动画只是改变了View的显示效果,并没有真正改变View的属性
    • 属性动画是真正改变了View的属性,比如平移效果。
    • 属性动画是Android 3.0引入的

2.Android自定义动画-表现形式一

那么什么是自定义动画呢?其实不明觉厉,那就是自己根据需求定义的动画效果。因为在实际开发中,大部分的复杂酷炫的动画效果用我们Android原生提供的动画都是满足不了的,那么就需要我们自己去定义。

那么本篇文章将通过三个案例的形式给大家演示通过自定义动画的第一种表现方式-自定义控件绘制的方式

那么接下来通过一些小demo案例来进行演示如何实现一些原生动画无法实现的自定义效果。

①WIFI效果

首先看下效果图:

1)思路

根据上面的效果图我们可以发现android原生动画是无法实现的,所以我们需要自定义控件动态去绘制这样的效果,那么思路可以分为以下两步:

  1. 先绘制WIFI在满信号的情况下的视图效果,也就是静态视图
  2. 通过handler的postDelayed方法可以死循环不断执行view的invalidate()方法来达到动态绘制的效果(每次绘制需要控制绘制几个信号)

2)具体实现

那么因为我们需要去绘制这个扇形和弧线,所以首先需要去创建一个自定义的view重写它的onDraw()方法,在绘制之前可以在view创建的时候先将画笔初始化出来。

具体的难点在于第二步如何动态去绘制,可以定义一个具体的数值比如 shouldExistSignalSize 来控制每次绘制的时候绘制哪个信号,从最开始的时候只绘制第一个信号(也就是扇形),接着第二次绘制的时候需要绘制第一个和第二个信号,往后就是第一个信号,第二个信号,第三个信号;当四格信号都绘制完毕的时候记得将 shouldExistSignalSize 重置。

代码如下:

/*** Created by PeiHuan on 2017/6/24.* <p>* WIFI控件*/
public class WIFIView extends View {public WIFIView(Context context) {this(context, null);}public WIFIView(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public WIFIView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private Paint paint;/*** 初始化准备*/private void init() {paint = new Paint();//画笔颜色paint.setColor(Color.BLACK);//画笔粗细paint.setStrokeWidth(6);//抗锯齿paint.setAntiAlias(true);handler.postDelayed(new Runnable() {@Overridepublic void run() {invalidate();handler.postDelayed(this,500);}},500);}private Handler handler = new Handler();/**WIFI控件宽高较小一边的长度*/private int wifiLength;@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);wifiLength = Math.min(w, h);}/*** 开始角度*/private float startAngle = -135;/*** 扇形或者弧的旋转角度*/private float sweepAngle = 90;/*** 信号大小,默认4格*/private int signalSize = 4;/**每次应该绘制的信号个数*/private float shouldExistSignalSize = 0f;@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);shouldExistSignalSize++;if(shouldExistSignalSize>4){shouldExistSignalSize=1;}canvas.save();//计算最小的扇形信号所在的圆的半径float signalRadius = wifiLength/2/signalSize;//向下平移画布,保证绘制的图形能够完全显示canvas.translate(0,signalRadius);for (int i = 0; i < signalSize; i++) {if(i>=signalSize-shouldExistSignalSize) {//定义每个信号所在圆的半径float radius = signalRadius * i;RectF rectf = new RectF(radius, radius, wifiLength - radius, wifiLength - radius);if (i < signalSize - 1) {paint.setStyle(Paint.Style.STROKE);canvas.drawArc(rectf, startAngle, sweepAngle, false, paint);} else {paint.setStyle(Paint.Style.FILL);canvas.drawArc(rectf, startAngle, sweepAngle, true, paint);}}}canvas.restore();}
}

详细代码请参考GitHub仓库:
https://github.com/zphuanlove/AnimationProject

②MUSIC效果

接下来再来看一个很常见的效果,同样也是通过自定义控件实现ondraw()去动态绘制;这也是很多目前能看到的一些音乐相关的app具有的效果,效果图如下:

1)思路

流程和思路和第一个demo类似,但产生动画的策略略有不同。

  1. 首先绘制静态效果图,剖析出整个图形由哪几部分组成:(两个圆,四段弧线)

  2. 通过不断绘制产生动画(不断更改四段弧线的起始角度)

WIFI demo我们使用的是handler的postDelayed方法造成一个死循环
这次我们可以通过在onDraw方法中调用invalidate来实现动画。

2)具体实现

具体实现同样也是在构造函数初始的时候去初始化画笔,然后在ondraw()方法中去绘制一个大圆一个小圆以及四段弧线,这里四段弧线可以分成两部分,及相对的两部分,每部分由一个大弧和一个小弧组成,两部分之间间隔180度。要绘制弧线就是要确认弧所在圆的外接矩形的左上右下,通过下图的计算可以很方便的计算出大弧所在的矩形的左上右下:

代码如下:

/*** Created by PeiHuan on 2017/6/24.* <p>* Music控件*/
public class MusicView extends View {private Paint paint;private int length;public MusicView(Context context) {this(context, null);}public MusicView(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public MusicView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}/*** 初始化操作*/private void init() {paint = new Paint();//画笔颜色paint.setColor(Color.BLACK);//画笔粗细paint.setStrokeWidth(2);//抗锯齿paint.setAntiAlias(true);//不填充paint.setStyle(Paint.Style.STROKE);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);length = Math.min(w, h);bigCircleRadius = length / 2;bigAngelRadius = length / 3;smallAngelRadius = length / 4;}/*** 大圆的半径*/private float bigCircleRadius;/*** 小圆的半径*/private float smallCircleRadius = 5f;/*** 两段大弧的半径*/private float bigAngelRadius;/*** 两段小弧的半径*/private float smallAngelRadius;private float startAngle1 = 0;private float startAngle2 = 180;private float sweepAngle = 60;@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//绘制两个圆canvas.drawCircle(bigCircleRadius, bigCircleRadius, bigCircleRadius - smallCircleRadius, paint);//小圆粗一些paint.setStrokeWidth(3);canvas.drawCircle(bigCircleRadius, bigCircleRadius, smallCircleRadius, paint);//绘制四段弧线//两段大弧,弧度相差180度RectF rectF = new RectF(bigCircleRadius-bigAngelRadius,bigCircleRadius-bigAngelRadius,bigCircleRadius+bigAngelRadius,bigCircleRadius+bigAngelRadius);canvas.drawArc(rectF,startAngle1,sweepAngle,false,paint);canvas.drawArc(rectF,startAngle2,sweepAngle,false,paint);//两段小弧,弧度相差180度RectF rectFSmaller = new RectF(bigCircleRadius-smallAngelRadius,bigCircleRadius-smallAngelRadius,bigCircleRadius+smallAngelRadius,bigCircleRadius+smallAngelRadius);canvas.drawArc(rectFSmaller,startAngle1,sweepAngle,false,paint);canvas.drawArc(rectFSmaller,startAngle2,sweepAngle,false,paint);startAngle1+=5;startAngle2+=5;if(!isDetached) {invalidate();}}/*** 自定义控件是否脱离窗体*/private boolean isDetached;/*** 当自定义控件脱离窗体,即将销毁*/@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();isDetached = true;}
}

详细代码请参考GitHub仓库:
https://github.com/zphuanlove/AnimationProject

③文字水波效果

最后一个效果就要酷炫一些了,不过代码实现起来也很简单,因为这里主要是要用到android中的一个关键技术:着色器实现。

我们先来看看效果:

1)思路

自定义TextView,在TextView的文本上添加遮盖物,并让着色器不断平移和下降,当下降完全显示文字后再移动着色器到文字顶部继续重复执行。

2)着色器Shader

简单铺垫下shader的作用,如果想要深入学习的同学可以下去自行查阅资料,这里不是本篇的重点了。

我们在用Android中的Canvas绘制各种图形时,可以通过Paint.setShader(shader)方法为画笔Paint设置shader,这样就可以绘制出多彩的图形。那么Shader是什么呢?Shader就是着色器的意思。我们可以这样理解,Canvas中的各种drawXXX方法定义了图形的形状,画笔中的Shader则定义了图形的着色、外观,二者结合到一起就决定了最终Canvas绘制的被色彩填充的图形的样子。

类android.graphics.Shader有五个子类:

  • LinearGradient 线性梯度渐变
  • RadialGradient 环形梯度渐变或者灯光渲染
  • SweepGradient 扫描梯度渐变
  • BitmapShader 图片渲染
  • ComposeShader 组合渲染

这里重点介绍下BitmapShader,因为该案例需要使用到它。

BitmapShader,顾名思义,就是用Bitmap对绘制的图形进行渲染着色,其实就是用图片对图形进行贴图。如果亲自装修过或者看过装修的同学应该知道新房在喷漆的时候会将一些不需要喷漆的地方用报纸进行包住来遮挡,那么BitmapShader也是通过的道理,比如我们想要对文字Loading进行喷色,着色,那么只需要将文字其余的地方遮住,只取图片上的颜色来对文字进行着色即可。

从字面上理论的角度理解后,再从它的构造函数上进行理解:

/*** Call this to create a new shader that will draw with a bitmap.** @param bitmap            The bitmap to use inside the shader* @param tileX             The tiling mode for x to draw the bitmap in.* @param tileY             The tiling mode for y to draw the bitmap in.*/
public BitmapShader(@NonNull Bitmap bitmap, TileMode tileX, TileMode tileY) 

第一个参数是Bitmap对象,该Bitmap决定了用什么图片对绘制的图形进行贴图,着色。

第二个参数和第三个参数都是Shader.TileMode类型的枚举值,有以下三个取值:CLAMP 、REPEAT 和 MIRROR。

  • CLAMP表示,当所画图形的尺寸大于Bitmap的尺寸的时候,会用Bitmap四边的颜色填充剩余空间。
  • REPEAT表示,当我们绘制的图形尺寸大于Bitmap尺寸时,会用Bitmap重复平铺整个绘制的区域。
  • MIRROR 与REPEAT类似,当绘制的图形尺寸大于Bitmap尺寸时,MIRROR也会用Bitmap重复平铺整个绘图区域,与REPEAT不同的是,两个相邻的Bitmap互为镜像。

3)代码实现

首先创建一个自定义view继承TextView,并且初始化字体,初始化着色器,代码如下:

/*** Created by PeiHuan on 2017/6/25.** 水面下降效果控件*/
public class WaterTextView extends android.support.v7.widget.AppCompatTextView {public WaterTextView(Context context) {this(context,null);}public WaterTextView(Context context, @Nullable AttributeSet attrs) {this(context, attrs,0);}public WaterTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {//让当前的TextView的字体为美术字体Typeface typeface = Typeface.createFromAsset(getResources().getAssets(), "Satisfy-Regular.ttf");setTypeface(typeface);//Matrix:矩阵,可以实现视图的平移旋转等效果matrix = new Matrix();//创建一个着色器createShader();}private void createShader() {Bitmap originalBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.wave);int waveWidth = originalBitmap.getWidth();waveHeight = originalBitmap.getHeight();Bitmap bitmap=Bitmap.createBitmap(waveWidth, waveHeight, originalBitmap.getConfig());//创建一个画布,为了将wave的图片颜色数据写入到Bitmap中Canvas canvas=new Canvas(bitmap);//设置画布的颜色从而控制文字的着色颜色canvas.drawColor(Color.RED);canvas.drawBitmap(originalBitmap,new Matrix(),getPaint());//CLAMP:使用原来的那张图片整体//REPEAT:将原来的图片复制无数份//MIRROR:镜像,将原来的图片镜像后,写入,再镜像...shader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);getPaint().setShader(shader);shaderX = 0;shaderY = -waveHeight/2;}}

接着让波浪动起来,通过ondraw()方法调用invalidate(),控制着色器的Y轴平移,代码如下:

@Override
protected void onDraw(Canvas canvas) {super.onDraw(canvas);repeatShader();
}private void repeatShader() {shaderX +=5;shaderY +=0.1;if(shaderY >-waveHeight/2+height){shaderY = -waveHeight/2;}matrix.setTranslate(shaderX, shaderY);shader.setLocalMatrix(matrix);invalidate();
}

详细代码请参考GitHub仓库:
https://github.com/zphuanlove/AnimationProject

总结

该篇文章通过三个案例效果给大家演示了如何实现android下的自定义动画效果,不过这仅仅只是android自定义动画的第一种表现形式,接下来还会在下篇文章中继续讲解第二种形式的展现。

文中的案例在github上均有详细以及扩展代码展示,三个案例汇总到一个项目中。

Thanks!


http://chatgpt.dhexx.cn/article/BrkWT33Z.shtml

相关文章

百度地图添加自定义图标标注以及自定义动画效果

百度地图添加自定义图标标注以及自定义动画效果 1、添加自定义图标标注2、添加自定义动画效果2.1、标注对象marker的构成2.2、自定义动画效果实现过程2.3、最终实现效果 上次写的是添加自定义图标&#xff0c;但是用的是添加自定义覆盖物方法&#xff0c;结果不支持点聚合&…

Vue中如何进行自定义动画与动画效果设计

Vue中如何进行自定义动画与动画效果设计 在Vue中&#xff0c;动画效果是非常有用的&#xff0c;它可以使用户界面变得更加生动、有趣&#xff0c;从而提高用户体验。Vue提供了一套非常方便的动画系统&#xff0c;使得我们可以非常容易地实现动画效果。 在本文中&#xff0c;我…

Android 自定义动画(实现类似分享动画)

最近在开发app中,要实现点击进入分享动画页面,然后照着每个Item的功能,来实现各自的功能 效果图如下: 首选自定义动画Activity import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import andr…

UE4 创建自定义动画节点

创建自定义动画节点需要两个类&#xff1a; 一个是您在编辑器中看到的图表节点 一个是真正在运行时工作的行为节点 动画图表节点&#xff0c;派生自&#xff1a;UAnimGraphNode_Base 例如&#xff1a;class UAnimGraphNode_SequencePlayer : public UAnimGraphNode_Base 动画…

ViewPager2添加自定义动画

此篇为ViewPager2的拓展篇&#xff0c;具体可查看ViewPager2的使用 ViewPager2自定义动画的核心是使用PageTransformer来实现&#xff0c;他是ViewPager2中的一个接口 原理 要显示非默认屏幕滑动动画&#xff0c;请实现 ViewPager2.PageTransformer 接口并将其提供给 ViewPa…

jQuery(五)--自定义动画、动画

目录 一、自定义动画 1.1 animate() 1.2 animate()动画执行顺序 1.3 animate()动画回调函数和匀速运动 1.4 animate动画之stop()/delay() 二、动画 2.1 show()/hide()/toggle() 2.2 slideDown()/slideUp()/slideToggle() 2.3 fadeIn()/fadeOut()/fadeTo()/fadeToggle(…

Android ProgressBar 自定义动画

源码地址&#xff1a; https://download.csdn.net/download/dreams_deng/12236355 1. 自定义圆形动画 1.1 布局 <!-- indeterminateDrawable 旋转图片indeterminateDuration 旋转速度--><ProgressBarandroid:id"id/pb_welcome_loading"android:layout_…

Qt自定义动画移动路径

在使用Qt实现动画时&#xff0c;一般使用QPropertyAnimation来实现&#xff0c;一般我们实现控件的移动动画都是走直线&#xff0c;我们如何实现自己想要的移动路径呢&#xff0c;比如走圆弧。下面介绍通过QPropertyAnimation实现自定义动画移动路径&#xff0c;比如走圆曲线、…

Flutter开发之——动画-自定义动画

一 为什么要进行自定义动画 当系统提供的动画不满足业务需求时&#xff0c;就需要我们自己进行自定义动画通过自定义动画&#xff0c;可以提高自定义组件的能力 二 自定义动画过程 继承StatefulWidget &#xff0c;完成动画界面的绘制setState 中动画执行及状态监听并刷新UId…

JQuery自定义动画——animate()学习

JQuery自定义动画——animate()学习 可以使 用animate 方法创建和实现自定义动画&#xff0c;animate() 方法通过执行 CSS 属性集的自定义动画&#xff0c;满足更多复杂多变的要求。 该方法通过CSS样式将元素从一个状态改变为另一个状态。即通过CSS属性值逐渐改变的&#xff0…

搞定动画之 JQuery 中的自定义动画

古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志——苏轼 写在前面 所谓的自定义动画就是通过 jQuery 提供的方法来完成我们自己想要的动画效果 animate()方法 jQuery 提供了 animate() 方法完成自定义动画效果&#xff0c;该方法具有两种用法。 用…

animate.css 自定义动画

在使用animate.css 的时候 动画的高度超过了预期的高度 在这种情况下肯定是过不了测试的&#xff0c;怎么办的&#xff1f; <div class"fold-div animated " :class"{slideInDown:foldDivHeightShow}" </div>上边代码可以知道 用的是 slideInDown…

JQuery中的animate自定义动画

animate()方法用于创建自定义动画。 概述 .animate( properties [, duration ] [, easing ] [, complete ] ) properties 类型: PlainObject 一个CSS属性和值的对象,动画将根据这组对象移动。 duration (默认: 400) 类型: Number or String 一个字符串或者数字决定动画将运…

jQuery自定义动画

首先创建一个新的html&#xff0c;在body下面输入源代码&#xff1b;div标签代表的是颜色的面板&#xff0c;button标签代表的是按钮当我们输入好了源代码之后呢&#xff0c;那我们的源代码部分已经完成了&#xff0c;接下来剩下的就只有css样式和jQuery函数了 接下来我们先完成…

自定义动画

自定义动画非常简单&#xff0c;只需要实现它的applyTransformation的逻辑就可以了&#xff0c;不过通常情况下&#xff0c;还需要覆盖父类的initialize方法来实现一些初始化工作。applyTransformation方法有如下两个参数。 applyTransformation(float interpolatedTime, Trans…

自定义控件三部曲之动画篇(四)——ValueAnimator基本使用

前言&#xff1a;不要让别人的无知断送了你的梦想&#xff0c;永远坚信你所坚信的。 相关文章&#xff1a; 《Android自定义控件三部曲文章索引》&#xff1a;http://blog.csdn.net/harvic880925/article/details/50995268 一、概述 long long ago&#xff0c;我写过几篇有关…

[HTML/CSS]动画效果以及自定义动画效果

一&#xff0c;实现div或者文字的当鼠标浮于其上时的动画效果&#xff1a; 1&#xff0c;transition加在div中&#xff0c;实现动画效果的过渡效果&#xff0c;transition: all 3s;其中all表示所有样式都参与过渡&#xff0c;3s表示实现效果的时间&#xff1b;linear为使动画匀…

css如何让文字强制换行

我们在编写html时&#xff0c; 有时候&#xff0c;常常需要在移动端用到一些table的属性&#xff0c;来呈现一些数据。如果说我们的数据内不含连续的数字或字母时&#xff0c;显示是不会出错的。 可是如果我们要呈现的数据为数字或长字母信息时&#xff0c;常常会出现这样的情…

CSS文本强制换行

发生背景&#xff1a; 在没有空格的&#xff08;字母、数字&#xff0c;符号&#xff09;&#xff0c;超过容器宽度时就会把容器撑大&#xff0c;不换行。所以在这里需要对其设置强制换行的样式&#xff1b; 解决方案&#xff1a; /* word-wrap: break-word; */ /…

css强制换行和禁止换行

强制换行 word-break: break-all; /* 只对英文起作用&#xff0c;以字母作为换行依据。 */ word-wrap: break-word; /* 只对英文起作用&#xff0c;以单词作为换行依据。 */ white-space: pre-wrap; /* 只对中文起作用&#xff0c;强制换行。 */ 禁止换行 white-space:…