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

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
 android:id="@+id/switch_anim_root"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content">

 <FrameLayout
  android:layout_width="wrap_content"
  android:layout_height="wrap_content">

  <ImageView
   android:layout_width="42dp"
   android:layout_height="25dp"
   android:background="@drawable/switch_container" />

  <ImageView
   android:id="@+id/switch_anim_circle_point"
   android:layout_width="20dp"
   android:layout_height="20dp"
   android:layout_marginLeft="2.5dp"
   android:layout_marginTop="2.5dp"
   android:background="@drawable/switch_off_circle_point" />
 </FrameLayout>

 <ImageView
  android:id="@+id/finger_switch"
  android:layout_width="34dp"
  android:layout_height="41dp"
  android:layout_marginLeft="5dp"
  android:layout_marginTop="25dp"
  android:background="@drawable/finger_normal" />
</merge>

布局文件预缆长这样:

第二步:定义自定义控件(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

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:id="@+id/activity_animation_main"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:gravity="center"
 android:orientation="vertical">
 <com.androidanimation.animationview.SwitchOnAnimView
  android:id="@+id/switch_on_anim_view"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"/>

</LinearLayout>

定义并实现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

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

(0)

相关推荐

  • Android实现循环平移动画示例

    实现用一张背景图做循环从左往右平移动画. 1.实现两个animation xml文件,一个起始位置在-100%p ,一个在0%p.设置repeat属性为循环,重复. 复制代码 代码如下: <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolato

  • Android 动画之TranslateAnimation应用详解

    android中提供了4中动画: AlphaAnimation 透明度动画效果 ScaleAnimation 缩放动画效果 TranslateAnimation 位移动画效果 RotateAnimation 旋转动画效果 本节讲解TranslateAnimation动画,TranslateAnimation比较常用,比如QQ,网易新闻菜单条的动画,就可以用TranslateAnimation实现, 通过TranslateAnimation(float fromXDelta, float toXD

  • Android 动画之RotateAnimation应用详解

    android中提供了4中动画: AlphaAnimation 透明度动画效果 ScaleAnimation 缩放动画效果 TranslateAnimation 位移动画效果 RotateAnimation 旋转动画效果 本节讲解RotateAnimation 动画, RotateAnimation (float fromDegrees, float toDegrees, int pivotXType, float pivotXValue, int pivotYType, float pivot

  • Android实现阅读APP平移翻页效果

    自己做的一个APP需要用到翻页阅读,网上看过立体翻页效果,不过bug太多了还不兼容.看了一下多看阅读翻页是采用平移翻页的,于是就仿写了一个平移翻页的控件.效果如下: 在翻页时页面右边缘绘制了阴影,效果还不错.要实现这种平移翻页控件并不难,只需要定义一个布局管理页面就可以了.具体实现上有以下难点: 1.循环翻页,页面的重复利用. 2.在翻页时过滤掉多点触碰. 3.采用setAdapter的方式设置页面布局和数据. 下面就来一一解决这几个难点.首先看循环翻页问题,怎么样能采用较少的页面实现这种翻页呢

  • Android 动画之ScaleAnimation应用详解

    android中提供了4中动画: AlphaAnimation 透明度动画效果 ScaleAnimation 缩放动画效果 TranslateAnimation 位移动画效果 RotateAnimation 旋转动画效果 本节讲解ScaleAnimation 动画, ScaleAnimation(float fromX, float toX, float fromY, float toY,int pivotXType, float pivotXValue, int pivotYType, flo

  • Android Animation之TranslateAnimation(平移动画)

    TranslateAnimation(平移动画)的意思无非就是一张图片或其他从一个位置到达另外一个位置.直接代码分析,相关重要属性参数解释都在代码中. 1.首先编写main.xml文件. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_w

  • Android Animation实战之屏幕底部弹出PopupWindow

    Android动画的一个实战内容,从屏幕底部滑动弹出PopupWindow. 相信这种效果大家在很多APP上都遇到过,比如需要拍照或者从SD卡选择图片,再比如需要分享某些东西时,大多会采用这么一种效果: 那这种效果如何实现呢? 我们仿写一个这种效果的实例吧: 1)我们首先定义一下,弹出窗口的页面布局组件:take_photo_pop.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout

  • Android多点触控实现对图片放大缩小平移,惯性滑动等功能

    文章将在原有基础之上做了一些扩展功能: 1.图片的惯性滑动 2.图片缩放小于正常比例时,松手会自动回弹成正常比例 3.图片缩放大于最大比例时,松手会自动回弹成最大比例 实现图片的缩放,平移,双击缩放等基本功能的代码如下,每一行代码我都做了详细的注释 public class ZoomImageView extends ImageView implements ScaleGestureDetector.OnScaleGestureListener, View.OnTouchListener , V

  • Android 动画之AlphaAnimation应用详解

    android中提供了4中动画: AlphaAnimation 透明度动画效果 ScaleAnimation 缩放动画效果 TranslateAnimation 位移动画效果 RotateAnimation 旋转动画效果 本节讲解AlphaAnimation 动画,窗口的动画效果,淡入淡出什么的,有些游戏的欢迎动画,logo的淡入淡出效果就使用AlphaAnimation. 直接看代码: 复制代码 代码如下: public class MainActivity extends Activity

  • Android 自定义球型水波纹带圆弧进度效果(实例代码)

    需求 如下,实现一个圆形水波纹,带进度,两层水波纹需要渐变显示,且外围有一个圆弧进度. 思路 外围圆弧进度:可以通过canvas.drawArc()实现.由于圆弧需要实现渐变,可以通过给画笔设置shader(SweepGradient)渲染,为了保证圆弧起始的颜色值始终一致,需要动态调整shader的参数.具体参见 SweepGradient(centerX.toFloat(), centerY.toFloat(), circleColors[0], floatArrayOf(0f, value

  • Android自定义dialog 自下往上弹出的实例代码

    具体代码如下所示: package com.example.idmin.myapplication.wiget; import android.app.Dialog; import android.content.Context; import android.os.Bundle; import android.view.Gravity; import android.view.View; import android.view.WindowManager; import android.wid

  • Android实现状态栏和虚拟按键背景颜色的变化实例代码详解

    今天介绍一下,我在项目开发过程中,实现状态栏和虚拟按键背景颜色变化的方法,实现方式是,通过隐藏系统的状态栏和虚拟按键的背景,实现图片和背景显示到状态栏和虚拟按键下方.下面来看实现代码: 实现状态栏背景的设置 状态栏工具类 public class StatusBarUtil { /** * 设置沉浸式状态栏 * * @param activity 需要设置的activity */ public static void setTransparent(Activity activity) { //A

  • Android开发中通过手机号+短信验证码登录的实例代码

    首先,需要一个电话号码,目前很多账户都是将账户名设置成手机号,然后点击按钮获取手机验证码. 其次,你需要后台给你手机短信的验证接口,各个公司用的不一样,这个身为前端,不需要你来考虑,你只要让你后台给你写好接口,你直接调用就好了. activity_login.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.andr

  • Android实现listview滑动时渐隐渐现顶部栏实例代码

    我在开发的时候遇到了这样的需求,就是在listview的滑动中,需要对顶部的栏目由透明慢慢的变为不透明的状态,就是以下的效果 最先开始的时候想的很简单,无非就是监听listview的滑动距离,然后根据距离算出透明度的比值,就可以了,但是事实上呢也的确是这样做的 只是在获取listview的滑动距离上可能没法直接获取,需要动态的去计算 下面贴出全部代码吧,不想码字了,最近感冒了,脑袋晕乎乎的,还疼,代码更直观一些 private void initListener() { lvList.setOn

  • Android长按imageview把图片保存到本地的实例代码

    工具类 之前用 AsyncTask 现在改用rxJava public class SaveImageUtils { public static void imageSave(final ImageView imageView, final int id) { Observable .create(new Observable.OnSubscribe<ImageView>() { @Override public void call(Subscriber<? super ImageVie

  • Android仿微博个人详情页滚动到顶部的实例代码

    个人详情页滑动到顶部 最近产品提了个新需求,需要实现点击App内的某个按钮跳转到个人详情页并且滑动到顶部,个人详情页的页面交互稍微复杂,技术角度上包含了状态栏颜色变换,view滑动联动等问题,技术实现上采用了Google出的CoordinatorLayout那套组件,由于App的个人详情页跟微博的相似,这里就拿微博为例来描述.微博默认的效果以及手动滑动到顶部的效果图如下. 个人详情页技术实现分析: 先看看xml布局的伪代码: <?xml version="1.0" encodin

  • Android自定义控件之可拖动控制的圆环控制条实例代码

    前几天收到这么一个需求,本来以为挺简单的,没想到最后发现实现起来还是有点小麻烦的,在这里小小的总结一下. 先看看下面这张需求的样图: 然后在看一下最终实现的效果图,可能是gif录制软件的问题,有一些浮影,忽略就好了: 首先要分析一下最核心的地方,如何获取到滑动距离对应的弧长,看图: p1是手指按下的点,很明显要想知道当前进度弧边的值,就是要求出角d的值. 以p为圆心点,atan(b)=Math.atan((-p.y)/(-p.x)); 所以角d的值为:Math.toDegrees(atan);

  • Android自定义控件开发实战之实现ListView下拉刷新实例代码

    这篇博客为大家介绍一个android常见的功能--ListView下拉刷新: 首先下拉未松手时候手机显示这样的界面: 下面的代码是自定的扎样的控件: <span style="font-family: comic sans ms,sans-serif; font-size: 16px;">package com.dhsr.smartID.view; import android.content.Context; import android.util.AttributeSe

  • Android实现多点触控,自由缩放图片的实例代码

    Android多点触控涉及到的知识点 1.ScaleGestureDetector 2.OnScaleGestureListener 3.Matrix 4.OnTouchListener 四个知识点需要了解一下,需要注意的是Matrix在内存中是一个一维数组,操控图片的Matrxi是一个3X3的矩阵,在内存中也就是一个大小为9的一维数组. 实现多点触控,自由变化图片 1. ImageView的基础上继承 2.因为要在图片加载完成就获取到相关的属性,所以实现OnGlobalLayoutListen

随机推荐