自定义带刻度线的SeekBar

在开发中遇到了一个需求就是实现带有刻度线的SeekBar,本文就简单记录一下自定义SeekBar的过程。下面是最终的两张效果图,一张是滑块上显示刻度线,一张是滑块上不显示刻度线:
这里写图片描述
这里写图片描述

思路就是继承系统的SeekBar,重写onDraw方法绘制刻度线。代码如下:

package cn.znh.customview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Build;
import android.support.v7.widget.AppCompatSeekBar;
import android.util.AttributeSet;

/**
 * @author:zhaonh
 * @time 2018/8/25 18:32
 * <p>
 * 类描述:自定义带刻度线的SeekBar
 */
public class RulerSeekBar extends AppCompatSeekBar {

    /**
     * 刻度线画笔
     */
    private Paint mRulerPaint;

    /**
     * 刻度线的个数,等分数等于刻度线的个数加1
     */
    private int mRulerCount = 4;

    /**
     * 每条刻度线的宽度
     */
    private int mRulerWidth = 2;

    /**
     * 刻度线的颜色
     */
    private int mRulerColor = Color.WHITE;

    /**
     * 滑块上面是否要显示刻度线
     */
    private boolean isShowTopOfThumb = false;

    public RulerSeekBar(Context context) {
        super(context);
        init();
    }

    public RulerSeekBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public RulerSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    /**
     * 初始化
     */
    private void init() {
        //创建绘制刻度线的画笔
        mRulerPaint = new Paint();
        mRulerPaint.setColor(mRulerColor);
        mRulerPaint.setAntiAlias(true);

        //Api21及以上调用,去掉滑块后面的背景
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            setSplitTrack(false);
        }
    }

    /**
     * 重写onDraw方法绘制刻度线
     *
     * @param canvas
     */
    @Override
    protected synchronized void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //极限条件校验
        if (getWidth() <= 0 || mRulerCount <= 0) {
            return;
        }

        //获取每一份的长度
        int length = (getWidth() - getPaddingLeft() - getPaddingRight() - mRulerCount * mRulerWidth) / (mRulerCount + 1);

        //计算刻度线的顶部坐标和底部坐标
        int rulerTop = getHeight() / 2 - getMinimumHeight() / 2;
        int rulerBottom = rulerTop + getMinimumHeight();

        //获取滑块的位置信息
        Rect thumbRect = null;
        if (getThumb() != null) {
            thumbRect = getThumb().getBounds();
        }

        //绘制刻度线
        for (int i = 1; i <= mRulerCount; i++) {
            //计算刻度线的左边坐标和右边坐标
            int rulerLeft = i * length + getPaddingLeft();
            int rulerRight = rulerLeft + mRulerWidth;

            //判断是否需要绘制刻度线
            if (!isShowTopOfThumb && thumbRect != null && rulerLeft - getPaddingLeft() > thumbRect.left && rulerRight - getPaddingLeft() < thumbRect.right) {
                continue;
            }

            //进行绘制
            canvas.drawRect(rulerLeft, rulerTop, rulerRight, rulerBottom, mRulerPaint);
        }
    }

    /**
     * 设置刻度线的个数
     *
     * @param mRulerCount
     */
    public void setRulerCount(int mRulerCount) {
        this.mRulerCount = mRulerCount;
        requestLayout();
    }

    /**
     * 设置刻度线的宽度,单位(px)
     *
     * @param mRulerWidth
     */
    public void setRulerWidth(int mRulerWidth) {
        this.mRulerWidth = mRulerWidth;
        requestLayout();
    }

    /**
     * 设置刻度线的颜色
     *
     * @param mRulerColor
     */
    public void setRulerColor(int mRulerColor) {
        this.mRulerColor = mRulerColor;
        if (mRulerPaint != null) {
            mRulerPaint.setColor(mRulerColor);
            requestLayout();
        }
    }

    /**
     * 滑块上面是否需要显示刻度线
     *
     * @param isShowTopOfThumb
     */
    public void setShowTopOfThumb(boolean isShowTopOfThumb) {
        this.isShowTopOfThumb = isShowTopOfThumb;
        requestLayout();
    }
}

注意:

  • 代码中的getHeight()是整个SeekBar的高度值,getMinimumHeight()是进度条的高度值
  • thumbRect里的滑块坐标信息都是去除padding后的

简单定义了几个属性:

  • mRulerCount:刻度线的个数,等分数等于刻度线的个数加1
  • mRulerWidth:每条刻度线的宽度
  • mRulerColor:刻度线的颜色
  • isShowTopOfThumb:滑块上面是否要显示刻度线

使用就跟系统的SeekBar一样使用就行:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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">

    <cn.znh.rulerseebar.RulerSeekBar
        android:id="@+id/seek_bar"
        style="@style/Widget.AppCompat.ProgressBar.Horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@null"
        android:maxHeight="16dp"
        android:minHeight="16dp"
        android:progress="50"
        android:progressDrawable="@drawable/shape_progress_drawable"
        android:thumb="@drawable/shape_thumb_icon"
        android:thumbOffset="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

Demo地址:https://github.com/huihuigithub/RulerSeekBar.git

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android中的SeekBar是一种常见的用户界面组件,它允许用户通过滑动来选择一个范围内的值。然而,默认情况下,SeekBar只显示一个可移动的滑块,没有刻度。 如果我们想要一个刻度SeekBar,我们需要进行一些自定义。其中一种方法是使用SeekBar的OnSeekBarChangeListener回调接口。我们可以编写一个自定义的OnSeekBarChangeListener,根据SeekBar的值来更新刻度。 首先,我们可以创建一个布局文件,包含一个SeekBar和一个用于显示刻度的TextView。然后,在代码中获取SeekBar和TextView的实例,并设置SeekBar的max值和初始值。 接下来,我们需要为SeekBar添加一个自定义的OnSeekBarChangeListener。在监听器的onProgressChanged方法中,我们可以获取SeekBar的当前值,并根据需要更新刻度。例如,我们可以将刻度的范围划分为10个等级,当SeekBar的值在某个等级范围内时,我们就更新TextView的显示内容为对应的刻度。 最后,我们将SeekBar和TextView添加到布局中,并显示在屏幕上。当用户滑动SeekBar时,刻度将会实时更新并显示在TextView上。 总结起来,要实现一个刻度SeekBar,我们需要进行自定义,通过实现SeekBar的OnSeekBarChangeListener接口来更新刻度,并将SeekBar和显示刻度的TextView添加到布局中。 这样,我们就可以在Android应用程序中使用刻度SeekBar,以更好地满足用户需求。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值