Android 儀表盤控件UI分享(二)

一、SpeedView

 <com.github.anastr.speedviewlib.SpeedView
        android:id="@+id/speedView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        app:sv_withIndicatorLight="true"/>

  <Button
        android:id="@+id/b_open_control"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="control" />
 speedView = findViewById(R.id.speedView)
 ok = findViewById(R.id.ok)

 ok.setOnClickListener { 
    // 設(shè)置值
    speedView.speedTo(25f)
 }
 // 數(shù)值回調(diào)監(jiān)聽
 speedView.speedTextListener =  { speed: Float? -> String.format(Locale.getDefault(), "lol%.0f", speed) }

 speedView.clearSections()

// 設(shè)置外圓樣式,從0-0.1顏色為LTGRAY,寬度為30f,樣式默認(rèn)為BUTT,也可設(shè)置為Style.ROUND/Style.BUTT
// 源碼分析:
// class Section @JvmOverloads constructor(
//        startOffset: Float, 開始的偏移量
//        endOffset: Float,  結(jié)束的偏移量
//        color: Int,              顏色
//        width: Float = 0f,  寬度
//        style: Style = Style.BUTT,  樣式
//): Parcelable {
 speedView.addSections(
            Section(0f, .1f, Color.LTGRAY, speedView.dpTOpx(30f)),
            Section(.1f, .2f, Color.GRAY, speedView.dpTOpx(30f), Style.ROUND),
            Section(.2f, .3f, Color.DKGRAY, speedView.dpTOpx(30f)),
            Section(.3f, .4f, Color.BLACK, speedView.dpTOpx(30f)),
            Section(.4f, .5f, Color.CYAN, speedView.dpTOpx(30f), Style.ROUND),
            Section(.5f, .6f, Color.BLUE, speedView.dpTOpx(30f)),
            Section(.6f, .7f, Color.GREEN, speedView.dpTOpx(30f)),
            Section(.7f, .8f, Color.YELLOW, speedView.dpTOpx(30f)),
            Section(.8f, .9f, Color.MAGENTA, speedView.dpTOpx(30f))
         )

// Section的監(jiān)聽回調(diào)previousSection是指針滑動過的部分,newSection是被指定的部分
 speedView.onSectionChangeListener = { previousSection: Section?, newSection: Section? ->
           if (previousSection != null) {
               // previousSection.setPadding(10);
               previousSection.width = speedView.dpTOpx(3f)
            }
            if (newSection != null) {
                // newSection.setPadding(0);
                newSection.width = speedView.dpTOpx(15f)
            }
            Unit
        }

setSpeedAt:該函數(shù) setSpeedAt 用于立即設(shè)置速度值,不帶動畫效果,具體邏輯如下:
限制速度范圍:將傳入的 speed 限制在 maxSpeed 和 minSpeed 之間;
判斷加速方向:更新 isSpeedIncrease 表示當(dāng)前是否為加速狀態(tài);
更新速度值:同時更新 speed 和 currentSpeed;
取消動畫:調(diào)用 cancelSpeedAnimator() 停止可能存在的動畫;
刷新視圖并抖動:調(diào)用 invalidate() 刷新界面,tremble() 執(zhí)行抖動效果。

speedPercentTo:該函數(shù) speedPercentTo 的功能是將指定的百分比值轉(zhuǎn)換為實際速度值,并在給定的動畫時長內(nèi)平滑過渡到該速度。
參數(shù)說明:
percent:百分比值(0 到 100)。
moveDuration:動畫持續(xù)時間,默認(rèn)為 2000 毫秒。
功能邏輯:
調(diào)用 getSpeedValue(percent.toFloat()) 將百分比轉(zhuǎn)為實際速度值。
再調(diào)用 speedTo(...) 執(zhí)行帶動畫的速度變化。
注解作用:
@JvmOverloads 支持在 Java 中調(diào)用時使用默認(rèn)參數(shù)。

speedTo:該函數(shù) speedTo 用于平滑地將速度從當(dāng)前值動畫過渡到目標(biāo)速度,并確保速度始終在 [minSpeed, maxSpeed] 范圍內(nèi)。
具體邏輯如下:
限制速度范圍:若傳入的 speed 超出 [minSpeed, maxSpeed],則自動修正為邊界值。
判斷是否變化:如果新速度與當(dāng)前速度相同,則直接返回不執(zhí)行動畫。
設(shè)置動畫方向:記錄是加速還是減速(isSpeedIncrease)。
取消舊動畫:調(diào)用 cancelSpeedAnimator() 停止正在進行的速度動畫。
創(chuàng)建并啟動動畫:使用 ValueAnimator 實現(xiàn)平滑過渡,使用 DecelerateInterpolator 實現(xiàn)減速效果,并通過監(jiān)聽器更新當(dāng)前速度和刷新界面。

stop():該 stop() 函數(shù)用于停止速度表動畫,并根據(jù)條件觸發(fā)震動效果。具體邏輯如下:
如果 speedAnimator 和 realSpeedAnimator 都不在運行,直接返回;
將當(dāng)前速度保存到 speed;
取消速度動畫;
調(diào)用 tremble() 方法產(chǎn)生震動效果。

realSpeedTo :該函數(shù) realSpeedTo 用于模擬速度變化的真實感動畫,具體功能如下:
限制速度范圍:確保目標(biāo)速度不超過最大/最小值。
判斷加速或減速:根據(jù)當(dāng)前速度與目標(biāo)速度比較,決定是加速還是減速。
創(chuàng)建屬性動畫:使用 ValueAnimator 實現(xiàn)平滑過渡效果。
動態(tài)更新當(dāng)前速度:
加速時:按 accelerate 值緩慢增加;
減速時:按 decelerate 值快速減少;
刷新界面并結(jié)束動畫:當(dāng)速度達到目標(biāo)值時停止動畫并重繪視圖。

speedView.clearSections(): 該函數(shù)用于移除所有儀表盤中的“section”區(qū)域,并刷新視圖。具體邏輯如下:
遍歷 _sections 列表,調(diào)用每個元素的 clearGauge() 方法,清除對應(yīng)區(qū)域的儀表數(shù)據(jù);
清空 _sections 列表;
調(diào)用 invalidateGauge() 方法,觸發(fā)視圖重繪。

其他設(shè)置

設(shè)置最大值:
speedView.maxSpeed = 50f
設(shè)置儀表圓外邊框的寬度:
speedView.speedometerWidth = 5
設(shè)置數(shù)值文本的字體大?。?speedView.speedTextSize = 5f
設(shè)置指針顏色:
speedView.indicator.color = Color.parseColor("#000000")
設(shè)置中間圓點的顏色:
speedView.centerCircleColor = Color.parseColor("#000000")
設(shè)置區(qū)間樣式:
 private fun setLowSpeedColor() {
        val lowSpeedColor = findViewById<EditText>(R.id.lowSpeedColor)
        try {
            speedView.sections[0].startOffset  = 0f
            speedView.sections[0].endOffset = .1f
            speedView.sections[0].color = Color.parseColor(lowSpeedColor.text.toString())
        } catch (e: Exception) {
            lowSpeedColor.error = e.message
        }
    }

 private fun setMediumSpeedColor() {
        val mediumSpeedColor = findViewById<EditText>(R.id.mediumSpeedColor)
        try {
            speedView.sections[1].startOffset  = .1f
            speedView.sections[1].endOffset = 0.8f
            speedView.sections[1].color = Color.parseColor(mediumSpeedColor.text.toString())
        } catch (e: Exception) {
            mediumSpeedColor.error = e.message
        }
    }

private fun setHighSpeedColor() {
        val highSpeedColor = findViewById<EditText>(R.id.highSpeedColor)
        try {
            speedView.sections[2].startOffset  = .8f
            speedView.sections[2].endOffset = 1f
            speedView.sections[2].color = Color.parseColor(highSpeedColor.text.toString())
        } catch (e: Exception) {
            highSpeedColor.error = e.message
        }
    }

是否啟用抖動效果:
speedView.withTremble = true
是否啟用其他特效:
speedView.isWithEffects = true
設(shè)置刻度線密度(數(shù)量):
speedView.setDegreeBetweenMark(10)
設(shè)置刻度線寬度:
speedView.rayMarkWidth = 10f

二、Pointer Speedometer

 <com.github.anastr.speedviewlib.PointerSpeedometer
        android:id="@+id/pointerSpeedometer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        app:sv_unitTextSize="15sp"
        app:sv_indicatorLightColor="@android:color/white"
        app:sv_withIndicatorLight="true"
        app:sv_speedTextTypeface="fonts/good-times.ttf" />
// 監(jiān)聽回調(diào)
 pointerSpeedometer.onSpeedChangeListener =
            { gauge: Gauge, _: Boolean?, _: Boolean? ->
                textSpeedChange.text = String.format(
                    Locale.getDefault(), "onSpeedChange %d", gauge.currentIntSpeed
                )
            }

三、Tube Speedometer

<com.github.anastr.speedviewlib.TubeSpeedometer
        android:id="@+id/speedometer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        app:sv_speedTextSize="22sp"
        app:sv_speedTextTypeface="fonts/James-Almacen.ttf"/>

四、Image Speedometer

<com.github.anastr.speedviewlib.ImageSpeedometer
        android:id="@+id/imageSpeedometer"
        android:layout_width="250dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        app:sv_image="@drawable/for_image_speedometer"
        app:sv_indicator="LineIndicator"
        app:sv_indicatorColor="#a750bcff"
        app:sv_speedTextColor="#fff"
        app:sv_unitTextColor="#fff"/>

四、Progressive Gauge

  <com.github.anastr.speedviewlib.ProgressiveGauge
        android:id="@+id/gauge"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        app:sv_speedTextPosition="BOTTOM_RIGHT"
        app:sv_unitUnderSpeedText="false"
        app:sv_speedTextSize="25dp"
        app:sv_unitTextSize="18dp"
        app:sv_speedTextColor="#fff"
        app:sv_unitTextColor="#fff"
        app:sv_speedometerBackColor="#b3b3b3"
        app:sv_speedometerColor="#dc4ae1" />

五、Image Linear Gauge


 <com.github.anastr.speedviewlib.ImageLinearGauge
        android:id="@+id/gauge"
        android:layout_width="wrap_content"
        android:layout_height="300dp"
        android:layout_gravity="center_horizontal"
        app:sv_orientation="HORIZONTAL"
        app:sv_speedTextPosition="BOTTOM_CENTER"
        app:sv_unitUnderSpeedText="false"
        app:sv_speedometerBackColor="#9e9e9e"
        app:sv_image="@drawable/fire"/>
checkBoxOrientation.setOnCheckedChangeListener { _, b ->
      if (b) imageLinearGauge.orientation =
          LinearGauge.Orientation.VERTICAL else imageLinearGauge.orientation =
          LinearGauge.Orientation.HORIZONTAL
}

六、指針設(shè)置

 <com.github.anastr.speedviewlib.SpeedView
        android:id="@+id/speedometer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        app:sv_speedTextSize="11sp"
        app:sv_unitTextSize="8sp"
        app:sv_textSize="8sp"
        app:sv_startDegree="110"
        app:sv_endDegree="430"
        app:sv_speedometerWidth="45dp"
        app:sv_indicator="NormalIndicator"
        app:sv_indicatorWidth="20dp"
        app:sv_centerCircleColor="#0000"
        app:sv_indicatorColor="#df4346" />
設(shè)置指針樣式:
speedometer.setIndicator(Indicator.Indicators.NoIndicator)
設(shè)置指針寬度:
speedometer.indicator.width = 10f
設(shè)置自定義指針樣式:
val imageIndicator = ImageIndicator(applicationContext, ContextCompat.getDrawable(this, R.drawable.image_indicator1)!! )
speedometer.indicator = imageIndicator

七、刻度線設(shè)置

<com.github.anastr.speedviewlib.SpeedView
        android:id="@+id/speedometer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        app:sv_markColor="#414141"
        app:sv_markWidth="3dp"/>
設(shè)置刻度線樣式:
speedometer.markStyle = if(isChecked) Style.ROUND else Style.BUTT
設(shè)置刻度線數(shù)量:
speedometer.marksNumber = 10
設(shè)置刻度線高度:
speedometer.markHeight = 10f
設(shè)置刻度線寬度:
speedometer.markWidth = 10f

八、引導(dǎo)提示

 <com.github.anastr.speedviewlib.SpeedView
        android:id="@+id/speedView"
        android:layout_width="300dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:padding="20dp"
        app:sv_speedTextSize="23dp"
        app:sv_indicatorColor="#03A9F4"
        app:sv_centerCircleColor="#795548"/>
findViewById<View>(R.id.b_center).setOnClickListener { noteCenter() }
findViewById<View>(R.id.b_center_indicator).setOnClickListener { noteCenterIndicator() }
findViewById<View>(R.id.b_top_center).setOnClickListener { noteTopIndicator() }
findViewById<View>(R.id.b_image).setOnClickListener { noteImageNote() }
findViewById<View>(R.id.b_spannable).setOnClickListener { noteSpannableString() }

private fun noteCenter() {
        val type = Typeface.createFromAsset(assets, "fonts/lhandw.ttf")
        val note = TextNote(applicationContext, "Wait !")
            .setPosition(Note.Position.CenterSpeedometer)
            .setTextTypeFace(type)
            .setTextSize(speedView.dpTOpx(20f))
        speedView.addNote(note, 2000)
    }

private fun noteCenterIndicator() {
        val note = TextNote(applicationContext, "Stop !!")
            .setPosition(Note.Position.CenterIndicator)
            .setTextTypeFace(Typeface.create(Typeface.DEFAULT, Typeface.BOLD))
            .setTextSize(speedView.dpTOpx(13f))
        speedView.addNote(note, 2000)
    }

private fun noteTopIndicator() {
        val note = TextNote(applicationContext, "TOP")
            .setPosition(Note.Position.TopIndicator)
            .setAlign(Note.Align.Bottom)
            .setTextSize(speedView.dpTOpx(13f))
        speedView.addNote(note, 2000)
    }

private fun noteImageNote() {
        val imageNote = ImageNote(
            applicationContext, R.mipmap.ic_launcher
        )
            .setPosition(Note.Position.BottomIndicator)
        speedView.addNote(imageNote, 2000)
    }

private fun noteSpannableString() {
        val s = SpannableString("Speedometer")
        s.setSpan(RelativeSizeSpan(1.2f), 0, 11, 0)
        s.setSpan(RelativeSizeSpan(1.7f), 0, 1, 0)
        s.setSpan(ForegroundColorSpan(Color.parseColor("#64DD17")), 0, 1, 0)
        s.setSpan(ForegroundColorSpan(Color.parseColor("#FF1744")), 1, 5, 0)
        s.setSpan(ForegroundColorSpan(Color.parseColor("#AA00FF")), 5, 6, 0)
        s.setSpan(RelativeSizeSpan(1.4f), 5, 6, 0)
        s.setSpan(ForegroundColorSpan(Color.parseColor("#2196F3")), 6, 11, 0)
        val note = TextNote(applicationContext, s)
            .setBackgroundColor(Color.parseColor("#EEFF41"))
            .setPosition(Note.Position.QuarterSpeedometer)
            .setTextSize(speedView.dpTOpx(10f))
        speedView.addNote(note, 2000)
    }

九、刻度數(shù)值

<com.github.anastr.speedviewlib.SpeedView
        android:id="@+id/speedometer"
        android:layout_width="250dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        app:sv_tickNumber="6"/>
設(shè)置刻度數(shù)值是否跟隨指針旋轉(zhuǎn):
speedometer.isTickRotation = true
設(shè)置刻度數(shù)值顯示數(shù)量:
speedometer.tickNumber = 10
設(shè)置刻度數(shù)值位置:
speedometer.tickPadding = 10f

十、偏移量X,Y

 <com.github.anastr.speedviewlib.SpeedView
        android:id="@+id/speedometer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        app:sv_centerCircleRadius="2dp"
        app:sv_withTremble="false"
        app:sv_indicator="NeedleIndicator" />
//該函數(shù)用于設(shè)置指示器旋轉(zhuǎn)的支點位置,參數(shù) xOffset 和 yOffset 表示在 X 和 Y 軸上的比例位置(范圍為 [0f, 1f])
 speedometer.setFulcrum(fulcrumX, fulcrumY)
 speedometer.setFulcrum(.5f, .55f);

其他

設(shè)置圓邊框部分樣式(圓角還是平角):
app:sv_sectionStyle="ROUND"
設(shè)置圓邊框部分樣式顏色:
speedView.doOnSections { it.color = Color.rgb((0..255).random(), (0..255).random(), (0..255).random()) }

demo:


 <RelativeLayout
        android:layout_width="@dimen/dp_300"
        android:layout_height="@dimen/dp_300">

        <ImageView
            android:layout_width="@dimen/dp_300"
            android:layout_height="@dimen/dp_300"
            android:src="@mipmap/icon_speed_panel"/>

        <com.zn.core.panel.SpeedView
            android:id="@+id/svSpeed"
            app:sv_speedometerWidth="0dp"
            app:sv_centerCircleColor="#123456"
            app:sv_centerCircleRadius="@dimen/dp_25"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:sv_endDegree="380"
            app:sv_indicator="KiteIndicator"
            app:sv_indicatorColor="#eb1912"
            app:sv_indicatorWidth="@dimen/dp_5"
            app:sv_marksNumber="0"
            app:sv_maxSpeed="40"
            app:sv_minSpeed="0"
            app:sv_speedTextColor="@color/white"
            app:sv_speedTextFormat="INTEGER"
            app:sv_speedTextSize="@dimen/dp_20"
            app:sv_startDegree="160"
            app:sv_textColor="@color/white"
            app:sv_tickNumber="0"
            app:sv_unit="x100 r/min"
            app:sv_speedTextPadding="@dimen/dp_60"
            app:sv_unitTextColor="@color/white"
            app:sv_unitTextSize="@dimen/dp_20"
            app:sv_unitUnderSpeedText="true"
            app:sv_withTremble="false" />

    </RelativeLayout>
 <com.zn.core.panel.ImageSpeedometer
            android:id="@+id/svSpeed"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:sv_endDegree="380"
            app:sv_image="@mipmap/icon_speed_panel"
            app:sv_indicator="KiteIndicator"
            app:sv_indicatorColor="#eb1912"
            app:sv_indicatorWidth="@dimen/dp_5"
            app:sv_marksNumber="0"
            app:sv_maxSpeed="40"
            app:sv_minSpeed="0"
            app:sv_speedTextColor="@color/white"
            app:sv_speedTextFormat="INTEGER"
            app:sv_speedTextPosition="CENTER_BOTTOM"
            app:sv_speedTextSize="@dimen/dp_20"
            app:sv_startDegree="160"
            app:sv_textColor="@color/white"
            app:sv_tickNumber="0"
            app:sv_unit="x100 r/min"
            app:sv_unitTextColor="@color/white"
            app:sv_unitTextSize="@dimen/dp_20"
            app:sv_unitUnderSpeedText="false"
            app:sv_withTremble="false" />
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容