# 自定义View：播放、暂停按钮优雅的过渡

## 测量及初始化

``````
mWidth = MeasureSpec.getSize(widthMeasureSpec);
mHeight = MeasureSpec.getSize(heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
switch (widthMode) {
case MeasureSpec.EXACTLY:
mWidth = mHeight = Math.min(mWidth, mHeight);
setMeasuredDimension(mWidth, mHeight);
break;
case MeasureSpec.AT_MOST:
float density = getResources().getDisplayMetrics().density;
mWidth = mHeight = (int) (50 * density); //默认50dp
setMeasuredDimension(mWidth, mHeight);
break;
}

``````

``````
canvas.drawCircle(mWidth / 2, mHeight / 2, mRadius, mPaint);

``````

## 计算Path

1、初始化完毕后，怎么实现两个竖条到一个三角形的过渡呢？这里首先想到的就是自定义 View 常用的 drawPath 方法，抛开动画不谈，整个 View 变化过程其实就是两个矩形变成两个直角三角形的过程。

``````
float distance = mGapWidth;  //暂停时左右两边矩形距离
float barWidth = mRectWidth / 2 - distance / 2;     //一个矩形的宽度
float leftLeftTop = barWidth;       //左边矩形左上角

float rightLeftTop = barWidth + distance;       //右边矩形左上角
float rightRightTop = 2 * barWidth + distance;  //右边矩形右上角
float rightRightBottom = rightRightTop; //右边矩形右下角

``````

bottom 的话直接加上矩形的高度即可。

``````
mLeftPath.moveTo(0, 0);
mLeftPath.lineTo(leftLeftTop, mRectHeight);
mLeftPath.lineTo(barWidth, mRectHeight);
mLeftPath.lineTo(barWidth, 0);
mLeftPath.close();

mRightPath.moveTo(rightLeftTop, 0);
mRightPath.lineTo(rightLeftTop, mRectHeight);
mRightPath.lineTo(rightRightBottom, mRectHeight);
mRightPath.lineTo(rightRightTop, 0);
mRightPath.close();

``````

2、在一开始写的时候就写了这么多计算的方法，但是这时候矩形的边角会超出 View 的范围，所以后来计算了一波位置：

``````
float space = (float) (mRadius / Math.sqrt(2));
mRectLT = (int) (mRadius - space);
int rectRB = (int) (mRadius + space);
mRect.top = mRectLT;
mRect.bottom = rectRB;
mRect.left = mRectLT;
mRect.right = rectRB;

``````

``````
mLeftPath.moveTo(mRectLT, mRectLT);
mLeftPath.lineTo(leftLeftTop + mRectLT, mRectHeight + mRectLT);
mLeftPath.lineTo(barWidth + mRectLT, mRectHeight + mRectLT);
mLeftPath.lineTo(barWidth + mRectLT, mRectLT);
mLeftPath.close();

mRightPath.moveTo(rightLeftTop + mRectLT, mRectLT);
mRightPath.lineTo(rightLeftTop + mRectLT, mRectHeight + mRectLT);
mRightPath.lineTo(rightRightBottom + mRectLT, mRectHeight + mRectLT);
mRightPath.lineTo(rightRightTop + mRectLT, mRectLT);
mRightPath.close();

``````

``````
canvas.drawPath(mLeftPath, mPaint);
canvas.drawPath(mRightPath, mPaint);

``````

## 动画实现

``````
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0 , 1);
valueAnimator.setDuration(200);
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mProgress = (float) animation.getAnimatedValue();
invalidate();
}
});

``````

``````
float distance = mGapWidth * (1 - mProgress);  //暂停时左右两边矩形距离
float barWidth = mRectWidth / 2 - distance / 2;     //一个矩形的宽度
float leftLeftTop = barWidth * mProgress;       //左边矩形左上角

float rightLeftTop = barWidth + distance;       //右边矩形左上角
float rightRightTop = 2 * barWidth + distance;  //右边矩形右上角
float rightRightBottom = rightRightTop - barWidth * mProgress; //右边矩形右下角

``````

``````
canvas.rotate(rotation, mWidth / 2f, mHeight / 2f);

``````

√（( r / √2 ) ^ 2 + OF ^ 2） = √2 * r - OF

``````radius * Math.sqrt(2) / 8f
``````

``````mRectHeight / 8f
``````

``````
canvas.translate((float) (mRectHeight / 8f * mProgress), 0);

``````

## 总结

``````
<declare-styleable name="PlayPauseView">
<attr name="bg_color" format="color"/>
<attr name="btn_color" format="color"/>
<attr name="gap_width" format="float"/>