当前位置: 首页 > news >正文

安卓实例——统一动画

自定义控件动画

  • 适用场景:当父View和子View属于同一部分,不需要处理子View任何事件
  • 优点:控件可复用
  • 缺点:动画种类有限,较难实现复杂动画

在res目录新建attr.xml

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="ScaleLinearLayout"><attr name="pressScaleX" format="float" /><attr name="pressScaleY" format="float" /><attr name="pressAlpha" format="float" /><attr name="pressDuration" format="integer" /><attr name="releaseDuration" format="integer" /></declare-styleable>
</resources>

如下代码,控件点击后通过缩放动画实现点击效果

public class ScaleLinearLayout extends LinearLayout implements View.OnTouchListener {private static final String TAG = "ScaleLinearLayout";private static final float DEFAULT_ORIGINAL_SCALE_X = 1f;private static final float DEFAULT_ORIGINAL_SCALE_Y = 1f;private static final float DEFAULT_PRESSED_SCALE_X = 0.95f;private static final float DEFAULT_PRESSED_SCALE_Y = 0.95f;private static final float DEFAULT_ORIGINAL_ALPHA = 1f;private static final float DEFAULT_PRESSED_ALPHA = 0.4f;private static final int DEFAULT_PRESS_DURATION = 120;private static final int DEFAULT_RELEASE_DURATION = 120;private float mPressScaleX;private float mPressScaleY;private float mPressAlpha;private int mPressDuration;private int mReleaseDuration;private AnimatorSet currentAnimatorSet;public ScaleLinearLayout(Context context) {this(context, null);}public ScaleLinearLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}public ScaleLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initAttr(context, attrs);initListener();}private void initAttr(Context context, AttributeSet attrs) {try (TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ScaleLinearLayout)) {mPressScaleX = ta.getFloat(R.styleable.ScaleLinearLayout_pressScaleX, DEFAULT_PRESSED_SCALE_X);mPressScaleY = ta.getFloat(R.styleable.ScaleLinearLayout_pressScaleY, DEFAULT_PRESSED_SCALE_Y);mPressAlpha = ta.getFloat(R.styleable.ScaleLinearLayout_pressAlpha, DEFAULT_PRESSED_ALPHA);mPressDuration = ta.getInteger(R.styleable.ScaleLinearLayout_pressDuration, DEFAULT_PRESS_DURATION);mReleaseDuration = ta.getInteger(R.styleable.ScaleLinearLayout_releaseDuration, DEFAULT_RELEASE_DURATION);Log.d(TAG, "initAttr: mPressScaleX = " + mPressScaleX);Log.d(TAG, "initAttr: mPressScaleY = " + mPressScaleY);Log.d(TAG, "initAttr: mPressAlpha = " + mPressAlpha);Log.d(TAG, "initAttr: mPressDuration = " + mPressDuration);Log.d(TAG, "initAttr: mReleaseDuration = " + mReleaseDuration);ta.recycle();} catch (Exception e) {e.printStackTrace();}}private void initListener() {setOnTouchListener(this);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {return true;    // 父view拦截所有触摸/点击事件}private void press() {Log.d(TAG, "press: ");ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(this, "scaleX", DEFAULT_ORIGINAL_SCALE_X, mPressScaleX);ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(this, "scaleY", DEFAULT_ORIGINAL_SCALE_Y, mPressScaleY);ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(this, "alpha", DEFAULT_ORIGINAL_ALPHA, mPressAlpha);scaleXAnimator.setDuration(mPressDuration);scaleYAnimator.setDuration(mPressDuration);alphaAnimator.setDuration(mPressDuration);currentAnimatorSet = new AnimatorSet();currentAnimatorSet.playTogether(scaleXAnimator, scaleYAnimator, alphaAnimator);currentAnimatorSet.start();}private void release() {Log.d(TAG, "release: ");ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(this, "scaleX", mPressScaleX, DEFAULT_ORIGINAL_SCALE_X);ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(this, "scaleY", mPressScaleY, DEFAULT_ORIGINAL_SCALE_Y);ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(this, "alpha", mPressAlpha, DEFAULT_ORIGINAL_ALPHA);scaleXAnimator.setDuration(mReleaseDuration);scaleYAnimator.setDuration(mReleaseDuration);alphaAnimator.setDuration(mReleaseDuration);currentAnimatorSet = new AnimatorSet();currentAnimatorSet.playTogether(scaleXAnimator, scaleYAnimator, alphaAnimator);currentAnimatorSet.start();}private void stopCurrentAnimator() {if (currentAnimatorSet != null && currentAnimatorSet.isRunning()) {Log.d(TAG, "stopCurrentAnimator: ");currentAnimatorSet.cancel();currentAnimatorSet = null;}}@Overridepublic boolean onTouch(View v, MotionEvent event) {int action = event.getAction();Log.d(TAG, "ScaleLinearLayout: action = " + action);switch (action) {case ACTION_DOWN:stopCurrentAnimator();press();break;case ACTION_UP:case ACTION_CANCEL:stopCurrentAnimator();release();break;}return false;}
}

使用时可指定动画参数

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:custom="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><com.example.demo0.ScaleLinearLayoutandroid:id="@+id/btn_container"android:layout_width="150dp"android:layout_height="100dp"android:layout_centerInParent="true"android:background="#1A181818"android:gravity="center"custom:pressAlpha="0.5"custom:pressDuration="200"custom:releaseDuration="200"><ImageViewandroid:id="@+id/iv"android:layout_width="50dp"android:layout_height="50dp"android:layout_marginStart="10dp"android:src="@mipmap/ic_launcher" /><TextViewandroid:id="@+id/title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="30px"android:text="按钮"android:textSize="20sp" /></com.example.demo0.ScaleLinearLayout>
</RelativeLayout>

一次性动画

  • 适用场景:动画只运行一次
  • 优点:可以使用复杂动画,并同时对多个View使用
  • 缺点:无法控制动画暂停/开始

startAnimation()可以统一执行动画

public class AnimUtil {public static void startAnimation(List<Animator> objectAnimatorList,AnimatorListenerAdapter listenerAdapter) {AnimatorSet animatorSet = new AnimatorSet();List<Animator> animators = new ArrayList<>(objectAnimatorList);animatorSet.playTogether(animators);if (listenerAdapter != null) {animatorSet.addListener(listenerAdapter);}animatorSet.start();}
}
<?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="horizontal"android:gravity="center_horizontal"tools:context=".MainActivity"><ImageViewandroid:id="@+id/iv1"android:layout_width="50dp"android:layout_height="50dp"android:src="@mipmap/ic_launcher" /><ImageViewandroid:id="@+id/iv2"android:layout_width="50dp"android:layout_height="50dp"android:layout_marginStart="10dp"android:src="@drawable/ic_launcher_background" />
</LinearLayout>

对于上面两个ImageView,点击时消失,然后显示第一个

public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";private ImageView mIv1;private ImageView mIv2;private List<ImageView> mHideList;private List<ImageView> mShowList;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mIv1 = findViewById(R.id.iv1);mIv2 = findViewById(R.id.iv2);mHideList = List.of(mIv1, mIv2);mShowList = List.of(mIv1);mIv1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {hideView();}});}private void hideView() {AnimUtil.startAnimation(createHideAnimation(mHideList), new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {mHideList.forEach(v -> v.setVisibility(View.GONE));showView();}});}private void showView() {AnimUtil.startAnimation(createShowAnimation(mShowList), new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {super.onAnimationEnd(animation);mShowList.forEach(v -> v.setVisibility(View.VISIBLE));}});}private List<Animator> createHideAnimation(List<? extends View> views) {List<Animator> animators = new ArrayList<>();for (View view : views) {ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f);alphaAnim.setDuration(500);animators.add(alphaAnim);}return animators;}private List<Animator> createShowAnimation(List<? extends View> views) {List<Animator> animators = new ArrayList<>();for (View view : views) {ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f);alphaAnim.setDuration(500);animators.add(alphaAnim);}return animators;}
}

可控制动画

  • 适用场景:循环动画,需要控制动画
  • 优点:可以使用复杂动画,并同时对多个View使用
  • 缺点:若控制不当可能导致内存泄露

如下对多个View循环改变透明度

public class AlphaCycleAnimator {private static final String TAG = "AlphaCycleAnimator";private static final float FULL_ALPHA = 1.0f;private static final float PARTIAL_ALPHA = 0.6f;private static final long DURATION = 600;private AnimatorSet animatorSet;private List<View> targetViews;public AlphaCycleAnimator(List<View> views) {this.targetViews = views;this.animatorSet = new AnimatorSet();setupAnimation();}private void setupAnimation() {AnimatorSet forwardSet = createAlphaAnimator(FULL_ALPHA, PARTIAL_ALPHA);AnimatorSet reverseSet = createAlphaAnimator(PARTIAL_ALPHA, FULL_ALPHA);// 组合动画形成循环animatorSet.playSequentially(forwardSet, reverseSet);animatorSet.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(android.animation.Animator animation) {Log.d(TAG, "onAnimationEnd: ");animatorSet.start(); // 动画结束后重新开始}});}private AnimatorSet createAlphaAnimator(float fromAlpha, float toAlpha) {AnimatorSet set = new AnimatorSet();for (View view : targetViews) {ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha", fromAlpha, toAlpha);animator.setDuration(DURATION);set.playTogether(animator);}return set;}public void start() {Log.d(TAG, "start: ");if (animatorSet != null && !animatorSet.isRunning()) {animatorSet.start();}}public void stop() {Log.d(TAG, "stop: ");if (animatorSet != null && animatorSet.isRunning()) {animatorSet.removeAllListeners();   // 需要先停止监听再取消,否则无法停止动画animatorSet.cancel();for (View view : targetViews) { // 停止动画后需要恢复透明度view.setAlpha(FULL_ALPHA);}}}
}
<?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="horizontal"android:gravity="center_horizontal"tools:context=".MainActivity"><ImageViewandroid:id="@+id/iv1"android:layout_width="50dp"android:layout_height="50dp"android:src="@mipmap/ic_launcher" /><ImageViewandroid:id="@+id/iv2"android:layout_width="50dp"android:layout_height="50dp"android:layout_marginStart="10dp"android:src="@drawable/ic_launcher_background" />
</LinearLayout>

对于如上2个ImageView,点击第一个开始动画,第二个结束动画

public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";private ImageView mIv1;private ImageView mIv2;AlphaCycleAnimator mInterruptCycleAnimator;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mIv1 = findViewById(R.id.iv1);mIv2 = findViewById(R.id.iv2);mIv1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (mInterruptCycleAnimator == null) {mInterruptCycleAnimator = new AlphaCycleAnimator(Arrays.asList(mIv1, mIv2));}mInterruptCycleAnimator.start();}});mIv2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (mInterruptCycleAnimator != null) {mInterruptCycleAnimator.stop();mInterruptCycleAnimator = null;}}});}}
http://www.dtcms.com/a/512369.html

相关文章:

  • 数字化转型:概念性名词浅谈(第七十三讲)
  • 【推荐系统】快手OneSearch 提升3.2%订单量
  • jsp做的网页是网站吗三亚网红
  • 网页浏览器图标电商网站如何优化
  • 几种常用关系型数据库详细介绍
  • R-CNN详解
  • 网站维护要求哈尔滨网站建设效果
  • 多线程:线程类的方法做什么
  • 网站快速备案安全开发公司抽奖送房
  • Java一、二维数组
  • 企业网站模板观叫湖南岚鸿团队discuz好还是wordpress
  • 定制网站开发系统wordpress 繁简转换插件
  • 饲料网站建设 中企动力怎么做钓鱼网站生成器
  • vue 中 file-saver 功能介绍,使用场景,使用示例
  • 战略选择与系统性杠杆效应
  • @tanstack/react-query中isLoading,isFetchingisRefetching的区别
  • 深入解析C语言中的位域(Bit Fields):原理、规则与实践
  • 从前端到 Java 后端:一份详细转型路线指南
  • 专题学习网站模板虚拟主机网站源码
  • 持久化输出与 ChatMemory
  • 网站建设新手指南营销网站建设企业
  • 网站头页免费申请一个不花钱网站
  • BERT,GPT,ELMO模型对比
  • Memory Decoder: A Pretrained, Plug-and-PlayMemory for Large Language Models
  • 普通服务器都能跑:深入了解 Qwen3-Next-80B-A3B-Instruct
  • 【21】MFC入门到精通——MFC 调试及运行状态下,使用printf() 或者 cout 打印输出信息
  • 使用 rqt_reconfigure 实时控制 ROS 自定义话题参数
  • 公司电脑做网站网站优化平台有哪些
  • 软件公司网站模版网站首页 栏目页 内容页
  • 【论文精读-4】RBG:通过强化学习分层解决物流系统中的大规模路径问题(Zefang Zong,2022)