用屬性動畫實現一個確認按鈕
不多BB,先上圖
- 此按鈕由一個圓一個勾組成,準確的說應該是一個圓2條線組成
- 還有動畫,這裡用的是屬性動畫,分為4部分,圓圈,線(2條),還有整體的放大縮小
開工
這裡不解釋初始化畫筆,各種資料過程,
關鍵點在onDraw方法裡
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Log.e("current", "X:" + mCenterX + "," + "Y:" + mCenterY);
mRectF.left = mCenterX - mRadius;
mRectF.top = mCenterY - mRadius;
mRectF.right = mCenterX + mRadius;
mRectF.bottom = mCenterY + mRadius;
//畫圓
canvas.drawArc(mRectF, 0, mDegree, false, mCirclePaint);
//畫勾左邊
canvas.drawLine(mCenterX - mRadius / 2, mCenterY,
mCenterX - mRadius / 2 + mLeftValue, mCenterY + mLeftValue,
mLinePaint);
//畫勾的右邊
//mCenterX + mRightValue, mCenterY + mRadius / 2 - 1.7f * mRightValue這個座標在下圖解析
canvas.drawLine(mCenterX, mCenterY + mRadius / 2,
mCenterX + mRightValue, mCenterY + mRadius / 2 - 1.7f * mRightValue, mLinePaint);
}
mLeftValue,mRightValue是動態改變的
下面解釋mCenterX + mRightValue, mCenterY + mRadius / 2 - 1.7f * mRightValue這個座標
這裡m=mRightValue(動態變化的值)
h就是勾右邊線座標高度
1.7是估計出來的值,假設勾右邊線與y軸成30度
其他的比如動畫等的,原始碼裡註釋的很清楚-----AnimationViewSet
原始碼
/**
* 圓圈的畫筆
*/
private Paint mCirclePaint;
/**
* 線的畫筆
*/
private Paint mLinePaint;
/**
* 設定線寬,px
*/
private float mStrokeWidth = 10;
private float mCenterX, mCenterY;
/**
* 為了畫出目標圓形的矩形外框
*/
private RectF mRectF = new RectF();
/**
* 圓的半徑
*/
private float mRadius = 300;
/**
* 畫圓時動態設定的角度
*/
private Float mDegree = 360f;
private Float mLeftValue = 150f;
private Float mRightValue = 150f;
//預設半徑
private static final int DEFAULT_RADIUS = 150;
//邊距
private static final float PADDING = 20;
private AnimatorSet mAnimatorSet = new AnimatorSet();
private ValueAnimator mCircleAnim;
private ValueAnimator mLineLeftAnimator;
private ValueAnimator mLineRightAnimator;
public ConfirmView(Context context) {
this(context, null);
}
public ConfirmView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ConfirmView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaint();
}
/**
* 初始化畫筆
*/
private void initPaint() {
mCirclePaint = new Paint();
//抗鋸齒
mCirclePaint.setAntiAlias(true);
//設定連線點為圓角
mCirclePaint.setStrokeJoin(Paint.Join.ROUND);
mCirclePaint.setStrokeWidth(mStrokeWidth);
mCirclePaint.setColor(Color.WHITE);
mCirclePaint.setStyle(Paint.Style.STROKE);
mLinePaint = new Paint();
mLinePaint.setAntiAlias(true);
mLinePaint.setStrokeJoin(Paint.Join.ROUND);
mLinePaint.setStrokeWidth(mStrokeWidth);
mLinePaint.setColor(Color.WHITE);
mLinePaint.setStyle(Paint.Style.STROKE);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
reMeasure();
}
/**
* 重新測量寬和高
*/
private void reMeasure() {
int viewWidth = getMeasuredWidth();
int viewHeight = getMeasuredHeight();
mCenterX = viewWidth / 2;
mCenterY = viewHeight / 2;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mCenterX = w / 2;
mCenterY = h / 2;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Log.e("current", "X:" + mCenterX + "," + "Y:" + mCenterY);
mRectF.left = mCenterX - mRadius;
mRectF.top = mCenterY - mRadius;
mRectF.right = mCenterX + mRadius;
mRectF.bottom = mCenterY + mRadius;
//畫圓
canvas.drawArc(mRectF, 0, mDegree, false, mCirclePaint);
//畫勾左邊
canvas.drawLine(mCenterX - mRadius / 2, mCenterY,
mCenterX - mRadius / 2 + mLeftValue, mCenterY + mLeftValue,
mLinePaint);
//畫勾的右邊
//mCenterX + mRightValue, mCenterY + mRadius / 2 - 1.7f * mRightValue這個座標
canvas.drawLine(mCenterX, mCenterY + mRadius / 2,
mCenterX + mRightValue, mCenterY + mRadius / 2 - 1.7f * mRightValue, mLinePaint);
}
public void loadCircle(int mRadius) {
mRadius = mRadius < 0 ? DEFAULT_RADIUS : mRadius;
this.mRadius = mRadius - PADDING;
if (mAnimatorSet != null && mAnimatorSet.isRunning()) {
return;
}
resetDegreeAndLeftRightValueAndPaintColor();
reMeasure();
//這裡其實限定了
//mDegree,對應更新值的方法是mLeftValue = (Float) animation.getAnimatedValue();,在下面的監聽器裡
//mLeftValue
//mRightValue三個數的取值
mCircleAnim = ValueAnimator.ofFloat(0, 360);
mLineLeftAnimator = ValueAnimator.ofFloat(0, this.mRadius / 2f);
mLineRightAnimator = ValueAnimator.ofFloat(0, this.mRadius / 2f);
mCircleAnim.setDuration(800);
mLineLeftAnimator.setDuration(500);
mLineRightAnimator.setDuration(500);
mCircleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mDegree = (Float) animation.getAnimatedValue();
invalidate();
}
});
mLineLeftAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mLeftValue = (Float) animation.getAnimatedValue();
invalidate();
}
});
mLineRightAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mRightValue = (Float) animation.getAnimatedValue();
invalidate();
}
});
mAnimatorSet.play(mCircleAnim).before(mLineLeftAnimator);
mAnimatorSet.play(mLineRightAnimator).after(mLineLeftAnimator);
mAnimatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
stopPropertyAnimation();
if (mEndListener != null) {
mEndListener.onCircleDone();
//放大效果
loadEndAnim();
}
}
});
mAnimatorSet.start();
}
/**
* 載入結束動畫
*/
private void loadEndAnim() {
//放大的值
ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(this, "scaleX", 1.0f, 1.2f, 1.0f);
ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(this, "scaleY", 1.0f, 1.2f, 1.0f);
AnimatorSet set = new AnimatorSet();
set.setDuration(3000);
set.setInterpolator(new BounceInterpolator());
set.playTogether(scaleXAnim, scaleYAnim);
set.start();
}
private void stopPropertyAnimation() {
if (null != mCircleAnim) {
mCircleAnim.end();
}
if (null != mLineLeftAnimator) {
mLineLeftAnimator.end();
}
if (null != mLineRightAnimator) {
mLineRightAnimator.end();
}
clearAnimation();
}
private void resetDegreeAndLeftRightValueAndPaintColor() {
mDegree = 0f;
mLeftValue = 0f;
mRightValue = 0f;
mCirclePaint.setColor(Color.WHITE);
mLinePaint.setColor(Color.WHITE);
}
public interface onCircleFinishListener {
void onCircleDone();
}
private onCircleFinishListener mEndListener;
public void addCircleAnimatorEndListener(onCircleFinishListener endListener) {
if (mEndListener == null) {
this.mEndListener = endListener;
}
}
public void setPaintColor(int color) {
mCirclePaint.setColor(color);
mLinePaint.setColor(color);
invalidate();
}
}
相關文章
- 用CSS Houdini實現一個Material風格的按鈕CSS
- Flutter 敲一個靈動的錄音按鈕動畫 - Speed CodeFlutter動畫
- VOL表格動態新增操作按鈕及彈窗確認方法
- Flutter動畫:用Flutter來實現一個拍手動畫Flutter動畫
- Android 屬性動畫實戰Android動畫
- CSS3動畫按鈕效果CSSS3動畫
- 屬性動畫動畫
- 用ESP32-C3做一個運動按鈕
- layUI layer彈框按鈕 : 確認,取消,關閉事件UI事件
- 直播平臺開發,Clip-path實現按鈕流動邊框動畫動畫
- 使用SVG實現的一個Android播放/暫停按鈕SVGAndroid
- VUE動態路由和按鈕的實現Vue路由
- Android 動畫之屬性動畫Android動畫
- android屬性動畫Android動畫
- Qt實現一個支援QSS的Switch Button(開關按鈕)QT
- java實現用一個變數表示多個屬性的狀態Java變數
- HTML 單選按鈕實現 (性別選擇)(解讀)HTML
- JavaFx 實現按鈕防抖Java
- SVG 和 CSS3 實現一個超酷愛心 Like 按鈕SVGCSSS3
- iOS - 新增一個全域性懸浮按鈕(整合pods版)iOS
- SVG 動畫 fill 屬性SVG動畫
- SVG restart 動畫屬性SVGREST動畫
- SVG restart動畫屬性SVGREST動畫
- 一個按鈕,一鍵傳功!
- [譯] 用 Flutter 實現 Facebook 的響應式按鈕Flutter
- CSS3滑鼠懸浮動畫按鈕效果CSSS3動畫
- unity 實現輪盤方式的按鈕滾動效果Unity
- 【Android 動畫】動畫詳解之屬性動畫(三)Android動畫
- 【Android 動畫】動畫詳解之屬性動畫(五)Android動畫
- VB.net MessageBox彈出的確認對話方塊點選確定按鈕
- js練習----radio name屬性定義單選按鈕組JS
- QFileDialog實現同時選擇檔案和資料夾,確認取消按鈕英文問題解決方法
- XE 畫矩形實現拖拉改變大小(屬性)
- Android 動畫詳解:屬性動畫、View 動畫和幀動畫Android動畫View
- 初識屬性動畫——使用Animator建立動畫動畫
- Laravel 動態屬性的實現Laravel
- 屬性動畫與差值器動畫
- web前端動畫專題(3):撩人的按鈕特效Web前端動畫特效
- Simple WPF: WPF 實現按鈕的長按,短按功能