溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Android如何自定義帶有圓形進(jìn)度條的可長按控件功能

發(fā)布時間:2022-06-16 10:02:09 來源:億速云 閱讀:182 作者:iii 欄目:開發(fā)技術(shù)

今天小編給大家分享一下Android如何自定義帶有圓形進(jìn)度條的可長按控件功能的相關(guān)知識點,內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

(一)繼承自View并實現(xiàn)構(gòu)造方法,代碼如下:

public class LongClickView extends View {
    public int DEFAULT_MAX_SECONDS = 15;
    public int DEFAULT_ANNULUS_WIDTH = 5;
    public int DEFAULT_ANNULUS_COLOR;
    public int DEFAULT_RATE = 50;
    private Paint mSmallCirclePaint;
    private Paint mMiddenCirclePaint;
    private Paint mBigCirclePaint;
    private Paint mAngleCirclePaint;
    private int mWidthSize;
    private Timer mTimer;//計時器
    private AtomicInteger mCount = new AtomicInteger(0);
    private MyClickListener mMyClickListener;
    private boolean mIsFinish = true;
    private long mStartTime;//點擊的時間
    private long mEndTime;//點擊結(jié)束的時間
    private int mMaxSeconds;
    private int mDelayMilliseconds;
    private int mAnnulusColor;
    private float mAnnulusWidth;

    public interface MyClickListener {
        void longClickFinish();//長按結(jié)束

        void singleClickFinish();//單擊結(jié)束
    }

    public void setMyClickListener(MyClickListener myClickListener) {
        mMyClickListener = myClickListener;
    }

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

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

    public LongClickView(Context context, @Nullable AttributeSet attrs, int defStyleAttr)                 {
        super(context, attrs, defStyleAttr);
        getAttrs(context, attrs);
        initView();
    }
}

(二)定義并獲取自定義屬性,屬性以及獲取屬性代碼如下:

attr_long_click_view.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="LongClickView">
        <attr name="maxSeconds" format="integer" />
        <attr name="annulusWidth" format="integer" />
        <attr name="annulusColor" format="color" />
        <attr name="delayMilliseconds" format="integer" />
    </declare-styleable>
</resources>
 private void getAttrs(Context context, @Nullable AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.LongClickView);
        //maxSeconds 最大的秒數(shù)
        mMaxSeconds = typedArray.getInt(R.styleable.LongClickView_maxSeconds, DEFAULT_MAX_SECONDS);
        //annulusWidth 圓環(huán)的寬度
        mAnnulusWidth = typedArray.getInt(R.styleable.LongClickView_annulusWidth, DEFAULT_ANNULUS_WIDTH);
        //annulusColor 圓環(huán)的顏色
        DEFAULT_ANNULUS_COLOR = context.getResources().getColor(R.color.color_grey);
        mAnnulusColor = typedArray.getColor(R.styleable.LongClickView_annulusColor, DEFAULT_ANNULUS_COLOR);
        //delayMilliseconds 進(jìn)度條隔多少時間走一次,值越小走的越快,顯得更流暢
        mDelayMilliseconds = typedArray.getInt(R.styleable.LongClickView_delayMilliseconds, DEFAULT_RATE);
    }

(三)定義畫筆工具 的代碼如下:

    private void initView() {
        mBigCirclePaint = new Paint();
        mSmallCirclePaint = new Paint();
        mMiddenCirclePaint = new Paint();
        mAngleCirclePaint = new Paint();
        mBigCirclePaint.setStyle(Paint.Style.FILL);
        mBigCirclePaint.setColor(Color.LTGRAY);
        mBigCirclePaint.setAntiAlias(true);
        mBigCirclePaint.setStrokeWidth(5);
        mSmallCirclePaint.setStrokeWidth(5);
        mSmallCirclePaint.setAntiAlias(true);
        mSmallCirclePaint.setColor(Color.WHITE);
        mSmallCirclePaint.setStyle(Paint.Style.FILL);

        mMiddenCirclePaint.setStrokeWidth(5);
        mMiddenCirclePaint.setAntiAlias(true);
        mMiddenCirclePaint.setColor(Color.LTGRAY);
        mMiddenCirclePaint.setStyle(Paint.Style.FILL);
        mAngleCirclePaint.setStrokeWidth(5);
        mAngleCirclePaint.setAntiAlias(true);
        mAngleCirclePaint.setColor(mAnnulusColor);
        mAngleCirclePaint.setStyle(Paint.Style.FILL);
        ...//這里是長按監(jiān)聽

    }

(四)onMeasure中測量大小,onDraw中繪制圓與扇形,代碼如下:

onMeasure中,如果沒有定義實際寬高就會使用父組件的寬高,如果有實際寬高便會使用自己的寬高

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mWidthSize = MeasureSpec.getSize(widthMeasureSpec);
        setMeasuredDimension(mWidthSize, mWidthSize);
    }

onDraw中,一共有三層圓形填充繪制以及一層扇形填充繪制,先繪制最外層的灰色圓形,再根據(jù)此時的進(jìn)度繪制一定角度的扇形,然后覆蓋一層灰色的圓形,最后在覆蓋上一層白色的中心圓,并且在繪制過程以及繪制結(jié)束時的中心圓半徑不同。代碼如下:

 @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawCircle(mWidthSize / 2, mWidthSize / 2, mWidthSize / 2, mBigCirclePaint);//最外層的填充圓
        RectF rectF = new RectF(0, 0, mWidthSize, mWidthSize);//進(jìn)度扇形
        if (mCount.get() > 0) {
            //求出每一次定時器執(zhí)行所繪制的扇形度數(shù)
            float perAngle = 360f / mMaxSeconds / (1000f / mDelayMilliseconds);
            canvas.drawArc(rectF, 0, perAngle * mCount.get(), true, mAngleCirclePaint);
        }
        canvas.drawCircle(mWidthSize / 2, mWidthSize / 2, mWidthSize / 2 - mAnnulusWidth, mMiddenCirclePaint);//中間一層灰色的圓
        //最后繪制中心圓
        if (mIsFinish) {
            canvas.drawCircle(mWidthSize / 2, mWidthSize / 2, mWidthSize / 2 - mAnnulusWidth, mSmallCirclePaint);
        } else {
            canvas.drawCircle(mWidthSize / 2, mWidthSize / 2, mWidthSize / 8, mSmallCirclePaint);
        }
        super.onDraw(canvas);
    }

(五)監(jiān)聽長按監(jiān)聽開始定時器并刷新畫布,監(jiān)聽觸摸事件進(jìn)行結(jié)束的回調(diào),定時器使用的是Timer類,當(dāng)時間超過自定義的最大秒數(shù)時就會自動停止,并定時刷新畫布,代碼如下:

        this.setOnLongClickListener(new OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                mIsFinish = false;
                mCount.set(0);
                mTimer = new Timer();
                mTimer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        mCount.addAndGet(1);
                        invalidate();
                        if (mCount.get() * mDelayMilliseconds >= mMaxSeconds * 1000) {
                            mCount.set(0);
                            this.cancel();
                            invalidate();
                            mIsFinish = true;
                            if (mMyClickListener != null) {
                                mMyClickListener.longClickFinish();
                            }
                        }
                    }
                }, 0, mDelayMilliseconds);
                return true;
            }
        });
 @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            mEndTime = System.currentTimeMillis();
            new MyAsyncTask().execute();
        } else if (event.getAction() == MotionEvent.ACTION_DOWN) {
            mStartTime = System.currentTimeMillis();
        }
        return super.onTouchEvent(event);
    }

將定時器停止與停止后的判斷邏輯放在AsyncTask中編寫,確保定時器不會繼續(xù)處理邏輯之后再做判斷

    public class MyAsyncTask extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... voids) {
            if (mTimer != null) {
                mTimer.cancel();
            }
            return null;
        }
        @Override
        protected void onPostExecute(Void aVoid) {
            //使用時間戳的差來判斷是單擊或者長按
            if (mEndTime - mStartTime > 1000) {
                //防止在自動結(jié)束后松開手指又重新調(diào)用了一次長按結(jié)束的回調(diào)
                if (!mIsFinish) {
                    if (mMyClickListener != null) {
                        mMyClickListener.longClickFinish();
                    }
                }
            } else {
                //若是單擊就清除進(jìn)度條
                mCount.set(0);
                invalidate();
                if (mMyClickListener != null) {
                    mMyClickListener.singleClickFinish();
                }
            }
            mIsFinish = true;
        }
    }

結(jié)束后的回調(diào)類代碼如下:

   public interface MyClickListener {
        void longClickFinish();//長按結(jié)束

        void singleClickFinish();//單擊結(jié)束
    }

最后,完整的代碼如下,自定義屬性上方有貼出來代碼:

public class LongClickView extends View {
    public int DEFAULT_MAX_SECONDS = 15;
    public int DEFAULT_ANNULUS_WIDTH = 5;
    public int DEFAULT_ANNULUS_COLOR;
    public int DEFAULT_RATE = 50;
    private Paint mSmallCirclePaint;
    private Paint mMiddenCirclePaint;
    private Paint mBigCirclePaint;
    private Paint mAngleCirclePaint;
    private int mWidthSize;
    private Timer mTimer;//計時器
    private AtomicInteger mCount = new AtomicInteger(0);
    private MyClickListener mMyClickListener;
    private boolean mIsFinish = true;
    private long mStartTime;//點擊的時間
    private long mEndTime;//點擊結(jié)束的時間
    private int mMaxSeconds;
    private int mDelayMilliseconds;
    private int mAnnulusColor;
    private float mAnnulusWidth;
    public interface MyClickListener {
        void longClickFinish();//長按結(jié)束
        void singleClickFinish();//單擊結(jié)束
    }
    public void setMyClickListener(MyClickListener myClickListener) {
        mMyClickListener = myClickListener;
    }
    public LongClickView(Context context) {
        this(context, null);
    }
    public LongClickView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public LongClickView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        getAttrs(context, attrs);
        initView();
    }
    private void getAttrs(Context context, @Nullable AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.LongClickView);
        //maxSeconds 最大的秒數(shù)
        mMaxSeconds = typedArray.getInt(R.styleable.LongClickView_maxSeconds, DEFAULT_MAX_SECONDS);
        //annulusWidth 圓環(huán)的寬度
        mAnnulusWidth = typedArray.getInt(R.styleable.LongClickView_annulusWidth, DEFAULT_ANNULUS_WIDTH);
        //annulusColor 圓環(huán)的顏色
        DEFAULT_ANNULUS_COLOR = context.getResources().getColor(R.color.color_grey);
        mAnnulusColor = typedArray.getColor(R.styleable.LongClickView_annulusColor, DEFAULT_ANNULUS_COLOR);
        //delayMilliseconds 進(jìn)度條隔多少時間走一次,值越小走的越快,顯得更流暢
        mDelayMilliseconds = typedArray.getInt(R.styleable.LongClickView_delayMilliseconds, DEFAULT_RATE);
    }
    private static final String TAG = "LongClickView";
    private void initView() {
        mBigCirclePaint = new Paint();
        mSmallCirclePaint = new Paint();
        mMiddenCirclePaint = new Paint();
        mAngleCirclePaint = new Paint();
        mBigCirclePaint.setStyle(Paint.Style.FILL);
        mBigCirclePaint.setColor(Color.LTGRAY);
        mBigCirclePaint.setAntiAlias(true);
        mBigCirclePaint.setStrokeWidth(5);
        mSmallCirclePaint.setStrokeWidth(5);
        mSmallCirclePaint.setAntiAlias(true);
        mSmallCirclePaint.setColor(Color.WHITE);
        mSmallCirclePaint.setStyle(Paint.Style.FILL);
        mMiddenCirclePaint.setStrokeWidth(5);
        mMiddenCirclePaint.setAntiAlias(true);
        mMiddenCirclePaint.setColor(Color.LTGRAY);
        mMiddenCirclePaint.setStyle(Paint.Style.FILL);
        mAngleCirclePaint.setStrokeWidth(5);
        mAngleCirclePaint.setAntiAlias(true);
        mAngleCirclePaint.setColor(mAnnulusColor);
        mAngleCirclePaint.setStyle(Paint.Style.FILL);
        this.setOnLongClickListener(new OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                mIsFinish = false;
                mCount.set(0);
                mTimer = new Timer();
                mTimer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        mCount.addAndGet(1);
                        invalidate();
                        if (mCount.get() * mDelayMilliseconds >= mMaxSeconds * 1000) {
                            mCount.set(0);
                            this.cancel();
                            invalidate();
                            mIsFinish = true;
                            if (mMyClickListener != null) {
                                mMyClickListener.longClickFinish();
                            }
                        }
                    }
                }, 0, mDelayMilliseconds);
                return true;
            }
        });
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mWidthSize = MeasureSpec.getSize(widthMeasureSpec);
        setMeasuredDimension(mWidthSize, mWidthSize);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawCircle(mWidthSize / 2, mWidthSize / 2, mWidthSize / 2, mBigCirclePaint);//最外層的填充圓
        RectF rectF = new RectF(0, 0, mWidthSize, mWidthSize);//進(jìn)度扇形
        if (mCount.get() > 0) {
            //求出每一次定時器執(zhí)行所繪制的扇形度數(shù)
            float perAngle = 360f / mMaxSeconds / (1000f / mDelayMilliseconds);
            canvas.drawArc(rectF, 0, perAngle * mCount.get(), true, mAngleCirclePaint);
        }
        canvas.drawCircle(mWidthSize / 2, mWidthSize / 2, mWidthSize / 2 - mAnnulusWidth, mMiddenCirclePaint);//中間一層灰色的圓
        //最后繪制中心圓
        if (mIsFinish) {
            canvas.drawCircle(mWidthSize / 2, mWidthSize / 2, mWidthSize / 2 - mAnnulusWidth, mSmallCirclePaint);
        } else {
            canvas.drawCircle(mWidthSize / 2, mWidthSize / 2, mWidthSize / 8, mSmallCirclePaint);
        }
        super.onDraw(canvas);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            mEndTime = System.currentTimeMillis();
            new MyAsyncTask().execute();
        } else if (event.getAction() == MotionEvent.ACTION_DOWN) {
            mStartTime = System.currentTimeMillis();
        }
        return super.onTouchEvent(event);
    }
    public class MyAsyncTask extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... voids) {
            if (mTimer != null) {
                mTimer.cancel();
            }
            return null;
        }
        @Override
        protected void onPostExecute(Void aVoid) {
            //使用時間戳的差來判斷是單擊或者長按
            if (mEndTime - mStartTime > 1000) {
                //防止在結(jié)束后松開手指有重新調(diào)用了一次長按結(jié)束的回調(diào)
                if (!mIsFinish) {
                    if (mMyClickListener != null) {
                        mMyClickListener.longClickFinish();
                    }
                }
            } else {
                mCount.set(0);
                invalidate();
                if (mMyClickListener != null) {
                    mMyClickListener.singleClickFinish();
                }
            }
            mIsFinish = true;
        }
    }
}

使用的代碼如下:

activity_long_click_view.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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <com.example.customerview.long_click_view.LongClickView
        android:id="@+id/long_click_view"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        app:annulusColor="@color/color_2196F3"
        app:annulusWidth="20"
        app:delayMilliseconds="40"
        app:maxSeconds="4" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="長按錄制視頻,單擊拍照"
        android:textColor="@color/colorBlack"
        android:textSize="20dp" />
</LinearLayout>

LongClickViewActivity.java

        mLongClickView.setMyClickListener(new LongClickView.MyClickListener() {
            @Override
            public void longClickFinish() {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(LongClickViewActivity.this, "長按結(jié)束", Toast.LENGTH_SHORT).show();
                    }
                });
            }

            @Override
            public void singleClickFinish() {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(LongClickViewActivity.this, "單擊結(jié)束", Toast.LENGTH_SHORT).show();
                    }
                });
            }
        });

以上就是“Android如何自定義帶有圓形進(jìn)度條的可長按控件功能”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學(xué)習(xí)更多的知識,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI