Android自定义SeekBar控件实现

一、控件介绍

  SeekBar控件是Android原生组件之一,用于选择连续的数据或者块数据。一般情况下,SeekBar控件都是用来实现调节音量大小、颜色、亮度等操作。但是,在实际开发中,我们会发现自带的SeekBar样式不够美观、不够适用。因此,本文将介绍如何自定义SeekBar控件,实现控件的样式和功能更加多样化。

二、自定义SeekBar的基本步骤

  自定义SeekBar的基本步骤如下:

  1、继承SeekBar,重写构造函数、绘制方法、触摸事件等方法;

  2、定义SeekBar需要用到的属性;

  3、在布局文件中引入自定义的SeekBar。

三、自定义SeekBar的具体实现

1. 自定义SeekBar属性的定义

  首先,我们需要定义需要用到的SeekBar属性。

<declare-styleable name="MySeekBar">    <attr name="thumb" format="reference" />    <attr name="progressColor" format="color" />    <attr name="progressBackground" format="color" />    <attr name="seekBarHeight" format="dimension" /></declare-styleable>

  其中,thumb属性用于设置SeekBar的把手图像,progressColor属性用于设置SeekBar填充区域的颜色,progressBackground属性用于设置SeekBar未填充区域的颜色,seekBarHeight属性用于设置SeekBar的高度。

2. 自定义SeekBar的绘制过程

  接下来,我们需要重写SeekBar的onMeasure()onDraw()onTouchEvent()方法。

2.1 onMeasure方法:测量SeekBar的大小

@Overrideprotected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    int height = MeasureSpec.getSize(heightMeasureSpec);    int width = MeasureSpec.getSize(widthMeasureSpec);    setMeasuredDimension(width, height);}

  通过重写onMeasure()方法,我们可以测量SeekBar的大小,并将其设置为期望的大小。

2.2 onDraw方法:绘制SeekBar的基本属性

@Overrideprotected synchronized void onDraw(Canvas canvas) {    super.onDraw(canvas);    int width = getWidth();    int height = getHeight();    float thumbX = getThumbPosX();    // 绘制背景    RectF rectBackground = new RectF(0, height / 2 - seekBarHeight / 2, width, height / 2 + seekBarHeight / 2);    paint.setColor(progressBackground);    canvas.drawRoundRect(rectBackground, height / 2, height / 2, paint);    // 绘制填充区域    float progressEnd = thumbX + getPaddingLeft();    RectF rectProgress = new RectF(0, height / 2 - seekBarHeight / 2, progressEnd, height / 2 + seekBarHeight / 2);    paint.setColor(progressColor);    canvas.drawRoundRect(rectProgress, height / 2, height / 2, paint);    // 绘制把手图像    canvas.drawBitmap(thumbBitmap, thumbX, height / 2 - thumbBitmap.getHeight() / 2, paint);}

  onDraw()方法是SeekBar的绘制核心方法,我们可以在该方法中实现SeekBar的基本绘制,包括背景、填充区域和把手图像等内容。

2.3 onTouchEvent方法:监听SeekBar的触摸事件

@Overridepublic boolean onTouchEvent(MotionEvent event) {    if (!isEnabled()) {        return false;    }    switch (event.getAction()) {        case MotionEvent.ACTION_DOWN:            touchDownX = event.getX();            break;        case MotionEvent.ACTION_MOVE:            float touchMoveX = event.getX();            float touchDelta = touchMoveX - touchDownX;            touchDownX = touchMoveX;            int thumbPosX = (int) (getThumbPosX() + touchDelta);            int maxRange = getWidth() - getPaddingLeft() - getPaddingRight();            int seekBarWidth = thumbBitmap.getWidth();            thumbPosX = Math.max(thumbPosX, 0);            thumbPosX = Math.min(thumbPosX, maxRange);            setProgress(thumbPosX * getMax() / (maxRange - seekBarWidth));            break;        case MotionEvent.ACTION_UP:            break;        case MotionEvent.ACTION_CANCEL:            break;    }    return true;}

  onTouchEvent()方法是SeekBar的触摸事件处理方法,通过监听触摸事件的四种状态,我们可以实时更新SeekBar的视图状态。

3. 自定义SeekBar的样式

3.1 基本样式

<com.example.MySeekBar    android:id="@+id/mySeekBar"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:paddingLeft="10dp"    android:paddingRight="10dp"    app:thumb="@drawable/ic_thumb"    app:progressColor="@color/colorAccent"    app:progressBackground="@color/colorPrimary"    app:seekBarHeight="20dp" />

  通过设置app:thumbapp:progressColorapp:progressBackground等属性,我们可以实现SeekBar的基本样式。

3.2 高级样式

<com.example.MySeekBar    android:id="@+id/mySeekBar"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:paddingLeft="10dp"    android:paddingRight="10dp"    app:thumb="@drawable/ic_thumb"    app:progressColor="@color/colorAccent"    app:progressBackground="@color/colorPrimary"    app:seekBarHeight="20dp"    style="?android:attr/progressBarStyleHorizontal" />

  除了基本样式外,我们还可以通过设置style="?android:attr/progressBarStyleHorizontal"属性,使得SeekBar的样式与系统默认的样式保持一致,效果更加美观。

四、完整代码示例

public class MySeekBar extends SeekBar {    private Paint paint;    private Bitmap thumbBitmap;    private int progressColor;    private int progressBackground;    private int seekBarHeight;    private float touchDownX;    public MySeekBar(Context context) {        super(context);        setup();    }    public MySeekBar(Context context, AttributeSet attrs) {        super(context, attrs);        setup(attrs);    }    public MySeekBar(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        setup(attrs);    }    private void setup() {        paint = new Paint(Paint.ANTI_ALIAS_FLAG);        thumbBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_thumb);    }    private void setup(AttributeSet attrs) {        paint = new Paint(Paint.ANTI_ALIAS_FLAG);        thumbBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_thumb);        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.MySeekBar);        progressColor = typedArray.getColor(R.styleable.MySeekBar_progressColor, Color.RED);        progressBackground = typedArray.getColor(R.styleable.MySeekBar_progressBackground, Color.GRAY);        seekBarHeight = (int) typedArray.getDimension(R.styleable.MySeekBar_seekBarHeight, 10);        typedArray.recycle();    }    @Override    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int height = MeasureSpec.getSize(heightMeasureSpec);        int width = MeasureSpec.getSize(widthMeasureSpec);        setMeasuredDimension(width, height);    }    @Override    protected synchronized void onDraw(Canvas canvas) {        super.onDraw(canvas);        int width = getWidth();        int height = getHeight();        float thumbX = getThumbPosX();        // 绘制背景        RectF rectBackground = new RectF(0, height / 2 - seekBarHeight / 2, width, height / 2 + seekBarHeight / 2);        paint.setColor(progressBackground);        canvas.drawRoundRect(rectBackground, height / 2, height / 2, paint);        // 绘制填充区域        float progressEnd = thumbX + getPaddingLeft();        RectF rectProgress = new RectF(0, height / 2 - seekBarHeight / 2, progressEnd, height / 2 + seekBarHeight / 2);        paint.setColor(progressColor);        canvas.drawRoundRect(rectProgress, height / 2, height / 2, paint);        // 绘制把手图像        canvas.drawBitmap(thumbBitmap, thumbX, height / 2 - thumbBitmap.getHeight() / 2, paint);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        if (!isEnabled()) {            return false;        }        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                touchDownX = event.getX();                break;            case MotionEvent.ACTION_MOVE:                float touchMoveX = event.getX();                float touchDelta = touchMoveX - touchDownX;                touchDownX = touchMoveX;                int thumbPosX = (int) (getThumbPosX() + touchDelta);                int maxRange = getWidth() - getPaddingLeft() - getPaddingRight();                int seekBarWidth = thumbBitmap.getWidth();                thumbPosX = Math.max(thumbPosX, 0);                thumbPosX = Math.min(thumbPosX, maxRange);                setProgress(thumbPosX * getMax() / (maxRange - seekBarWidth));                break;            case MotionEvent.ACTION_UP:                break;            case MotionEvent.ACTION_CANCEL:                break;        }        return true;    }    private float getThumbPosX() {        int width = getWidth() - getPaddingLeft() - getPaddingRight();        int seekBarWidth = thumbBitmap.getWidth();        float ratio = (float) getProgress() / (float) getMax();        return width * ratio;    }}

<declare-styleable name="MySeekBar">    <attr name="thumb" format="reference" />    <attr name="progressColor" format="color" />    <attr name="progressBackground" format="color" />    <attr name="seekBarHeight" format="dimension" /></declare-styleable>

<com.example.MySeekBar    android:id="@+id/mySeekBar"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:paddingLeft="10dp"    android:paddingRight="10dp"    app:thumb="@drawable/ic_thumb"    app:progressColor="@color/colorAccent"    app:progressBackground="@color/colorPrimary"    app:seekBarHeight="20dp" />

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/235890.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-12-12 11:56
下一篇 2024-12-12 11:57

相关推荐

  • Python中自定义函数必须有return语句

    自定义函数是Python中最常见、最基本也是最重要的语句之一。在Python中,自定义函数必须有明确的返回值,即必须要有return语句。本篇文章将从以下几个方面对此进行详细阐述。…

    编程 2025-04-29
  • Android ViewPager和ScrollView滑动冲突问题

    Android开发中,ViewPager和ScrollView是两个常用的控件。但是当它们同时使用时,可能会发生滑动冲突的问题。本文将从多个方面介绍解决Android ViewPa…

    编程 2025-04-28
  • Android如何点击其他区域收起软键盘

    在Android应用中,当输入框获取焦点弹出软键盘后,我们希望能够点击其他区域使软键盘消失,以提升用户体验。本篇文章将说明如何实现这一功能。 一、获取焦点并显示软键盘 在Andro…

    编程 2025-04-28
  • Python自定义列表

    本文将为大家介绍Python中自定义列表的方法和应用场景。对自定义列表进行详细的阐述,包括列表的基本操作、切片、列表推导式、列表的嵌套以及列表的排序,希望能够帮助大家更好地理解和应…

    编程 2025-04-27
  • 如何添加Python自定义模块?

    Python是一种非常流行的脚本语言,因其易学易用和功能强大而备受欢迎。自定义模块是Python开发中经常使用的功能之一。本文将从多个方面为您介绍如何添加Python自定义模块。 …

    编程 2025-04-27
  • Python ttk控件用法介绍

    本文将从多个方面对Python ttk控件进行详细阐述,旨在帮助开发者更好的使用和理解这一控件。 一、ttk控件概述 ttk控件是Python tkinter模块中的一个扩展模块,…

    编程 2025-04-27
  • Android Studio HUD 实现指南

    本文将会以实例来详细阐述如何在 Android Studio 中使用 HUD 功能实现菊花等待指示器的效果。 一、引入依赖库 首先,我们需要在 build.gradle 文件中引入…

    编程 2025-04-27
  • Android和Vue3混合开发方案

    本文将介绍如何将Android和Vue3结合起来进行混合开发,以及其中的优势和注意事项。 一、环境搭建 在进行混合开发之前,需要搭建好相应的开发环境。首先需要安装 Android …

    编程 2025-04-27
  • Android Java Utils 可以如何提高你的开发效率

    Android Java Utils 是一款提供了一系列方便实用的工具类的 Java 库,可以帮助开发者更加高效地进行 Android 开发,提高开发效率。本文将从以下几个方面对 …

    编程 2025-04-27
  • Android JUnit测试完成程序自动退出决方法

    对于一些Android JUnit测试的开发人员来说,程序自动退出是一个经常面临的困扰。下面从多个方面给出解决方法。 一、检查测试代码 首先,我们应该仔细检查我们的测试代码,确保它…

    编程 2025-04-25

发表回复

登录后才能评论