Android實(shí)現(xiàn)指針刻度轉(zhuǎn)盤
本文實(shí)例為大家分享了Android實(shí)現(xiàn)指針刻度轉(zhuǎn)盤的具體代碼,供大家參考,具體內(nèi)容如下
一. 先上個(gè)效果圖,實(shí)現(xiàn)如圖所示刻度轉(zhuǎn)盤和2個(gè)文本的繪制,最后1個(gè)刻度繪制的比較長一些(后期會(huì)添加動(dòng)畫效果,未完待續(xù)…):
二. 話不多說,上代碼,Timber可使用Log代替,也可根據(jù)自身需求將配置屬性放到attrs.xml中去:
package com.landleaf.householdtype.widget; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.util.Log; import android.view.View; import androidx.annotation.Nullable; import timber.log.Timber; public class PanelTempCircle extends View { private static final String TAG = PanelTempCircle.class.getSimpleName(); //#EFEFEF //#47C496 private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); //畫筆寬度,線段長度,最后一條大線條的長度 比其他線段長的長度 private int strokeWidth = 7, lineLength = 40, maxLineLength = 10; //繪制文本距離圓 private int txtMargin = 10; //中心點(diǎn)坐標(biāo) private int centerX, centerY; //內(nèi)圓半徑,外圓半徑 private int innerRadius, outRadius; //繪制文本 private String leftText = "0", rightText = "30"; //繪制文本的字體大小 private int textSize = 25; //背景 or 進(jìn)度條顏色 private int colorBackground = Color.parseColor("#EFEFEF"); private int colorProgress = Color.parseColor("#18C8C7"); private int colorText = Color.parseColor("#999999"); float fullAngle = 180f; float cutAngle = 90f; //每個(gè)線段相隔的寬度 private static final int perAngle = 6; private int startAngle = -12; public PanelTempCircle(Context context) { super(context); initPaint(context, null); } public PanelTempCircle(Context context, @Nullable AttributeSet attrs) { super(context, attrs); initPaint(context, attrs); } private void initPaint(Context context, AttributeSet attrs) { paint.setStrokeCap(Paint.Cap.ROUND); paint.setTextSize(textSize); paint.setStrokeWidth(strokeWidth); paint.setTextAlign(Paint.Align.CENTER); paint.setColor(colorBackground); } public PanelTempCircle(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initPaint(context, attrs); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); drawCircle(startAngle, 60, canvas, paint); } private void drawCircle(float startAngle, float endAngle, Canvas canvas, Paint paint) { for (float i = startAngle; i <= fullAngle - startAngle; i = i + perAngle) { //-12.-6,0,6....180,186,192 //得出坐標(biāo) int startM, startN, endM, endN, startX, startY, endX, endY; int startPaintRadius = innerRadius; int endPaintRadius = outRadius; float currentAngle = i; if (i <= 0) { currentAngle = Math.abs(i); } else if (currentAngle > fullAngle) { currentAngle = i - fullAngle; } //當(dāng)前進(jìn)度=結(jié)束進(jìn)度 if (i == endAngle) { startPaintRadius = innerRadius - maxLineLength; endPaintRadius = outRadius + maxLineLength; } //起始點(diǎn) double angleSin = Math.sin(Math.PI * (Math.abs(currentAngle) / fullAngle)); //起始點(diǎn) 高度 寬度 startM = (int) (angleSin * startPaintRadius); startN = (int) Math.sqrt(Math.pow(startPaintRadius, 2) - Math.pow(startM, 2)); //結(jié)束點(diǎn) 高度 寬度 endM = (int) (angleSin * endPaintRadius); endN = (int) Math.sqrt(Math.pow(endPaintRadius, 2) - Math.pow(endM, 2)); // Log.i(TAG, startM + "," + startN + "," + endM + "," + endN); //獲得起始點(diǎn)和結(jié)束點(diǎn)的坐標(biāo) if (i < 0) { //第三象限 startX = centerX - startN; endX = centerX - endN; startY = centerY + startM; endY = centerY + endM; } else if (i > fullAngle) { //第二象限 startX = centerX + startN; endX = centerX + endN; startY = centerY + startM; endY = centerY + endM; } else { if (i < cutAngle) { //第四象限 startX = centerX - startN; endX = centerX - endN; startY = centerY - startM; endY = centerY - endM; } else { //第一象限 startX = centerX + startN; endX = centerX + endN; startY = centerY - startM; endY = centerY - endM; } } //設(shè)置線條繪制顏色 if (i <= endAngle) { paint.setColor(colorProgress); } else { paint.setColor(colorBackground); } canvas.drawLine(startX, startY, endX, endY, paint); //判斷是否需要繪制文本 if (i == startAngle) { int textWidth = getTextWidth(paint, leftText); paint.setColor(colorText); canvas.drawText(leftText, startX + textWidth + txtMargin, startY, paint); Timber.tag(TAG).i("繪制左側(cè)文本:" + (startX + textWidth + txtMargin) + "," + startY); } if (i == fullAngle - startAngle) { int textWidth = getTextWidth(paint, rightText); paint.setColor(colorText); canvas.drawText(rightText, startX - textWidth - txtMargin, startY, paint); Timber.tag(TAG).i("繪制右側(cè)文本:" + (startX - textWidth - txtMargin) + "," + startY); } } } public int getTextWidth(Paint paint, String str) { int iRet = 0; if (str != null && str.length() > 0) { int len = str.length(); float[] widths = new float[len]; paint.getTextWidths(str, widths); for (int j = 0; j < len; j++) { iRet += (int) Math.ceil(widths[j]); } } return iRet; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); innerRadius = (getMeasuredWidth() - lineLength * 2 - maxLineLength * 2) / 2; outRadius = lineLength + innerRadius; Timber.tag(TAG).i("內(nèi)圈半徑:" + innerRadius + ",外圈半徑:" + outRadius); centerX = outRadius + maxLineLength; centerY = outRadius + maxLineLength; Timber.tag(TAG).i("中心坐標(biāo):(x=" + centerX + ",y=" + centerY + ")"); int heightMode = MeasureSpec.getMode(heightMeasureSpec); if (heightMode == MeasureSpec.AT_MOST) { double angleSin = Math.sin(Math.PI * (Math.abs(startAngle) / fullAngle)); int endPaintRadius = outRadius + maxLineLength; int height = (int) (endPaintRadius + angleSin * endPaintRadius); setMeasuredDimension(widthMeasureSpec, height); } } }
三. xml中使用方式:
說明:主要申明寬度即可,高度會(huì)在代碼中進(jìn)行計(jì)算;
<com.landleaf.householdtype.widget.PanelTempCircle android:id="@+id/mptc_set_temp" android:layout_width="270dp" android:layout_height="wrap_content" app:layout_constraintBottom_toTopOf="@+id/tvHumidity" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.3" />
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android中實(shí)現(xiàn)多行、水平滾動(dòng)的分頁的Gridview實(shí)例源碼
如果單行水平滾動(dòng),可以用Horizontalscrollview實(shí)現(xiàn)。如果是多行水平滾動(dòng),則結(jié)合Gridview(一般是垂直滾動(dòng)的)和Horizontalscrollview實(shí)現(xiàn)2013-06-06Android自定義View的實(shí)現(xiàn)方法實(shí)例詳解
本文通過實(shí)例代碼給大家詳細(xì)介紹了Android自定義View的實(shí)現(xiàn)方法,需要的朋友可以參考下2017-09-09Android開發(fā)實(shí)現(xiàn)的圖片點(diǎn)擊切換功能示例
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)的圖片點(diǎn)擊切換功能,涉及Android ImageView組件創(chuàng)建、布局及實(shí)現(xiàn)圖形切換相關(guān)操作技巧,需要的朋友可以參考下2019-04-04Android7.0實(shí)現(xiàn)拍照和相冊選取圖片功能
這篇文章主要為大家詳細(xì)介紹了Android7.0實(shí)現(xiàn)拍照和相冊選取圖片功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07Android開發(fā)之使用ExifInterface獲取拍照后的圖片屬性
這篇文章主要介紹了Android開發(fā)之使用ExifInterface獲取拍照后的圖片屬性,較為詳細(xì)的分析了ExifInterface類操作圖片的具體使用技巧,需要的朋友可以參考下2016-01-01Android應(yīng)用開發(fā)之簡易、大氣音樂播放器實(shí)現(xiàn)專輯倒影效果
這篇文章主要介紹了Android應(yīng)用開發(fā)之簡單、大氣音樂播放器實(shí)現(xiàn)專輯倒影效果,對android音樂播放器感興趣的朋友可以參考下2015-10-10Flutter 狀態(tài)管理scoped model源碼解讀
這篇文章主要為大家介紹了Flutter 狀態(tài)管理scoped model源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11android自定義控件實(shí)現(xiàn)簡易時(shí)間軸(2)
這篇文章主要為大家詳細(xì)介紹了android自定義控件實(shí)現(xiàn)簡易時(shí)間軸的第二篇,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01Android游戲開發(fā):實(shí)現(xiàn)手勢操作切換圖片的實(shí)例
本文主要介紹 Android游戲開發(fā)實(shí)現(xiàn)手勢操作切換圖片的實(shí)例,這里整理了詳細(xì)的資料和示例代碼,有開發(fā)Android游戲應(yīng)用的小伙伴可以參考下2016-08-08