詳解Android如何自定義view實(shí)現(xiàn)圓形進(jìn)度條
Android中實(shí)現(xiàn)進(jìn)度條有很多種方式,自定義進(jìn)度條一般是繼承progressBar或繼承view來(lái)實(shí)現(xiàn),本篇中講解的是第二種方式。
先上效果圖:
實(shí)現(xiàn)圓形進(jìn)度條總體來(lái)說(shuō)并不難,還是跟往常一樣繼承view,初始化畫(huà)筆,按下面的步驟一步步來(lái)就好了。對(duì)初學(xué)者來(lái)說(shuō)動(dòng)畫(huà)效果可能比較陌生,我們可以使用屬性動(dòng)畫(huà)中的valueAnimator來(lái)實(shí)現(xiàn)動(dòng)畫(huà)效果。
實(shí)現(xiàn)步驟:
1、畫(huà)出一個(gè)灰色的圓環(huán)作為背景。
2、畫(huà)出上層的圓環(huán)覆蓋下方的圓環(huán)。
3、加入動(dòng)畫(huà)效果
值得注意的是怎么設(shè)置圓環(huán)和文字的位置。
畫(huà)出矩形只需要傳入矩形對(duì)角線的坐標(biāo)即可,如果不加以處理的話畫(huà)出來(lái)的圓環(huán)的邊緣是不完整的,剛開(kāi)始接觸自定義view的同學(xué)們一定要先好好看看Android坐標(biāo)系相關(guān)內(nèi)容,不然很難理解位置參數(shù)為什么這樣設(shè)置。
完整代碼:
package com.example.floatingwindow.widget; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; import android.view.animation.DecelerateInterpolator; import androidx.annotation.Nullable; import com.example.floatingwindow.R; public class ProgressBarView extends View { private Paint mPaintBack; private Paint mPaint; private Paint mPaintText; private float process; private int strokeWidth = 15; private int textSize = 20; private long duration = 3000; private float startDegree = 0; private float endDegree = 360; private String text = "完成"; private String defaultText = "0%"; public ProgressBarView(Context context) { super(context); init(); } public ProgressBarView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } public ProgressBarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mPaintBack = new Paint(); mPaintBack.setColor(getResources().getColor(R.color.gray)); mPaintBack.setStyle(Paint.Style.STROKE); mPaintBack.setAntiAlias(true); mPaintBack.setStrokeCap(Paint.Cap.ROUND); mPaintBack.setStrokeWidth(strokeWidth); mPaint = new Paint(); mPaint.setColor(getResources().getColor(R.color.purple_200)); mPaint.setStyle(Paint.Style.STROKE); mPaint.setAntiAlias(true); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(strokeWidth); mPaintText = new Paint(); mPaintText.setAntiAlias(true); mPaintText.setStyle(Paint.Style.STROKE); mPaintText.setColor(Color.BLACK); mPaintBack.setStrokeCap(Paint.Cap.ROUND); mPaintText.setTextSize(sp2px(textSize)); } public void setStrokeWidth(int width) { strokeWidth = width; } public void setTextSize(int textSize) { this.textSize = textSize; } public void setDuration(long duration) { this.duration = duration; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //創(chuàng)建圓環(huán)矩形 RectF rectF = new RectF(strokeWidth, strokeWidth, getWidth() - strokeWidth, getHeight() - strokeWidth); //畫(huà)出灰色進(jìn)度條作為背景 canvas.drawArc(rectF, 0, 360, false, mPaintBack); //畫(huà)進(jìn)度條 canvas.drawArc(rectF, 0, process, false, mPaint); //計(jì)算進(jìn)度 int percent = (int) (process / 360 * 100); //設(shè)置文字在canvas中的位置 Paint.FontMetrics fm = mPaintText.getFontMetrics(); int mTxtWidth = (int) mPaintText.measureText(text, 0, defaultText.length()); int mTxtHeight = (int) Math.ceil(fm.descent - fm.ascent); int x = getWidth() / 2 - mTxtWidth / 2; int y = getHeight() / 2 + mTxtHeight / 4; if (percent < 100) { canvas.drawText(percent + "%", x, y, mPaintText); } else { canvas.drawText(text, x, y, mPaintText); } } /** * 設(shè)置動(dòng)畫(huà)效果 */ public void start() { ValueAnimator valueAnimator = ValueAnimator.ofFloat(startDegree, endDegree); valueAnimator.setDuration(duration); valueAnimator.setInterpolator(new DecelerateInterpolator()); valueAnimator.addUpdateListener(animation -> { process = (float) animation.getAnimatedValue(); invalidate(); }); valueAnimator.start(); } private int sp2px(int sp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics()); } }
最后就是動(dòng)畫(huà)效果了,使用valueanimator,傳入開(kāi)始和結(jié)束的進(jìn)度以及執(zhí)行時(shí)間。然后每次進(jìn)度發(fā)生變化時(shí)做UI刷新。
xml布局:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <com.example.floatingwindow.widget.ProgressBarView android:id="@+id/progressBar" android:layout_width="150dp" android:layout_height="150dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"> </com.example.floatingwindow.widget.ProgressBarView> </androidx.constraintlayout.widget.ConstraintLayout>
MainActivity:
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) progressBar.start() progressBar.setOnClickListener { progressBar.start()} }
以上就是詳解Android如何自定義view實(shí)現(xiàn)圓形進(jìn)度條的詳細(xì)內(nèi)容,更多關(guān)于Android圓形進(jìn)度條的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
linphone-sdk-android版本號(hào)生成解析
這篇文章主要為大家介紹了linphone-sdk-android版本號(hào)生成解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09Android畫(huà)中畫(huà)窗口開(kāi)啟方法
Android8.0 Oreo(API Level26)允許活動(dòng)啟動(dòng)畫(huà)中畫(huà)Picture-in-picture(PIP)模式。PIP是一種特殊類型的多窗口模式,主要用于視頻播放。PIP模式已經(jīng)可用于Android TV,而Android8.0則讓該功能可進(jìn)一步用于其他Android設(shè)備2023-01-01Android自定義View展開(kāi)菜單功能的實(shí)現(xiàn)
這篇文章主要介紹了Android自定義View展開(kāi)菜單功能的實(shí)現(xiàn),需要的朋友可以參考下2017-06-06Android 自定義LayoutManager實(shí)現(xiàn)花式表格
這篇文章主要介紹了Android 自定義LayoutManager實(shí)現(xiàn)花式表格,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02Android手機(jī)衛(wèi)士之確認(rèn)密碼對(duì)話框
這篇文章主要為大家詳細(xì)介紹了Android手機(jī)衛(wèi)士之確認(rèn)密碼對(duì)話框,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10Android開(kāi)發(fā)技巧之Fragment的懶加載
我們都知道fragment放在viewPager里面,viewpager會(huì)幫我們預(yù)先加載一個(gè),但是當(dāng)我們要看fragment里面的內(nèi)容時(shí),我們也許只會(huì)去看第一個(gè),不會(huì)去看第二個(gè),如果這時(shí)候不去實(shí)現(xiàn)fragment的懶加載的話,就會(huì)多余的去加載一些數(shù)據(jù),造成用戶多消耗流量。下面來(lái)一起看看吧。2016-10-10