热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android动画实现开关按钮动画(属性动画之平移动画)实例代码

这篇文章主要介绍了Android动画实现开关按钮动画(属性动画之平移动画)实例代码的相关资料,需要的朋友可以参考下

Android动画 实现开关按钮动画(属性动画之平移动画),最近做项目,根据项目需求,有一个这样的功能,实现类似开关的动画效果,经过自己琢磨及上网查找资料,终于解决了,这里就记录下:

  在Android里面,一些炫酷的动画确实是很吸引人的地方,让然看了就赏心悦目,一个好看的动画可能会提高用户对软件的使用率。另外说到动画,在Android里面支持3种动画: 逐帧动画(Frame Animation)、补间动画(Tween Animation)和属性动画(Property Animation),至于这几种动画的区别这里不再介绍,希望开发者都能在使用的过程中体会两者的不同。

  本文使用属性动画完成,说到属性动画,肯定要提到 JakeWharton大神写的NineOldAndroids动画库,如果你的app需要在android3.0以下使用属性动画,那么这个库就很有作用了,如果只需要在高版本使用,那么直接使用系统提供的动画API即可。

首先看一下本文要实现的动画效果:手指向上移动到开关按钮处, 然后一个点击动作,开关从关到开动画执行,同时手指向下移动回到原来的位置

点击图片调转到对应链接查看动画

 动画的使用场景

  引导用户去打开某个功能的开关按钮或者去打开系统的某项设置的时候,增加动画可以提高用户的点击率,表达的意思也更明确

 实现之前先做好如下准备工作

  1. 下载nineoldandroids-2.4.0.jar的库,放到android studio 工程目录的libs文件夹中

  2. 在build.gradle文件中引入

dependencies { compile files('libs/nineoldandroids-2.4.0.jar')}

  3. 准备好相关的图片资源

      

 接下来封装一个自定义控件来实现整个动画

第一步:先定义一个布局文件finger_switch_on_guide_layout.xml

<&#63;xml version="1.0" encoding="utf-8"&#63;>


 

 

布局文件预缆长这样:

 第二步:定义自定义控件(SwitchOnAnimView)实现整个动画

package com.androidanimation.animationview;

import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.FrameLayout;
import android.widget.ImageView;

import com.androidanimation.R;
import com.androidanimation.animations.BaseAnimatorListener;
import com.androidanimation.utils.ViewUtil;
import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.ObjectAnimator;
import com.nineoldandroids.view.ViewHelper;

/**
 * Created by popfisher on 2016/9/3.
 */

public class SwitchOnAnimView extends FrameLayout {

 private Handler mHandler = new Handler();
 /** 开关中间的圆圈View */
 private ImageView mCirclePtImgv;
 /** 手指View */
 private ImageView mFingerImgv;
 /** 手指移动的距离 */
 private float mFingerMoveDistance;
 /** 开关中间的圆圈View需要移动的距离 */
 private float mCirclePtMoveDistance;
 private static final int FINGER_ANIM_DURATION = 300;
 private static final int CIRCLE_PT_ANIM_DURATION = 500;

 private boolean isStopAnim = false;

 public SwitchOnAnimView(Context context) {
  this(context, null);
 }

 public SwitchOnAnimView(Context context, AttributeSet attrs) {
  super(context, attrs);
  // 加载布局
  LayoutInflater.from(context).inflate(R.layout.finger_switch_on_guide_layout, this, true);
  initView();
 }

 private void initView() {
  mCirclePtImgv = (ImageView) findViewById(R.id.switch_anim_circle_point);
  mFingerImgv = (ImageView) findViewById(R.id.finger_switch);

  // 下面两个距离要根据UI布局来确定
  mFingerMoveDistance = ViewUtil.dp2px(getContext(), 20f);
  mCirclePtMoveDistance = ViewUtil.dp2px(getContext(), 17.5f);
 }

 /**
  * 启动动画
  */
 public void startAnim() {
  isStopAnim = false;
  // 启动动画之前先恢复初始状态
  ViewHelper.setTranslationX(mCirclePtImgv, 0);
  mCirclePtImgv.setBackgroundResource(R.drawable.switch_off_circle_point);
  mFingerImgv.setBackgroundResource(R.drawable.finger_normal);
  startFingerUpAnim();
 }

 /**
  * 停止动画
  */
 public void stopAnim() {
  isStopAnim = true;
 }

 /**
  * 中间的圈点View平移动画
  */
 private void startCirclePointAnim() {
  if (mCirclePtImgv == null) {
   return;
  }
  ObjectAnimator circlePtAnim = ObjectAnimator.ofFloat(mCirclePtImgv, "translationX", 0, mCirclePtMoveDistance);
  circlePtAnim.setDuration(CIRCLE_PT_ANIM_DURATION);
  circlePtAnim.start();
 }

 /**
  * 手指向上移动动画
  */
 private void startFingerUpAnim() {
  ObjectAnimator fingerUpAnim = ObjectAnimator.ofFloat(mFingerImgv, "translationY", 0, -mFingerMoveDistance);
  fingerUpAnim.setDuration(FINGER_ANIM_DURATION);
  fingerUpAnim.addListener(new BaseAnimatorListener() {
   @Override
   public void onAnimationEnd(Animator animator) {
    if (mFingerImgv == null || mHandler == null) {
     return;
    }
    // 手指向上动画执行完成就设置手指View背景为点击状态的背景
    mFingerImgv.setBackgroundResource(R.drawable.finger_click);
    // 点击之后为了提现停顿一下的感觉,延迟200毫秒执行其他动画
    mHandler.postDelayed(new Runnable() {
     @Override
     public void run() {
      if (mCirclePtImgv == null || mHandler == null) {
       return;
      }
      // 将中间圆圈View背景设置为开关打开状态然后开始向右平移
      mCirclePtImgv.setBackgroundResource(R.drawable.switch_on_circle_point);
      startCirclePointAnim();
      // 延迟100毫秒启动手指向下平移动画
      mHandler.postDelayed(new Runnable() {
       @Override
       public void run() {
        // 手指向下移动开始时设置手指背景为正常的状态
        if (mFingerImgv != null) {
         mFingerImgv.setBackgroundResource(R.drawable.finger_normal);
        }
        startFingerDownAnim();
       }
      }, 100);
     }
    }, 200);
   }
  });
  fingerUpAnim.start();
 }

 /**
  * 手指向下移动动画
  */
 private void startFingerDownAnim() {
  if (mFingerImgv == null) {
   return;
  }
  ObjectAnimator fingerDownAnim = ObjectAnimator.ofFloat(mFingerImgv, "translationY", -mFingerMoveDistance, 0);
  fingerDownAnim.setDuration(FINGER_ANIM_DURATION);
  fingerDownAnim.addListener(new BaseAnimatorListener() {
   @Override
   public void onAnimationEnd(Animator animator) {
    // 手指向下移动动画完成,整个动画流程结束,重新开始下一次流程,循环执行动画,间隔1秒
    mHandler.postDelayed(new Runnable() {
     @Override
     public void run() {
      if (isStopAnim) {
       return;
      }
      startAnim();
     }
    }, 1000);
   }
  });
  fingerDownAnim.start();
 }
}

最后一步:就是找个载体把SwitchOnAnimView加进去,调用其startAnim方法执行动画,这里在一个Activity中把播放此动画

定义activity布局文件activity_finger_switchon_anim.xml

<&#63;xml version="1.0" encoding="utf-8"&#63;>

 

定义并实现Activity:FingerSwitchOnAnimActivity

package com.androidanimation;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;

import com.androidanimation.animationview.SwitchOnAnimView;

public class FingerSwitchOnAnimActivity extends Activity {

 private Handler mHandler = new Handler();
 private SwitchOnAnimView mSwitchOnAnimView;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_finger_switchon_anim);
  mSwitchOnAnimView= (SwitchOnAnimView) findViewById(R.id.switch_on_anim_view);
    
      mHandler.postDelayed(new Runnable() {
   @Override
   public void run() {
    mSwitchOnAnimView.startAnim();
   }
  }, 500);
} }

动画实现总结:

  掌握Android的动画并不难,难的时候怎么实现一些复杂的动画,这里总结一下实现复杂动画的几个步骤。

  1. 动画分解:任何复杂的动画都可以分解为很多个原子动画的组合

  2. 动画衔接时机分析:复杂动画分解为很多个原子动画之后,要重新衔接起来

            这里其实就是各个原子动画的执行时机,谁先谁后还是同时执行

  3. 实现原子动画:将拆解的原子动画依次实现

  4. 动画组装:上面都准备好之后,将原子动画按照一定的规律组装串联起来,整个复杂的动画就开始工作了

  原子动画:本文指不能再继续拆分的动画

  拿本文中的动画来说,动画可以分为四个:

  a. 手指向上平移动画

  b. 手指点击操作(这里不是动画,也可以当做一个简单的动画吧)

  c. 开关按钮原点向右平移动画

  d. 手指向下平移动画。

  本文动画执行时机为:

  a 先执行,a 执行完成之后立即执行 b,b 执行完成之后等待200ms执行 c(体现点击效果)

  c 执行开始100ms后开始执行 d

  动画的分解和动画衔接时机分析是不太容易的事,因为凭借肉眼有时候没法观察出来,所以播放动画的时候要放慢来看,如果还是不能看出来,最好还是要找公司的UI同事协助分析。因为我们能简单的区分平移动画,缩放动画这种简单,但是我们不能区分那种正弦算法动画或者是另外一些其他算法控制的动画。本文中的动画相对还是比较简单,实现起来也比较容易,但是思想确实一样的。

 源码下载地址:https://github.com/PopFisher/AndroidAnimationDemos

        感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!


推荐阅读
  • 基于KVM的SRIOV直通配置及性能测试
    SRIOV介绍、VF直通配置,以及包转发率性能测试小慢哥的原创文章,欢迎转载目录?1.SRIOV介绍?2.环境说明?3.开启SRIOV?4.生成VF?5.VF ... [详细]
  • 本文详细介绍了Git分布式版本控制系统中远程仓库的概念和操作方法。通过具体案例,帮助读者更好地理解和掌握如何高效管理代码库。 ... [详细]
  • FinOps 与 Serverless 的结合:破解云成本难题
    本文探讨了如何通过 FinOps 实践优化 Serverless 应用的成本管理,提出了首个 Serverless 函数总成本估计模型,并分享了多种有效的成本优化策略。 ... [详细]
  • Composer Registry Manager:PHP的源切换管理工具
    本文介绍了一个用于Composer的源切换管理工具——Composer Registry Manager。该项目旨在简化Composer包源的管理和切换,避免与常见的CRM系统混淆,并提供了详细的安装和使用指南。 ... [详细]
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 作者:守望者1028链接:https:www.nowcoder.comdiscuss55353来源:牛客网面试高频题:校招过程中参考过牛客诸位大佬的面经,但是具体哪一块是参考谁的我 ... [详细]
  • Linux 学习路径与核心框架
    本文提供了一套系统化的 Linux 学习路径,旨在帮助初学者和中级用户构建全面的知识体系。通过逐步深入的学习方法,掌握从基础命令到高级系统管理的技能。 ... [详细]
  • 本文详细介绍了 Flink 和 YARN 的交互机制。YARN 是 Hadoop 生态系统中的资源管理组件,类似于 Spark on YARN 的配置方式。我们将基于官方文档,深入探讨如何在 YARN 上部署和运行 Flink 任务。 ... [详细]
  • 本文介绍了一个用于 Android 开发的 Logcat 日志管理工具类,该类提供了默认和自定义标签的日志记录方法。通过这种方式,开发者可以更方便地管理和调试应用程序中的日志输出。 ... [详细]
  • 本文详细介绍超文本标记语言(HTML)的基本概念与语法结构。HTML是构建网页的核心语言,通过标记标签描述页面内容,帮助开发者创建结构化、语义化的Web页面。 ... [详细]
  • 本文详细介绍如何利用已搭建的LAMP(Linux、Apache、MySQL、PHP)环境,快速创建一个基于WordPress的内容管理系统(CMS)。WordPress是一款流行的开源博客平台,适用于个人或小型团队使用。 ... [详细]
  • 本题探讨了在一个有向图中,如何根据特定规则将城市划分为若干个区域,使得每个区域内的城市之间能够相互到达,并且划分的区域数量最少。题目提供了时间限制和内存限制,要求在给定的城市和道路信息下,计算出最少需要划分的区域数量。 ... [详细]
  • 本文探讨了如何使用自增和自减运算符遍历二维数组中的元素。通过实例详细解释了指针与二维数组结合使用的正确方法,并解答了常见的错误用法。 ... [详细]
  • 给定行数 numRows,生成帕斯卡三角形的前 numRows 行。例如,当 numRows 为 5 时,返回的结果应为:[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]。 ... [详细]
  • 本文介绍如何将自定义项目设置为Tomcat的默认访问项目,使得通过IP地址访问时直接展示该自定义项目。提供了三种配置方法:修改项目路径、调整配置文件以及使用WAR包部署。 ... [详细]
author-avatar
Becky30712701
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有