Android自定義控件之水平圓點(diǎn)加載進(jìn)度條
本文實(shí)例為大家分享了Android實(shí)現(xiàn)水平圓點(diǎn)加載進(jìn)度條的具體代碼,供大家參考,具體內(nèi)容如下
先來看看要實(shí)現(xiàn)的效果
實(shí)現(xiàn)思路非常簡(jiǎn)單:當(dāng)前變化的圓點(diǎn)先從最小半徑變大到最大最大半徑再變回最小半徑的圓,然后再切換到下個(gè)圓點(diǎn),同時(shí)顏色會(huì)先變淺在變會(huì)原來的顏色(可以理解為透明度變化),而且當(dāng)前圓點(diǎn)的上上一個(gè)圓點(diǎn)顏色會(huì)不斷變淺。大概就這樣(可能我實(shí)現(xiàn)的效果和圖片的有些出入)
先看下實(shí)現(xiàn)效果:
直接上代碼:
package com.kincai.testcustomview_pointprogress; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; import android.util.AttributeSet; import android.util.Log; import android.view.View; /** * Copyright (C) 2015 The KINCAI Open Source Project * . * Create By KINCAI * . * Time 2017-06-14 10:23 * . * Desc 水平圓點(diǎn)進(jìn)度條 */ public class DotPollingView extends View { private final String TAG = this.getClass().getSimpleName(); /** * 進(jìn)度當(dāng)前圓點(diǎn)畫筆和正常圓點(diǎn)畫筆 */ private Paint mSelectedPaint = new Paint(), mNormalPaint = new Paint(); /** * 正常圓點(diǎn)顏色 */ private int mColor; /** * 變大圓點(diǎn)的顏色 */ private int mSelectedColor; /** * 圓點(diǎn)總數(shù) */ private int mDotTotalCount = 3; /** * 正常圓點(diǎn)半徑 */ private int mDotRadius; /** * 當(dāng)前變化的圓點(diǎn)半徑變化量 0.0 - (mDotMaxRadius - mDotRadius)之間 */ private float mDotCurrentRadiusChange; /** * 圓點(diǎn)大小變化率 */ private float mRadiusChangeRate; /** * 最大圓點(diǎn)半徑 */ private int mDotMaxRadius; /** * 圓點(diǎn)最大間距 */ private int mDotSpacing; /** * 當(dāng)前變大的圓點(diǎn)索引 */ private int mCurrentDot = 0; private int mAlphaChange = 0; private int mAlphaChangeTotal = 220; private final int DOT_STATUS_BIG = 0X101; private final int DOT_STATUS_SMALL = 0X102; private int mDotChangeStatus = DOT_STATUS_BIG; public void setColor(int mColor) { this.mColor = mColor; mNormalPaint.setColor(mColor); } public void setSelectedColor(int mSelectedColor) { this.mSelectedColor = mSelectedColor; mSelectedPaint.setColor(mSelectedColor); } public void setDotTotalCount(int mDotTotalCount) { this.mDotTotalCount = mDotTotalCount; } public void setDotRadius(int mDotRadius) { this.mDotRadius = mDotRadius; } public void setRadiusChangeRate(float mRadiusChangeRate) { this.mRadiusChangeRate = mRadiusChangeRate; } public void setDotMaxRadius(int mDotMaxRadius) { this.mDotMaxRadius = mDotMaxRadius; } public void setDotSpacing(int mDotSpacing) { this.mDotSpacing = mDotSpacing; } public DotPollingView(Context context) { this(context, null); } public DotPollingView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public DotPollingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.DotPollingView, defStyleAttr, 0); initAttributes(typedArray); typedArray.recycle(); init(); } private void initAttributes(TypedArray Attributes) { mColor = Attributes.getColor(R.styleable.DotPollingView_dotP_dot_color, ContextCompat.getColor(getContext(),R.color.colorPrimary)); mSelectedColor = Attributes.getColor(R.styleable.DotPollingView_dotP_dot_selected_color, ContextCompat.getColor(getContext(),R.color.colorAccent)); mDotRadius = Attributes.getDimensionPixelSize(R.styleable.DotPollingView_dotP_dot_radius,DensityUtils.dp2px(getContext(),3)); mDotMaxRadius = Attributes.getDimensionPixelSize(R.styleable.DotPollingView_dotP_dot_max_radius,DensityUtils.dp2px(getContext(),5)); mDotSpacing = Attributes.getDimensionPixelSize(R.styleable.DotPollingView_dotP_dot_spacing,DensityUtils.dp2px(getContext(),6)); mDotTotalCount = Attributes.getInteger(R.styleable.DotPollingView_dotP_dot_count,3); mRadiusChangeRate = Attributes.getFloat(R.styleable.DotPollingView_dotP_dot_size_change_rate,0.3f); } /** * 初始化 */ private void init() { mDotCurrentRadiusChange = 0f; mSelectedPaint.setColor(mSelectedColor); mSelectedPaint.setAntiAlias(true); mSelectedPaint.setStyle(Paint.Style.FILL); mNormalPaint.setColor(mColor); mNormalPaint.setAntiAlias(true); mNormalPaint.setStyle(Paint.Style.FILL); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //測(cè)量寬高 int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int width; int height; if(widthMode == MeasureSpec.EXACTLY) { width = widthSize; Log.e(TAG, "onMeasure MeasureSpec.EXACTLY widthSize="+widthSize); } else { //指定最小寬度所有圓點(diǎn)加上間距的寬度, 以最小半徑加上間距算總和再加上最左邊和最右邊變大后的距離 width = (mDotTotalCount * mDotRadius * 2 + ((mDotTotalCount - 1) * mDotSpacing)) + (mDotMaxRadius - mDotRadius) * 2; Log.e(TAG, "onMeasure no MeasureSpec.EXACTLY widthSize="+widthSize+" width="+width); if(widthMode == MeasureSpec.AT_MOST) { width = Math.min(width, widthSize); Log.e(TAG, "onMeasure MeasureSpec.AT_MOST width="+width); } } if(heightMode == MeasureSpec.EXACTLY) { height = heightSize; Log.e(TAG, "onMeasure MeasureSpec.EXACTLY heightSize="+heightSize); } else { height = mDotMaxRadius * 2; Log.e(TAG, "onMeasure no MeasureSpec.EXACTLY heightSize="+heightSize+" height="+height); if(heightMode == MeasureSpec.AT_MOST) { height = Math.min(height, heightSize); Log.e(TAG, "onMeasure MeasureSpec.AT_MOST height="+height); } } setMeasuredDimension(width,height); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mNormalPaint.setAlpha(255); mSelectedPaint.setAlpha(255); if(mDotChangeStatus == DOT_STATUS_BIG) { mDotCurrentRadiusChange += mRadiusChangeRate; mAlphaChange +=12; } else { mDotCurrentRadiusChange -= mRadiusChangeRate; mAlphaChange -=12; } if(mAlphaChange >= mAlphaChangeTotal) { mAlphaChange = mAlphaChangeTotal; } Log.e("DotPollingView", "dot current radius change: " + mDotCurrentRadiusChange); //第一個(gè)圓點(diǎn)的圓心x坐標(biāo)計(jì)算:控件寬度的一半減去(所有圓點(diǎn)直徑的和以及所有間距的和相加的總和的一半)再加上一個(gè)半徑大小 // ,為什么要加上半徑?因?yàn)槲覀兤瘘c(diǎn)要的是圓心,但算出來的是最左邊x坐標(biāo) int startPointX = getWidth() / 2 - (mDotTotalCount * mDotRadius * 2 + ((mDotTotalCount - 1) * mDotSpacing)) / 2 + mDotRadius; //所有圓點(diǎn)的圓心y坐標(biāo)一致控件高度的一半 int startPointY = getHeight() / 2; for (int i = 0; i < mDotTotalCount; i++) { if(mCurrentDot == i) {//當(dāng)前圓點(diǎn) mSelectedPaint.setAlpha(255 - mAlphaChange); canvas.drawCircle(startPointX + mCurrentDot * (mDotRadius * 2 + mDotSpacing), startPointY , mDotRadius + mDotCurrentRadiusChange, mSelectedPaint); continue; } else if(mCurrentDot > 1 && mCurrentDot - 2 == i) {//當(dāng)前圓點(diǎn)前兩個(gè) mNormalPaint.setAlpha(255 - mAlphaChange); canvas.drawCircle(startPointX + (mCurrentDot - 2) * (mDotRadius * 2 + mDotSpacing), startPointY, mDotRadius, mNormalPaint); continue; } //畫正常的圓點(diǎn) mNormalPaint.setAlpha(255); canvas.drawCircle(startPointX + i * (mDotRadius * 2 + mDotSpacing), startPointY, mDotRadius, mNormalPaint); } //當(dāng)圓點(diǎn)變化率達(dá)到最大或超過最大半徑和正常半徑之差時(shí) 變化率重置0,當(dāng)前變大圓點(diǎn)移至下一圓點(diǎn) if (mDotCurrentRadiusChange >= (mDotMaxRadius - mDotRadius) && mDotChangeStatus == DOT_STATUS_BIG) { mDotCurrentRadiusChange = mDotMaxRadius - mDotRadius; mDotChangeStatus = DOT_STATUS_SMALL; } else if(mDotCurrentRadiusChange <= 0 && mDotChangeStatus == DOT_STATUS_SMALL) { mDotChangeStatus = DOT_STATUS_BIG; mDotCurrentRadiusChange = 0f; mCurrentDot = mCurrentDot == mDotTotalCount - 1 ? 0 : mCurrentDot + 1; mAlphaChange = 0; } invalidate(); } }
源碼下載github:TestCustomView_PointProgress
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android自定義控件實(shí)現(xiàn)通用驗(yàn)證碼輸入框(二)
- Android自定義控件實(shí)現(xiàn)通用驗(yàn)證碼輸入框
- Android自定義控件橫向柱狀統(tǒng)計(jì)圖
- Android自定義控件之圓形進(jìn)度條動(dòng)畫
- Android自定義控件之刻度尺控件
- Android Studio 創(chuàng)建自定義控件的方法
- Android開發(fā)自定義控件之折線圖實(shí)現(xiàn)方法詳解
- Android自定義控件實(shí)現(xiàn)時(shí)鐘效果
- Android自定義控件仿ios下拉回彈效果
- Android運(yùn)動(dòng)健康睡眠自定義控件的實(shí)現(xiàn)
相關(guān)文章
Android開發(fā)實(shí)現(xiàn)仿QQ消息SwipeMenuListView滑動(dòng)刪除置頂功能【附源碼下載】
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)仿QQ消息SwipeMenuListView滑動(dòng)刪除置頂功能,結(jié)合實(shí)例形式分析了Android swipemenulistview相關(guān)組件的使用技巧,并附帶demo源碼供讀者下載參考,需要的朋友可以參考下2017-12-12Flutter上線項(xiàng)目實(shí)戰(zhàn)記錄之路由篇
這篇文章主要給大家介紹了關(guān)于Flutter上線項(xiàng)目實(shí)戰(zhàn)記錄之路由篇的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Flutter具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09Android動(dòng)畫之漸變動(dòng)畫(Tween Animation)詳解 (漸變、縮放、位移、旋轉(zhuǎn))
這篇文章主要介紹了Android動(dòng)畫之漸變動(dòng)畫(Tween Animation)用法,結(jié)合實(shí)例形式詳細(xì)分析了Android漸變動(dòng)畫Tween Animation實(shí)現(xiàn)漸變,縮放,位移,旋轉(zhuǎn)等技巧,需要的朋友可以參考下2016-01-01android 大圖片拖拽并縮放實(shí)現(xiàn)原理
android 大圖片拖拽縮放有利于用戶體驗(yàn),在開發(fā)過程中經(jīng)常使用到,這篇圖片拖拽縮放也是我在項(xiàng)目中用到的,今天整理一下,將源碼奉獻(xiàn)給大家,希望對(duì)大家以后碰到相似的問題有幫助2013-01-01Android8.1原生系統(tǒng)網(wǎng)絡(luò)感嘆號(hào)消除的方法
這篇文章主要介紹了Android8.1原生系統(tǒng)網(wǎng)絡(luò)感嘆號(hào)消除的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-05-05Android利用Intent啟動(dòng)和關(guān)閉Activity
這篇文章主要為大家詳細(xì)介紹了Android利用Intent啟動(dòng)和關(guān)閉Activity的相關(guān)操作,感興趣的小伙伴們可以參考一下2016-06-06android實(shí)現(xiàn)掃描網(wǎng)頁二維碼進(jìn)行網(wǎng)頁登錄功能
這篇文章主要介紹了android掃描網(wǎng)頁二維碼進(jìn)行網(wǎng)頁登錄效果,掃描成功之后跳轉(zhuǎn)進(jìn)入主頁,具體實(shí)現(xiàn)代碼大家參考下本文2017-12-12