Android实现炫酷播放效果

 更新时间:2018年08月17日 09:57:29   作者:wanxiaofan  
这篇文章主要为大家详细介绍了Android实现炫酷播放效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了Android实现播放效果的具体代码,供大家参考,具体内容如下

一、首先看效果

二、实现原理

使用贝塞尔曲线实现滑动效果,在使用属性动画实现水波纹效果,然后就能实现以上效果

三、实现

1、先封装动画框架,创建动画基础类

PathPoint.java

public class PathPoint {
 
  public static final int MOVE = 0;
  public static final int LINE = 1;
  public static final int CURVE = 2;
  float mControl0X, mControl0Y;
  float mControl1X, mControl1Y;
  public float mX, mY;
  int mOperation;
 
  //line/move
  private PathPoint(int operation, float x, float y) {
    this.mOperation = operation;
    this.mX = x;
    this.mY = y;
  }
 
  //curve
  private PathPoint(float c0X, float c0Y, float c1X, float c1Y, float x, float y) {
    this.mControl0X = c0X;
    this.mControl0Y = c0Y;
    this.mControl1X = c1X;
    this.mControl1Y = c1Y;
    this.mX = x;
    this.mY = y;
    this.mOperation = CURVE;
 
  }
 
  public static PathPoint moveTo(float x, float y) {
 
    return new PathPoint(MOVE, x, y);
 
  }
 
  public static PathPoint lineTo(float x, float y) {
 
    return new PathPoint(LINE, x, y);
 
  }
 
  public static PathPoint curveTo(float c0X, float c0Y, float c1X, float c1Y, float x, float y) {
 
    return new PathPoint(c0X, c0Y, c1X, c1Y, x, y);
 
  }
}

2、创建动画集合类,并且保存绘制轨迹

AnimatorPath

public class AnimatorPath {
  //记录轨迹
  private List<PathPoint> mPoints = new ArrayList<>();
 
  public void moveTo(float x, float y) {
    mPoints.add(PathPoint.moveTo(x, y));
  }
 
  public void lineTo(float x, float y) {
    mPoints.add(PathPoint.lineTo(x, y));
  }
 
  public void curveTo(float c0X, float c0Y, float c1X, float c1Y, float x, float y) {
    mPoints.add(PathPoint.curveTo(c0X, c0Y, c1X, c1Y, x, y));
  }
 
 
  public Collection<PathPoint> getPoints() {
    return mPoints;
  }
}

3、实现页面布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="#ffe8e8e8">
 
 
  <ImageView
    android:id="@+id/album_cover"
    android:layout_width="match_parent"
    android:layout_height="250dp"
    android:background="#22eeff" />
 
  <android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="120dp"
    android:layout_below="@id/album_cover"
    android:layout_marginTop="-15dp"
    android:background="@color/colorPrimary"
    android:elevation="4dp"
    android:minHeight="?attr/actionBarSize"
    android:paddingLeft="72dp">
 
    <LinearLayout
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:gravity="center_vertical"
      android:orientation="vertical">
 
      <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:fontFamily="sans-serif"
        android:text="大海大海"
        android:textColor="#FFF"
        android:textSize="30sp" />
      <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:fontFamily="sans-serif-light"
        android:text="王小二"
        android:textColor="#9cffffff"
        android:textSize="18sp" />
    </LinearLayout>
  </android.support.v7.widget.Toolbar>
 
  <FrameLayout
    android:id="@+id/fab_container"
    android:layout_width="match_parent"
    android:layout_height="128dp"
    android:layout_below="@id/album_cover"
    android:layout_marginTop="-30dp"
    android:elevation="10dp">
 
    <LinearLayout
      android:id="@+id/media_controls_container"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_gravity="center"
      android:orientation="horizontal">
 
      <ImageView
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:scaleX="0"
        android:scaleY="0"
        android:src="@mipmap/play" />
 
      <ImageView
        android:id="@+id/iv_pause_play"
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_marginLeft="50dp"
        android:layout_marginRight="50dp"
        android:scaleX="0"
        android:scaleY="0"
        android:src="@mipmap/play" />
 
      <ImageView
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_marginRight="50dp"
        android:scaleX="0"
        android:scaleY="0"
        android:src="@mipmap/play" />
 
    </LinearLayout>
 
    <ImageButton
      android:id="@+id/fab"
      android:layout_width="56dp"
      android:layout_height="56dp"
      android:layout_gravity="top|right"
      android:layout_marginRight="72dp"
      android:background="@drawable/ripple"
      android:elevation="5dp"
      android:onClick="onPabPressed"
      android:transitionName="button_fab" />
  </FrameLayout>
 
</RelativeLayout>

4、获取控件,并且设置点击事件,设置一些动画常量

private View mFab;
  private FrameLayout mFabcontainer;
  private LinearLayout mControlsContainer;
 
  //从什么时候开始执行动画
  private static final float SCALE_FACTOR = 13f;
  //持续时间
  private static final long ANIMATION_DURATION = 300;
  //贝塞尔曲线滑动到什么时候开始执行动画
  private static final float MINIMUN_X_DISTANCE = 200;
  private boolean mRevealFlag;
  private float mFabSize;

5、给mFab设置点击事件

private void onFabPressed(View view) {
    final float startX = mFab.getX();
    //开始动画
    AnimatorPath path = new AnimatorPath();
    path.moveTo(0, 0);
    path.curveTo(-200, 200, -400, 100, -600, 50);
//    path.lineTo(-600,50);
 
    ObjectAnimator anim = ObjectAnimator.ofObject(this, "fabLoc",
        new PathEvaluator(), path.getPoints().toArray());
    anim.setInterpolator(new AccelerateInterpolator());
//    anim.setRepeatCount(ValueAnimator.INFINITE);
//    anim.setRepeatMode(ValueAnimator.REVERSE);
    anim.setDuration(ANIMATION_DURATION);
    anim.start();
    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator valueAnimator) {
        //到了path路径中的某个位置就是开始扩散动画
        if (Math.abs(startX - mFab.getX()) > MINIMUN_X_DISTANCE) {
          if (!mRevealFlag) {
            ImageButton fab = (ImageButton) mFab;
            fab.setImageDrawable(new BitmapDrawable());
            //看布局里边的FabContainer要比toolbar背景高mFabSize/2(为了最初的半个fab效果)
            mFabcontainer.setY(mFabcontainer.getY() + mFabSize / 2);
            //fab放大动画
            mFab.animate()
                .scaleXBy(SCALE_FACTOR)
                .scaleYBy(SCALE_FACTOR)
                .setListener(mEndRevealListener)
                .setDuration(ANIMATION_DURATION);
            mRevealFlag = true;
          }
        }
      }
    });
  }
 
  public void setFabLoc(PathPoint newLoc) {
    mFab.setTranslationX(newLoc.mX);
    if (mRevealFlag) {
      //因为布局里边的mFabcontainer要比toolbar背景高mFabSize/2,所以fab为了看起来平顺,需要上移mFabSize/2
      mFab.setTranslationY(newLoc.mY - (mFabSize / 2));
    } else {
      mFab.setTranslationY(newLoc.mY);
    }
 
  }
 
  private AnimatorListenerAdapter mEndRevealListener = new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
      super.onAnimationEnd(animation);
      mFab.setVisibility(View.INVISIBLE);
      mFabcontainer.setBackgroundColor(getResources().getColor(R.color.colorAccent));
      //reveal动画完毕后,接着每一个子控件都有个缩放动画(依次顺序出来)
      for (int i = 0; i < mControlsContainer.getChildCount(); i++) {
        View v = mControlsContainer.getChildAt(i);
        ViewPropertyAnimator animate = v.animate()
            .scaleX(1)
            .scaleY(1)
            .setDuration(ANIMATION_DURATION);
        animate.setStartDelay(i * 50);
        animate.start();
      }
    }
  };

PathEvaluator

public class PathEvaluator implements TypeEvaluator<PathPoint> {
  @Override
  public PathPoint evaluate(float t, PathPoint startValue, PathPoint endValue) {
    //t执行的百分比 (0~1)
    float x, y;
    if (endValue.mOperation == PathPoint.CURVE) {
      //三阶贝塞尔曲线 公式
      float oneMinusT = 1 - t;
      x = oneMinusT * oneMinusT * oneMinusT * startValue.mX +
          3 * oneMinusT * oneMinusT * t * endValue.mControl0X +
          3 * oneMinusT * t * t * endValue.mControl1X +
          t * t * t * endValue.mX;
      y = oneMinusT * oneMinusT * oneMinusT * startValue.mY +
          3 * oneMinusT * oneMinusT * t * endValue.mControl0Y +
          3 * oneMinusT * t * t * endValue.mControl1X +
          t * t * t * endValue.mY;
    } else if (endValue.mOperation == PathPoint.LINE) {
      //x=起始点+t*起始点和终点的距离
      x = startValue.mX + t * (endValue.mX - startValue.mX);
      y = startValue.mY + t * (endValue.mY - startValue.mY);
    } else {
      x = endValue.mX;
      y = endValue.mY;
 
    }
    return PathPoint.moveTo(x, y);
  }
}

注意:属性动画既可以改变属性,也可以改变一个变量或者方法

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Android自定义实现循环滚轮控件WheelView

    Android自定义实现循环滚轮控件WheelView

    滚轮布局WheelView大家经常使用,比如在选择生日的时候,风格类似系统提供的DatePickerDialog,这篇文章主要为大家详细介绍了Android自定义实现循环滚轮控件WheelView,感兴趣的小伙伴们可以参考一下
    2016-07-07
  • 你该知道的Gradle配置知识总结

    你该知道的Gradle配置知识总结

    这篇文章主要给大家介绍了关于Gradle配置的相关资料,文中通过示例代码介绍的非常详细,对各位Android开发者们具有一定的参考学习价值,需要的朋友可以参考学习,下面随着小编来一起学习学习吧。
    2017-10-10
  • Android实现房贷计算器

    Android实现房贷计算器

    这篇文章主要为大家详细介绍了Android实现房贷计算器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • 详解Android studio中正确引入so文件的方法

    详解Android studio中正确引入so文件的方法

    本篇文章主要介绍了Android studio中正确引入so文件的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • Android实现客户端语音动弹界面实例代码

    Android实现客户端语音动弹界面实例代码

    这篇文章主要介绍了Android实现客户端语音动弹界面实例代码,文章只给大家介绍了控件布局的方法,需要的朋友可以参考下
    2017-11-11
  • 关于Android Activity之间跳转问题(Intent)

    关于Android Activity之间跳转问题(Intent)

    这篇文章主要介绍了Android Activity之间跳转Intent,当一个Acitivity需要启动另一个Activity时,通过Intent来表达自己的意图,告知系统启动哪个Activity,本文给大家详细讲解,需要的朋友可以参考下
    2022-10-10
  • Android studio实现刮刮乐的方法

    Android studio实现刮刮乐的方法

    这篇文章主要为大家详细介绍了Android studio实现刮刮乐的两种方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-10-10
  • Android RecycleView添加head配置封装的实例

    Android RecycleView添加head配置封装的实例

    这篇文章主要介绍了Android RecycleView添加head配置封装的实例的相关资料,这里提供实例帮助大家实现这样的功能,需要的朋友可以参考下
    2017-08-08
  • Android自定义控件的创建方法

    Android自定义控件的创建方法

    这篇文章主要为大家详细介绍了Android自定义控件的创建方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • Android开发中超好用的正则表达式工具类RegexUtil完整实例

    Android开发中超好用的正则表达式工具类RegexUtil完整实例

    这篇文章主要介绍了Android开发中超好用的正则表达式工具类RegexUtil,结合完整实例形式分析了Android正则表达式常见操作技巧,包括针对证件号、银行账号、手机号、邮编等的正则判断相关操作技巧,需要的朋友可以参考下
    2017-11-11

最新评论