Android实现炫酷播放效果

2020-10-30 11:34:29 浏览数 (1)

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

一、首先看效果

二、实现原理

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

三、实现

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

PathPoint.java

代码语言:javascript复制
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

代码语言:javascript复制
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、实现页面布局

代码语言:javascript复制
<?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、获取控件,并且设置点击事件,设置一些动画常量

代码语言:javascript复制
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设置点击事件

代码语言:javascript复制
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

代码语言:javascript复制
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);
}
}

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

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

0 人点赞