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 { 
    // 设置值
    speedView.speedTo(25f)
 }
 // 数值回调监听
 speedView.speedTextListener =  { speed: Float? -> String.format(Locale.getDefault(), "lol%.0f", speed) }

 speedView.clearSections()

// 设置外圆样式,从0-0.1颜色为LTGRAY,宽度为30f,样式默认为BUTT,也可设置为Style.ROUND/Style.BUTT
// 源码分析:
// class Section @JvmOverloads constructor(
//        startOffset: Float, 开始的偏移量
//        endOffset: Float,  结束的偏移量
//        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的监听回调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:该函数 setSpeedAt 用于立即设置速度值,不带动画效果,具体逻辑如下:
限制速度范围:将传入的 speed 限制在 maxSpeed 和 minSpeed 之间;
判断加速方向:更新 isSpeedIncrease 表示当前是否为加速状态;
更新速度值:同时更新 speed 和 currentSpeed;
取消动画:调用 cancelSpeedAnimator() 停止可能存在的动画;
刷新视图并抖动:调用 invalidate() 刷新界面,tremble() 执行抖动效果。

speedPercentTo:该函数 speedPercentTo 的功能是将指定的百分比值转换为实际速度值,并在给定的动画时长内平滑过渡到该速度。
参数说明:
percent:百分比值(0 到 100)。
moveDuration:动画持续时间,默认为 2000 毫秒。
功能逻辑:
调用 getSpeedValue(percent.toFloat()) 将百分比转为实际速度值。
再调用 speedTo(...) 执行带动画的速度变化。
注解作用:
@JvmOverloads 支持在 Java 中调用时使用默认参数。

speedTo:该函数 speedTo 用于平滑地将速度从当前值动画过渡到目标速度,并确保速度始终在 [minSpeed, maxSpeed] 范围内。
具体逻辑如下:
限制速度范围:若传入的 speed 超出 [minSpeed, maxSpeed],则自动修正为边界值。
判断是否变化:如果新速度与当前速度相同,则直接返回不执行动画。
设置动画方向:记录是加速还是减速(isSpeedIncrease)。
取消旧动画:调用 cancelSpeedAnimator() 停止正在进行的速度动画。
创建并启动动画:使用 ValueAnimator 实现平滑过渡,使用 DecelerateInterpolator 实现减速效果,并通过监听器更新当前速度和刷新界面。

stop():该 stop() 函数用于停止速度表动画,并根据条件触发震动效果。具体逻辑如下:
如果 speedAnimator 和 realSpeedAnimator 都不在运行,直接返回;
将当前速度保存到 speed;
取消速度动画;
调用 tremble() 方法产生震动效果。

realSpeedTo :该函数 realSpeedTo 用于模拟速度变化的真实感动画,具体功能如下:
限制速度范围:确保目标速度不超过最大/最小值。
判断加速或减速:根据当前速度与目标速度比较,决定是加速还是减速。
创建属性动画:使用 ValueAnimator 实现平滑过渡效果。
动态更新当前速度:
加速时:按 accelerate 值缓慢增加;
减速时:按 decelerate 值快速减少;
刷新界面并结束动画:当速度达到目标值时停止动画并重绘视图。

speedView.clearSections(): 该函数用于移除所有仪表盘中的“section”区域,并刷新视图。具体逻辑如下:
遍历 _sections 列表,调用每个元素的 clearGauge() 方法,清除对应区域的仪表数据;
清空 _sections 列表;
调用 invalidateGauge() 方法,触发视图重绘。

其他设置

设置最大值:
speedView.maxSpeed = 50f
设置仪表圆外边框的宽度:
speedView.speedometerWidth = 5
设置数值文本的字体大小:
speedView.speedTextSize = 5f
设置指针颜色:
speedView.indicator.color = Color.parseColor("#000000")
设置中间圆点的颜色:
speedView.centerCircleColor = Color.parseColor("#000000")
设置区间样式:
 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
设置刻度线密度(数量):
speedView.setDegreeBetweenMark(10)
设置刻度线宽度:
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" />
// 监听回调
 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
}

六、指针设置

 <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" />
设置指针样式:
speedometer.setIndicator(Indicator.Indicators.NoIndicator)
设置指针宽度:
speedometer.indicator.width = 10f
设置自定义指针样式:
val imageIndicator = ImageIndicator(applicationContext, ContextCompat.getDrawable(this, R.drawable.image_indicator1)!! )
speedometer.indicator = imageIndicator

七、刻度线设置

<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"/>
设置刻度线样式:
speedometer.markStyle = if(isChecked) Style.ROUND else Style.BUTT
设置刻度线数量:
speedometer.marksNumber = 10
设置刻度线高度:
speedometer.markHeight = 10f
设置刻度线宽度:
speedometer.markWidth = 10f

八、引导提示

 <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)
    }

九、刻度数值

<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"/>
设置刻度数值是否跟随指针旋转:
speedometer.isTickRotation = true
设置刻度数值显示数量:
speedometer.tickNumber = 10
设置刻度数值位置:
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" />
//该函数用于设置指示器旋转的支点位置,参数 xOffset 和 yOffset 表示在 X 和 Y 轴上的比例位置(范围为 [0f, 1f])
 speedometer.setFulcrum(fulcrumX, fulcrumY)
 speedometer.setFulcrum(.5f, .55f);

其他

设置圆边框部分样式(圆角还是平角):
app:sv_sectionStyle="ROUND"
设置圆边框部分样式颜色:
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" />
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容