天天看點

android自定義滑塊解鎖

雖然網上已經有很多這個代碼,但是還是需要自己寫一遍,才能更深刻的了解其中的原理和步驟。

先看效果圖:

android自定義滑塊解鎖

 這裡的矩形,可以設定圓角,圓角非常大的時候,會變成圓形。

看代碼:

自定義內建View:

package com.test.viewtest;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;

/**
 * @date 2021/09/07
 * 側滑按鈕
 */
public class ProfileSlideView extends View {

    private Paint mBgPaint;
    private Paint mSliderPaint;
    private Paint mTextPaint;
    private Paint mArrowPaint;

    private RectF mBgRectF;
    private RectF mSliderRectF;
    private RectF mProgressRectF;

    //側滑條圓角度數
    private Float mCorner = 50f;
    private float mPadding = 4;
    private float mSliderWidth = 200;//滑塊寬度
    private Path mSlideArrowPath;

    private String mTipText = "右滑開鎖";//提示文案
    private float mTextSize ;//文字大小
    private float mLastTouchX = 0;
    //動畫
    private  ValueAnimator mAutoSlideAnimator;
    //滑塊自動歸位動畫時長
    private int mAutoSlideTime = 500;
    private float mSliderLevel = 0.5f;

    private int mProgressColor ;//已滑過的區域顔色
    private int mBackgroundColor ;//背景圖顔色
    private int mArrowPaintColor ;//箭頭顔色
    private int mTextPaintColor ;//提示文字顔色
    private int mSliderPaintColor ;//滑塊顔色

    public ProfileSlideView(Context context) {
        this(context, null);
    }

    public ProfileSlideView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ProfileSlideView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(context,attrs,defStyleAttr);
        mBgPaint = new Paint();
        mBgPaint.setAntiAlias(true);
        mBgPaint.setStyle(Paint.Style.FILL);
        mBgPaint.setColor(mBackgroundColor);
        mBgPaint.setAlpha(100);

        mSliderPaint = new Paint();
        mSliderPaint.setAntiAlias(true);
        mSliderPaint.setStyle(Paint.Style.FILL);

        mArrowPaint = new Paint();
        mArrowPaint.setAntiAlias(true);
        mArrowPaint.setStyle(Paint.Style.FILL);
        mArrowPaint.setColor(mArrowPaintColor);

        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setColor(mTextPaintColor);
        mTextPaint.setTextSize(30);

        mBgRectF = new RectF();
        mSliderRectF = new RectF();
        mProgressRectF = new RectF();

        mSlideArrowPath = new Path();
    }

    private void initAttrs(Context context, AttributeSet attrs, int defStyleAttr) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ProfileSlideView, defStyleAttr, 0);

        mCorner = typedArray.getDimension(R.styleable.ProfileSlideView_slideCorner, 22f);
        mSliderWidth = typedArray.getDimension(R.styleable.ProfileSlideView_sliderWidth,80f);
        mTextSize = typedArray.getDimension(R.styleable.ProfileSlideView_tipTextSize,16f);
        mAutoSlideTime = typedArray.getInt(R.styleable.ProfileSlideView_autoSlideTime, 500);
        mTipText = typedArray.getString(R.styleable.ProfileSlideView_tipText);
        mPadding = typedArray.getDimension(R.styleable.ProfileSlideView_sliderPadding, 2f);
        mSliderLevel = typedArray.getFloat(R.styleable.ProfileSlideView_sliderLevel, 0.5f);

        mProgressColor = typedArray.getColor(R.styleable.ProfileSlideView_mProgressColor, Color.parseColor("#88FFA0"));
        mBackgroundColor = typedArray.getColor(R.styleable.ProfileSlideView_bgPaintColor, Color.parseColor("#AAAAAA"));
        mArrowPaintColor = typedArray.getColor(R.styleable.ProfileSlideView_arrowPaintColor, Color.parseColor("#1A42E6"));
        mTextPaintColor = typedArray.getColor(R.styleable.ProfileSlideView_tipPaintColor, Color.parseColor("#444444"));
        mSliderPaintColor = typedArray.getColor(R.styleable.ProfileSlideView_sliderPaintColor, Color.parseColor("#00BB25"));

        typedArray.recycle();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        int viewWidth = right - left;
        int viewHeight = bottom - top;

        mBgRectF.left = 0f;
        mBgRectF.top = 0f;
        mBgRectF.right = viewWidth * 1.0f;
        mBgRectF.bottom = viewHeight * 1.0f;
        //mPadding為滑塊與背景條之間的邊距
        mSliderRectF.left = mPadding;
        mSliderRectF.top = mPadding;
        mSliderRectF.right = mSliderWidth;
        mSliderRectF.bottom = viewHeight * 1.0f - mPadding;

        mProgressRectF.left = mPadding;
        mProgressRectF.top = mPadding;
        mProgressRectF.right = mSliderWidth / 2;
        mProgressRectF.bottom = viewHeight * 1.0f - mPadding;
        Log.d("viewTest", "mSliderRectF: "+mSliderRectF.toString());
        Log.d("viewTest", "mProgressRectF: "+mProgressRectF.toString());

    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //繪制背景圖
        drawBackground(canvas);
        //繪制有效進度
        drawProgress(canvas);
        //繪制 圓形滑塊
        drawSlide(canvas);
        //繪制文字
        drawTipText(canvas);

        //初始化動畫
        initAnim();
    }

    private void drawBackground(Canvas canvas) {
        canvas.drawRoundRect(mBgRectF, mCorner, mCorner, mBgPaint);
    }

    //繪制滑塊
    private void drawSlide(Canvas canvas) {
        mSliderPaint.setColor(mSliderPaintColor);
        canvas.drawRoundRect(mSliderRectF, mCorner, mCorner,mSliderPaint);

        mArrowPaint.setStyle(Paint.Style.STROKE);
        mArrowPaint.setStrokeWidth(3f);
        //箭頭寬度為滑塊的1/16
        float arrowWidth = mSliderWidth / 16f;
        //繪制箭頭
        mSlideArrowPath.reset();
        //這裡使得 箭頭的橫坐标 在滑塊的1/2處
        float arrowPos = 0.5f;
        mSlideArrowPath.moveTo(mSliderRectF.left + mSliderWidth * arrowPos - (arrowWidth) / 2, mSliderRectF.bottom / 3f);
        mSlideArrowPath.lineTo(mSliderRectF.left + mSliderWidth * arrowPos + arrowWidth, mSliderRectF.bottom / 2f);
        mSlideArrowPath.lineTo(mSliderRectF.left + mSliderWidth * arrowPos - arrowWidth / 2, mSliderRectF.bottom * 2 / 3f);
        canvas.drawPath(mSlideArrowPath, mArrowPaint);
    }

    private void drawTipText(Canvas canvas) {
        float textWidth = mTextPaint.measureText(mTipText);
        Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
        Float baseLine = mBgRectF.height() * 0.5f - (fontMetrics.ascent + fontMetrics.descent) / 2;
        canvas.drawText(mTipText, ((mBgRectF.width() - mSliderWidth - textWidth) / 2f) + mSliderWidth, baseLine, mTextPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        Log.v("viewTest"," x= " +x+" y = "+y);
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            if(mSliderRectF.contains(x,y)){
                mAutoSlideAnimator.cancel();
            }else {
                return false;
            }
        } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
            if (mLastTouchX > 0f) {
                if( mSliderRectF.left + x - mLastTouchX + mSliderWidth > mBgRectF.width() - mPadding ){//判斷是否滑到了整個View的最右邊
                    mSliderRectF.left = mBgRectF.width() - mPadding - mSliderWidth;
                }else if(mSliderRectF.left + x - mLastTouchX < mPadding){//判斷是否滑到了整個View的最左邊
                    mSliderRectF.left = mPadding;
                }else {
                    mSliderRectF.left += x - mLastTouchX;
                }
                mSliderRectF.right = mSliderRectF.left + mSliderWidth;
                mProgressRectF.right = mSliderRectF.right;
                invalidate();
            }
            mLastTouchX = x;
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
//            if (mSliderRectF.centerX() > mBgRectF.centerX()) {
            if (mSliderRectF.centerX() > (mBgRectF.left+(mBgRectF.right-mBgRectF.left)*mSliderLevel)) {
                mAutoSlideAnimator.setFloatValues(mSliderRectF.left, mBgRectF.right - mPadding - mSliderWidth);
                mAutoSlideAnimator.start();
            } else {
                mAutoSlideAnimator.setFloatValues(mSliderRectF.left, mPadding);
                mAutoSlideAnimator.start();
            }
        }
        return true;
    }

    private void initAnim() {
        mAutoSlideAnimator = new ValueAnimator();
        mAutoSlideAnimator.setDuration(mAutoSlideTime);
        mAutoSlideAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mSliderRectF.left = (float) animation.getAnimatedValue();
                mSliderRectF.right = mSliderRectF.left + mSliderWidth;
                Log.e("viewTest","  mSliderRectF.right=="+ mSliderRectF.right);
                mProgressRectF.right = mSliderRectF.right;
                if (mSliderRectF.right == mBgRectF.width() - mPadding) {
                    if(mListener !=null){
                        mListener.slideEnd();
                    }
                    Log.e("viewTest"," mListener.slideEnd();");
                }
                invalidate();
            }
        });
    }
    private void drawProgress(Canvas canvas) {
        mSliderPaint.setColor(mProgressColor);
        canvas.drawRoundRect(mProgressRectF, mCorner, mCorner, mSliderPaint);
    }


    SlideListener mListener;

    public void addSlideListener(SlideListener listener) {
        mListener = listener;
    }

    public interface SlideListener {
        void slideEnd();
    }
}
           

自定義屬性:

<declare-styleable name="ProfileSlideView">
        <!-- 滑塊寬度 -->
        <attr name="sliderWidth" format="dimension" />
        <!-- 側滑條圓角度數 -->
        <attr name="slideCorner" format="dimension" />
        <!-- 滑塊和background之間的padding -->
        <attr name="sliderPadding" format="dimension" />
        <!-- 提示的文字 -->
        <attr name="tipText" format="string" />
        <!-- 提示的文字 大小 -->
        <attr name="tipTextSize" format="dimension" />
        <!-- 滑塊自動歸位動畫時長 -->
        <attr name="autoSlideTime" format="integer" />
        <!-- 已滑過的區域顔色 -->
        <attr name="mProgressColor" format="color" />
        <!-- 背景圖顔色 -->
        <attr name="bgPaintColor" format="color" />
        <!-- 箭頭顔色 -->
        <attr name="arrowPaintColor" format="color" />
        <!-- 提示文字顔色 -->
        <attr name="tipPaintColor" format="color" />
        <!-- 滑塊顔色 -->
        <attr name="sliderPaintColor" format="color" />
        <!-- 閥值(0-1之間) -->
        <attr name="sliderLevel" format="float" />
    </declare-styleable>
           

xml檔案中使用:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center">

    <com.test.viewtest.ProfileSlideView
        android:id="@+id/slideView"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        app:sliderWidth="200px"
        app:slideCorner="20dp"
        app:sliderPadding="2dp"
        app:tipText="右滑開鎖"
        app:tipTextSize="30sp"
        app:tipPaintColor="@color/textPaintColor"
        app:bgPaintColor="@color/backgroundColor"
        app:arrowPaintColor="@color/arrowPaintColor"
        app:mProgressColor="@color/progressColor"
        app:sliderPaintColor="@color/sliderPaintColor"
        app:sliderLevel="0.7"
        app:autoSlideTime="500" />

</LinearLayout>
           

activity中使用:

package com.test.viewtest.activity;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.Nullable;

import com.test.viewtest.ProfileSlideView;
import com.test.viewtest.R;

public class SlideViewActivity extends Activity {

    private ProfileSlideView profileSlideView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.slide_view);

        profileSlideView = findViewById(R.id.slideView);

        profileSlideView.addSlideListener(new ProfileSlideView.SlideListener() {
            @Override
            public void slideEnd() {
                Log.d("SlideViewActivity","slideEnd");
                Toast.makeText(SlideViewActivity.this,"slideEnd",Toast.LENGTH_SHORT).show();
            }
        });
    }
}