android动画系统十分复杂,要写详细的包含所有知识点的教程可能会是一本厚厚的书。首先是支持的动画各类非常多,lottie,gif,opengl,补间,属性,逐帧等种技术,二是写法十分的灵活,加上各种特效,系统的学习和演练,没有几个月是不行的。
这是抛砖引玉,只介绍我使用中用到的某些方法。
一.简单的补间动画,
淡入淡出;
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="2000" />
绽放;
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="0.0"
android:toXScale="1.0"
android:fromYScale="0.0"
android:toYScale="1.0"
android:pivotX="50%"
android:pivotY="50%"
android:duration="2000" />
移动;
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromYDelta="100%"
android:toYDelta="0"
android:duration="2000" />
使用十分简单:
Animation moveUp = AnimationUtils.loadAnimation(this, R.anim.move_up);
view.startAnimation(moveUp);
当然也可以代码实现:
透明度:
Animation fadeIn = new AlphaAnimation(0.0f, 1.0f); // 透明度从0到1变化
fadeIn.setDuration(2000); // 持续时间2秒
view.startAnimation(fadeIn);
缩放;
Animation scaleUp = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); // 在中心点缩放
scaleUp.setDuration(2000); // 持续时间2秒
view.startAnimation(scaleUp);
移动:
Animation moveUp = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF, 0.0f); // 从底部移动到顶部
moveUp.setDuration(2000); // 持续时间2秒
view.startAnimation(moveUp);
使用xml定义和代码是等效的,当希望一个图形既移动,又绽放,就需要用到set,里面的属性android:ordering="sequentially"可以依次播放,together可以同时播放,
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:ordering="sequentially"
tools:ignore="MissingDefaultResource">
<translate
android:duration="500"
android:fromXDelta="0"
android:toXDelta="100dp"
android:interpolator="@android:anim/linear_interpolator" />
<translate
android:duration="500"
android:fromXDelta="100dp"
android:toXDelta="0" />
<scale
android:duration="500"
android:fromYScale="1.0"
android:toYScale="0.2"
android:pivotY="50%"
android:interpolator="@android:anim/overshoot_interpolator" />
<scale
android:duration="500"
android:fromYScale="0.2"
android:toYScale="1.0"
android:pivotY="50%" />
</set>
代码实现:
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(translation, scaleX, scaleY, rotation);
animatorSet.setDuration(1000); // 设置总持续时间
animatorSet.start(); // 开始动画
也可以使用另一种顺次播放,with属性和play 设置的动画一起播放,比如可以把放缩和位移一起播放,after在play之后播放,before在play之前播放,这样可以设置三个动画组按顺序依次播放,像电影里的多幕局一样。这种设置很方便我们设置,C先播放,播放完成后A和B一起一播放,A,B播放完成后播放C,形成一起种循环,当然循环也是专门的属性控制。
playSequentially或
play(animator).with(anotherAnimator).after(scaleY).before();
二。属性动画
属性动画是android后期加入,逐渐取代补间动画的位置,理论上属性动画可以实现补间的所有功能。属性动画把一个视图变大和位移后,点击面积和位置就变了,如果你不需要这个,你依然可以使用补间动画。两种动画功能差不多,但使用的资源类型不动,他们在项目的不同文件夹里,一个是anim,一个是animator,话错就无法播放
一个简简单单的属性动画,这是一个使用了set的组合动画,当然也可以分开并不使用set:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 插值器的使用:android:interpolator="@android:anim/bounce_interpolator" -->
<!-- X轴方向平移 -->
<objectAnimator
android:interpolator="@android:anim/bounce_interpolator"
android:duration="2000"
android:propertyName="translationX"
android:valueFrom="-500"
android:valueTo="0"
android:valueType="floatType" />
<!-- Y轴方向平移 -->
<objectAnimator
android:duration="2000"
android:propertyName="translationY"
android:valueFrom="-500"
android:valueTo="0"
android:valueType="floatType" />
<!-- X轴横向拉伸 -->
<objectAnimator
android:duration="2000"
android:propertyName="scaleX"
android:valueFrom="1"
android:valueTo="2"
android:valueType="floatType" />
<!-- Y轴纵向拉伸 -->
<objectAnimator
android:duration="2000"
android:propertyName="scaleY"
android:valueFrom="1"
android:valueTo="2"
android:valueType="floatType" />
<!-- 透明度 -->
<objectAnimator
android:duration="1500"
android:propertyName="alpha"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType" />
<!-- 旋转 -->
<objectAnimator
android:duration="3000"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="360"
android:valueType="floatType" />
</set>
使用:
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file);
animator.setTarget(view);
animator.start();
完全的代码实现,两者是等效的,这往往取决于团队的习惯,xml文件的动画资源可以使用一些工具实现,特别适合某些不懂编程但懂设计的人才,他们使用和设计好,再让开发导入,可以保持动画和最终的效果一致。编程里的一些复杂设计,往往是为了方便一些非专业程序员加入。
-
// 创建平移动画 -
ObjectAnimator translateAnim = ObjectAnimator.ofFloat(animatedButton, "translationX", 0f, 300f); -
translateAnim.setDuration(800); -
// 创建缩放动画 -
ObjectAnimator scaleAnim = ObjectAnimator.ofFloat(animatedButton, "scaleX", 1f, 1.5f); -
scaleAnim.setDuration(800); -
// 创建AnimatorSet -
AnimatorSet animatorSet = new AnimatorSet(); -
animatorSet.playTogether(translateAnim, scaleAnim); // 同时执行 -
// 设置动画重复 -
animatorSet.setRepeatCount(1); // 重复一次,总共执行两次 -
animatorSet.setRepeatMode(ObjectAnimator.REVERSE); // 在完成后反向执行 -
// 启动动画 -
animatorSet.start();
animator有很多灵活的属性用来控制动画,
android:duration 动画播放时长
android:propertyName 动画属性
android:valueFrom 动画初始值
android:valueTo 动画结束值
android:startOffset 动画激活延时
android:repeatCount 动画重复次数
android:repeatMode 动画重复模式,repeat和reverse分别对应正序和倒序
android:valueType 取值参数类型
android:interpolator 设置插值器
android:propertyName,android:repeatCount,android:repeatMode,android:interpolator我认为是最重要的,android:interpolator有很多可选参数,一般需要熟练掌握,起码知道,方便要资源
AccelerateDecelerateInterpolator 其变化开始和结束速率较慢,中间加速
AccelerateInterpolator 其变化开始速率较慢,后面加速
DecelerateInterpolator 其变化开始速率较快,后面减速
LinearInterpolator 其变化速率恒定
AnticipateInterpolator 沿着开始相反的方向先运行
OvershootInterpolator 结束后顺着结束的运行规律让然运行一段时间
AnticipateOvershootInterpolator AnticipateInterpolator 和 OvershootInterpolator 的结合
BounceInterpolator 自由落体规律运动
CycleInterpolator 其速率为正弦曲线
LinearOutSlowInInterpolator 其变化先匀速再减速
FastOutSlowInInterpolator 其变化是先加速,然后减速
FastOutLinearInInterpolator 其变化先加速然后匀速,本质还是加速运动
android:propertyName也有参数;
| translationX | X轴方向平移 |
| translationY | Y轴方向平移 |
| scaleX | X轴横向拉伸 |
| scaleY | Y轴纵向拉伸 |
| alpha | 透明度 |
| rotation | 旋转 |
android:repeatCount可以使用整型数值或者ObjectAnimator.INFINITE无限循环,android:repeatMode可以保证你不必额外写动画复位代码。
注;
1.属性动画有一类特殊的动画,ValueAnimator,他能实现类似set的效果,需要根据需要自己修改view的属性,比如有节奏的修改背景色,形状,同时修改位移,大小,角度,透明度等值,实现完全的放飞。在onAnimationUpdate修改view的所有的属性,他只控制动画的进度,其他的全看自己需要,这非常重要,当你需要开发基础动画之外的动画时,比如图形圆变方,颜色黑变白等等,他能提供一种根据interpolator参数变化的平滑实现。
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
anim.setDuration(300);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentValue = (float) animation.getAnimatedValue();
Log.d("TAG", "cuurent value is " + currentValue);
}
});
anim.start();
2,另一个常用的大概是,这个可以实现与ValueAnimator类似的功能,但更简单,如下,实现了按时间修改背景,其他能做的还更多,他可以修改view的几乎所有的属性,比如textview打字机效果。
public static ObjectAnimator ofPropertyValuesHolder(Object target,PropertyValuesHolder... values)
如下:
PropertyValuesHolder rotationHolder = PropertyValuesHolder.ofFloat("Rotation", 60f, -60f, 40f, -40f, -20f, 20f, 10f, -10f, 0f);
PropertyValuesHolder colorHolder = PropertyValuesHolder.ofInt("BackgroundColor", 0xffffffff, 0xffff00ff, 0xffffff00, 0xffffffff);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(mTextView, rotationHolder, colorHolder);
animator.setDuration(3000);
animator.setInterpolator(new AccelerateInterpolator());
animator.start();
三。RenderScript、ScriptIntrinsicBlur、RenderEffect 可以高速的给view和图片添加高斯模糊和其他特殊效果,因为RenderScript 是 Android 提供的异构计算框架,能在 CPU/GPU/专用 DSP 上高效运行,所有比一般情况下自己写的效率要高。这是一个实现高斯模糊的例子。
public static Bitmap blurBitmapRS(Context context, Bitmap src, float radius) {
// 1. 创建输出 Bitmap,参数与源 Bitmap 相同
Bitmap outBitmap = src.copy(src.getConfig(), true);
// 2. 创建 RenderScript 对象
RenderScript rs = RenderScript.create(context);
// 3. 创建 ScriptIntrinsicBlur
ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
// 4. 创建输入、输出 Allocation
Allocation allIn = Allocation.createFromBitmap(rs, src);
Allocation allOut = Allocation.createFromBitmap(rs, outBitmap);
// 5. 设置模糊半径
blurScript.setRadius(radius);
// 6. 设置输入
blurScript.setInput(allIn);
// 7. 执行脚本
blurScript.forEach(allOut);
// 8. 拷贝到输出 Bitmap
allOut.copyTo(outBitmap);
// 9. 释放资源
allIn.destroy();
allOut.destroy();
blurScript.destroy();
rs.destroy();
return outBitmap;
}
由于view可以转为bitmap,使得我们可以对整个view实现高速的高斯模糊效果
// 获取原图 Bitmap
Bitmap src = ((BitmapDrawable)ivOriginal.getDrawable()).getBitmap();
Bitmap blurred;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
// 半径范围 0 < radius ≤ 25
blurred = BlurUtils.blurBitmapRS(this, src, 20f);
} else {
// 兼容老系统,fallback
blurred = BlurUtils.blurBitmapFast(src, 20);
}
ivBlurred.setImageBitmap(blurred);
四。RuntimeShader,可以在图像特效中使用shader脚本,一个高级的动画或者图像编程中常用,相机需要适时处理的场合,可以高速的水波,火焰,等粒子效果
//dazzling.agsl
uniform shader u_texture;
uniform vec2 u_resolution;
vec4 main(vec2 coords) {
vec4 tex = u_texture.eval(coords);
vec2 normUV = coords / u_resolution;
vec3 color = tex.rgb * vec3(normUV.x, normUV.y, 0.5);
return vec4(color, 1.0);
}
private void applyRuntimeShader(View view, float[] resolution) {
String shaderCode = StringUtils.loadString(this, "shaders/dazzling.agsl");
RuntimeShader shader = new RuntimeShader(shaderCode);
shader.setFloatUniform("u_resolution", resolution);
RenderEffect effect = RenderEffect.createRuntimeShaderEffect(shader, "u_texture");
view.setRenderEffect(effect);
}
五;drawBitmapMesh是个很重要的函数,可以实现水波荡漾,红旗招展,翻页,吸入等效果,
public void drawBitmapMesh (Bitmap bitmap,
int meshWidth,int meshHeight,
float[] verts,int vertOffset,
int[] colors,int colorOffset,Paint paint)
六。shader有很多种效果
BitmapShader:Android BitmapShader类详解 ,位图平铺。
LinearGradient:Android LinearGradient类详解 ,线性渐变。
RadialGradient:Android RadialGradient类详解 ,圆形渐变。
SweepGradient:Android SweepGradient类详解 ,角度渐变。
ComposeGradient:Android ComposeShader类详解 ,组合效果。
使用:
try {
InputStream isImage = getAssets().open("test6.png");
bitmap = BitmapFactory.decodeStream(isImage);
} catch (IOException e) {
e.printStackTrace();
}
//创建5种shader的派生类对象,分别测试效果
shaders[0] = new BitmapShader(bitmap,Shader.TileMode.REPEAT, Shader.TileMode.MIRROR);
shaders[1] = new LinearGradient(0f,0f,100f,100f,colors,null, Shader.TileMode.REPEAT);
shaders[2] = new RadialGradient(100f,100f,80f,colors,null, Shader.TileMode.REPEAT);
shaders[3] = new SweepGradient(160f,160f,colors,null);
shaders[4] = new ComposeShader(shaders[1],shaders[2], PorterDuff.Mode.ADD);
case R.id.btn1:myView.setShader(shaders[0]);break;
case R.id.btn2:myView.setShader(shaders[1]);break;
case R.id.btn3:myView.setShader(shaders[2]);break;
case R.id.btn4:myView.setShader(shaders[3]);break;
case R.id.btn5:myView.setShader(shaders[4]);break;
BitmapShader可以实现mask效果,
Bitmap originalBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.original_image);
Bitmap maskBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.mask_image);
BitmapShader shader = new BitmapShader(maskBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
Paint paint = new Paint();
paint.setShader(shader);
Canvas canvas = new Canvas(originalBitmap);
canvas.drawPaint(paint);
imageView.setImageBitmap(originalBitmap);
注:
view,drawable,bitmap是可以相互转化
七。setXfermode也可以实现mask
Bitmap originalBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.original_image);
Bitmap maskBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.mask_image);
Paint paint = new Paint();
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
Canvas canvas = new Canvas(originalBitmap);
canvas.drawBitmap(maskBitmap, 0, 0, null);
canvas.drawBitmap(originalBitmap, 0, 0, paint);
八。matrix
使用matrix也可以实现类似补间或者属性动画的效果,
参考:
Android--xml实现组合动画_android xml动画-优快云博客
Android属性动画完全解析(上),初识属性动画的基本用法-腾讯云开发者社区-腾讯云
Android自定义控件:动画类(九)----PropertyValuesHolder与Keyframe - vegatate - 博客园
Android实现Bitmap高斯模糊效果(附带源码)_android 高斯模糊-优快云博客
【Android】RuntimeShader 应用-优快云博客
使用Android Jetpack Compose渲染效果打造酷炫的动画效果_android agsl-优快云博客
https://www.jb51.net/article/38753.htm
Android APP完整基础教程(16)图形系统-图像特效_drawbitmapmesh-优快云博客
android mask切图_mob649e8164659f的技术博客_51CTO博客
Android动画与视觉特效技巧
1704

被折叠的 条评论
为什么被折叠?



