Android自定义控件之拖动条

安卓Seekbar自定义样式的开发 安卓自定义seekbar 阅读详情

首先奉上控件的截图,楼主的手机是小米5,。


下面说一下思路:

这个控件的主体就是一条细长的线,线的两端为圆形,中间有一个彩色的小圆指示当前进度,随着下面的seekbar的拖动或者手指的触摸,小圆的位置和控件的颜色会发生变化。

弄清楚了思路,就知道接下来该怎么办了,绘制这个控件还是很简单的,大概分为以下几步:

1、设置自定义控件的相关属性;

2、编写自定义控件类,继承android.view.View类,然后分别重写onMeasure()、onDraw()方法;

3、为控件添加触摸事件,这里需要在重写的onTouchEvent()方法中计算手指触摸的坐标,根据坐标的x、y值来确定是否触摸了控件;然后定义一个内部监听器,用于监听手指触摸事件,从而得到自定义控件的当前进度值。

代码如下:

1、attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="progressBar">
        <attr name="backgroundColor" format="color" />
        <attr name="startFillColor" format="color" />
        <attr name="middleFillColor" format="color" />
        <attr name="endFillColor" format="color" />
        <attr name="progressPointColor" format="color" />
        <attr name="lineWidth" format="dimension" />
    </declare-styleable>

</resources>

2、MySeekBar.java

package com.ctgu.horizontalprogressbarwithnotext;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;

/**
 * 水平渐变色拖动条
 * 
 */
public class MySeekBar extends View
{
	/**
	 * 进度条填充起始色
	 */
	protected int startFillColor;

	/**
	 * 进度条填充中间色
	 */
	protected int middleFillColor;

	/**
	 * 进度条填充结束颜色
	 */
	protected int endFillColor;

	/**
	 * 指示圆点颜色
	 */
	private int progressPointColor;

	/**
	 * 进度条未填充颜色
	 */
	protected int backgroundColor;

	/**
	 * 进度条长度
	 */
	protected float progressWidth;

	/**
	 * 进度条的高度,包括进度条的高度和上下的间隔
	 */
	private float progressHeight;

	/**
	 * 进度条的高度,不包括上下的间隔
	 */
	private float lineWidth;

	/**
	 * 进度条左侧间隔
	 */
	private float widthSpace;

	/**
	 * 进度条中心与上方的间隔
	 */
	private float heightSpace;

	/**
	 * 內圆的半径
	 */
	private float radius;

	/**
	 * 按比例计算各部分的值
	 */
	private float unit;

	/**
	 * 整个控件宽度
	 */
	protected int viewWidth;

	/**
	 * 整个控件高度
	 */
	protected int viewHeight;

	/**
	 * 渐变色数组
	 */
	private int colorArray[];

	/**
	 * 画笔
	 */
	protected Paint paint;

	/**
	 * 控件当前的进度
	 */
	private float progress = 0;

	/**
	 * 处理颜色渐变
	 */
	private LinearGradient shader;

	/**
	 * 自定义的监听器,负责监听控件的触摸事件
	 */
	private ProgressChangedListener listener;

	/**
	 * @param context
	 *            上下文
	 */
	public MySeekBar(Context context)
	{
		this(context, null);
	}

	/**
	 * @param context上下文
	 * @param attrs
	 *            自定义的属性
	 */
	public MySeekBar(Context context, AttributeSet attrs)
	{
		this(context, attrs, 0);
	}

	/**
	 * @param context
	 *            上下文
	 * @param attrs
	 *            自定义的属性
	 * @param defStyleAttr
	 *            自定义的风格
	 */
	public MySeekBar(Context context, AttributeSet attrs, int defStyleAttr)
	{
		super(context, attrs, defStyleAttr);

		colorArray = new int[3];
		paint = new Paint();

		TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.progressBar);
		int n = ta.getIndexCount();
		for (int i = 0; i < n; i++)
		{
			int attr = ta.getIndex(i);
			switch (attr)
			{
				case R.styleable.progressBar_startFillColor:
					colorArray[0] = ta.getColor(R.styleable.progressBar_startFillColor, 0xffff0000);
					break;
				case R.styleable.progressBar_middleFillColor:
					colorArray[1] = ta.getColor(R.styleable.progressBar_middleFillColor, 0xffff0000);
					break;
				case R.styleable.progressBar_endFillColor:
					colorArray[2] = ta.getColor(R.styleable.progressBar_endFillColor, 0xffff0000);
					break;
				case R.styleable.progressBar_backgroundColor:
					backgroundColor = ta.getColor(R.styleable.progressBar_backgroundColor, Color.GRAY);
					break;
				case R.styleable.progressBar_progressPointColor:
					progressPointColor = ta.getColor(R.styleable.progressBar_progressPointColor, Color.WHITE);
					break;
				case R.styleable.progressBar_lineWidth:
					lineWidth = ta.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
							TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics()));
					break;
			}
		}
		ta.recycle();
	}

	/**
	 * 测量组件高度和宽度
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
	{
		int width = 0;
		int height = 0;

		// 设置宽度
		// MeasureSpec.getMode()会得到三个int类型的值分别为:MeasureSpec.EXACTLY
		// MeasureSpec.AT_MOST,MeasureSpec.UNSPECIFIED。
		// MeasureSpec.UNSPECIFIED 未指定,所以可以设置任意大小。
		// MeasureSpec.AT_MOST MeasureExampleView可以为任意大小,但是有一个上限。
		int specMode = MeasureSpec.getMode(widthMeasureSpec);
		int specSize = MeasureSpec.getSize(widthMeasureSpec); // 会解析MeasureSpec值得到父容器width或者height。
		switch (specMode)
		{
			case MeasureSpec.EXACTLY: // 明确指定了
				width = specSize;
				break;
			case MeasureSpec.AT_MOST: // 一般为wrap_content
				width = getPaddingLeft() + getPaddingRight();
				break;
		}

		// 设置高度
		specMode = MeasureSpec.getMode(heightMeasureSpec);
		specSize = MeasureSpec.getSize(heightMeasureSpec);
		switch (specMode)
		{
			case MeasureSpec.EXACTLY:
				height = specSize;
				break;
			case MeasureSpec.AT_MOST:
				height = width / 10;
				break;
		}
		// Logger.d("onMeasure():width=" + width + ",height=" + height);
		setMeasuredDimension(width, height);

		viewWidth = getMeasuredWidth(); // 获得视图的宽度
		viewHeight = getMeasuredHeight(); // 获得视图的高度
		unit = Math.min((float) viewWidth / 300, (float) viewHeight / 30); // 按比例计算各部分的值

		progressWidth = 280 * unit; // 进度条的长度
		progressHeight = 30 * unit; // 进度条的高度,包括上下间隔

		widthSpace = 8 * unit; // 进度条左侧间隔
		heightSpace = progressHeight / 2; // float heightSpace 进度条中心与上方的间隔

		radius = lineWidth / 2; // 內圆的半径
	}

	@Override
	public void onDraw(Canvas canvas)
	{
		float percent = ((float) progress) / 100; // 当前进度的百分比
		if (percent > 1)
		{
			percent = 1;
		}

		// 画灰色的底线
		paint.setAntiAlias(true);
		paint.setDither(true);
		paint.setColor(backgroundColor); // 设置颜色为灰色
		paint.setStrokeWidth(lineWidth); // 设置线的宽度
		paint.setStrokeCap(Paint.Cap.ROUND); // 设置线为圆角
		canvas.drawLine(widthSpace, heightSpace, widthSpace + progressWidth, heightSpace, paint); // 画灰色的底线

		// 画渐变色横线
		shader = new LinearGradient(0, 0, widthSpace + progressWidth, 0, colorArray, null,
				Shader.TileMode.CLAMP);
		paint.setShader(shader);// 设置渐变色
		canvas.drawLine(widthSpace, heightSpace, widthSpace + percent * progressWidth, heightSpace, paint); // 画渐变色进度线条

		// 画圆
		paint.setShader(null);
		paint.setColor(progressPointColor);
		paint.setStrokeWidth(2);
		paint.setStyle(Paint.Style.FILL); // 设置绘画方式为填充
		canvas.drawCircle(widthSpace + percent * progressWidth, heightSpace, radius, paint); // 绘制圆
	}

	@Override
	public boolean onTouchEvent(MotionEvent event)
	{
		int action = event.getAction();
		switch (action)
		{
			case MotionEvent.ACTION_DOWN:
			case MotionEvent.ACTION_MOVE:
				float x = event.getX();
				float y = event.getY();

				if ((x >= (0 - radius)) && (x <= (progressWidth + widthSpace + radius)))
				{
					if (y >= 0 && y <= progressHeight)
					{
						this.progress = x * 100.0f / (progressWidth + widthSpace); // 这里要重新计算进度值
						invalidate(); // 重绘界面
						if (listener != null)
						{
							listener.onProgressChanged(progress); // 在处理触摸事件时传入重新计算过的进度参数,
						}
					}
				}
				return true;
			case MotionEvent.ACTION_UP:
				invalidate(); // 手指抬起时刷新一下页面
				return true;
		}
		return super.onTouchEvent(event);
	}

	public void setOnProgressChangeListener(ProgressChangedListener listener2)
	{
		this.listener = listener2;
	}

	/**
	 * 设置进度条的进度值
	 * 
	 * @param pro
	 *            传入的进度值
	 */
	public void setProgress(float pro)
	{
		if (pro < 0)
		{
			this.progress = 0;
		}
		else if (pro > 100)
		{
			this.progress = 100;
		}
		else
		{
			this.progress = pro;
		}
		invalidate();
	}

	/**
	 * 设置渐变色数组
	 * 
	 * @param colorArray
	 */
	public void setColorArray(int[] colorArray)
	{
		this.colorArray = colorArray;
	}

	public interface ProgressChangedListener
	{
		public void onProgressChanged(float touchX);
	}
}

3、activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:lh2="http://schemas.android.com/apk/res/com.ctgu.horizontalprogressbarwithnotext"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.ctgu.horizontalprogressbarwithnotext.MySeekBar
        android:id="@+id/progressBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_marginTop="50dp"
        lh2:progressPointColor="#EEC591"
        lh2:lineWidth="16dp"
        lh2:backgroundColor="#D8D8D8"
        lh2:endFillColor="#e03060"
        lh2:middleFillColor="#B03060"
        lh2:startFillColor="#505050" />

    <SeekBar
        android:id="@+id/seekbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/progressBar"
        android:layout_marginLeft="40dp"
        android:layout_marginRight="40dp"
        android:layout_marginTop="30dp"
        android:padding="20dp" />

</RelativeLayout>

4、MainActivity.java

package com.ctgu.horizontalprogressbarwithnotext;

import android.app.Activity;
import android.os.Bundle;
import android.widget.SeekBar;

import com.ctgu.horizontalprogressbarwithnotext.MySeekBar.ProgressChangedListener;

/**
 * 测试界面
 */
public class MainActivity extends Activity
{
	private MySeekBar bar;
	private SeekBar seekbar;

	// private int colors[] = { Color.RED, Color.GREEN };

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		bar = (MySeekBar) findViewById(R.id.progressBar);
		// bar.setColorArray(colors); // 传入一个渐变色数组,更改默认的拖动条样式,是可选项
		bar.setOnProgressChangeListener(new ProgressChangedListener()
		{
			@Override
			public void onProgressChanged(float progress)
			{
				bar.setProgress(progress);
			}
		});

		seekbar = (SeekBar) findViewById(R.id.seekbar);
		seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
		{
			@Override
			public void onStopTrackingTouch(SeekBar seekBar)
			{

			}

			@Override
			public void onStartTrackingTouch(SeekBar seekBar)
			{

			}

			@Override
			public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
			{
				bar.setProgress(progress);
			}
		});
	}
}

整个项目的代码如下:

demo地址











android 自定义SeekBar(拖动) 要做一个视频播放器,界面需要自己定义,在做拖动的时候,很难看。所以就上网找资料并且进行调试。 网上很多资料,但是可能别人的能调好,但是自己照搬不一定能调出跟网上资料一样的效果。 所以,自定义SeekBar最重要的就是设置背景以及android:minHeight跟android:maxHeight属性,也可以加上android:thumbOffset。 我的SeekBar背景大小为579* 阅读详情

相关推荐

Android实现自定义的垂直SeekBar

然而,默认的SeekBar只支持水平方向的滑动,如果我们需要实现一个垂直方向的SeekBar,就需要进行一些自定义。在这个示例中,我们将垂直SeekBar放置在一个垂直方向的LinearLayout中,并设置了一些基本属性,如ID、宽度、高度和最大值。首先,我们需要创建一个自定义的垂直SeekBar类,继承自SeekBar。方法:用于绘制SeekBar,在绘制之前对画布进行旋转和平移操作,使SeekBar在垂直方向上正确显示。方法:用于测量SeekBar的尺寸,将宽度和高度进行交换,以实现垂直方向的滑动。

DevGlider的博客 1013

Android 滑动条、Slider、Seekbar深度自定义

为了更好的满足日常开发中对Slider控件的各种需要,以下我们来看下基于nifty-slider来定制我们所需的各种功能及交互效果

a 5878

Android代码-自定义圆形拖动

SwagPoints SwagPoints - An Android custom circular SeekBar that supports max/min range and step settings. Gradle dependencies { ... compile 'com.dualcores.swagpoints:swagpoints:1.0.2' } Usage In XML layout: <com.dualcores.swagpoints.SwagPoints xmlns:swagpoints="http://schemas.android.com/apk/res-auto" android:id="@ id/seekbar_point" android:layout_width="match_parent" android:layout_height="340dp" android:layout_gravity="center" android:padding="64dp"

Android自定义滑动进度,Android自定义双向进度的实现代码

想整个双向的进度,就是可以选取播放范围的。像这样:然而官方控件里只有单向的。不要慌,我们自己画一个。绘制一个进度主要是三方面。1.样式,2.尺寸,3.操作监听。完整代码来一遍:注释基本上就把原理说明了一下。package util;import android.content.Context;import android.graphics.Canvas;import android.graph...

weixin_31913479的博客 714

Android自定义控件】实现可滑动的进度

本文为Android自定义控件,可滑动的进度,记录了从0到1开发的整个过程,加深对自定义View的理解,方便复习。

Ho博客 5779

android 拖动控件 方向盘控件 自定义控件

android 拖动控件 方向盘控件 自定义控件

qq_37630270的博客 189

自定义拖动android,Android自定义控件-可拖动控制的圆环控制

原标题:Android自定义控件-可拖动控制的圆环控制前几天收到这么一个需求,本来以为挺简单的,没想到最后发现实现起来还是有点小麻烦的,在这里小小的总结一下。先看看下面这张需求的样图: 样图然后在看一下最终实现的效果图,可能是gif录制软件的问题,有一些浮影,忽略就好了: 最终demo图首先要分析一下最核心的地方,如何获取到滑动距离对应的弧长,看图: 参考图p1是手指按下的点,很明显要想知道当前...

weixin_39684495的博客 350

Android自定义控件-可拖动控制的圆环控制

前几天收到这么一个需求,本来以为挺简单的,没想到最后发现实现起来还是有点小麻烦的,在这里小小的总结一下。 先看看下面这张需求的样图: 然后在看一下最终实现的效果图,可能是gif录制软件的问题,有一些浮影,忽略就好了: 首先要分析一下最核心的地方,如何获取到滑动距离对应的弧长,看图: p1是手指按下的点,很明显要想知道当前进度弧边的值,就是要求出角d的值。 以p为圆心点,atan(b)=Mat...

Android 开发架构 749

Android 自定义圆形渐变色拖动取色工具

android自定义圆形渐变色拖动取色View

qq_45371893的博客 1369

探索创新:ArcSeekBar - 圆弧形拖动

探索创新:ArcSeekBar - 圆弧形拖动 在寻找一个具有拖动功能的圆弧Seek Bar时,你是否曾感到困扰?现在,这个问题有了答案。ArcSeekBar 是一款由@GcsSloop开发的开源Android控件,它完美地融合了美观与实用性。不仅提供了传统的进度功能,还拥有丰富的自定义选项,让你在界面设计中更具灵活性。 一、项目介绍 ArcSeekBar 是一个专为Android打造的圆弧形拖...

gitblog_00069的博客 520

Android 拖动/滑动条控件、星级评分控件

ProgressBar有2个子控件: SeekBar 拖动控件 RatingBar 星级评分控件 1、拖动控件 1 <SeekBar 2 android:layout_width="300dp" 3 android:layout_height="wrap_content" 4 android:id="@+id/seekBar" 5 and...

594

Android学习笔记十二之Android基础UI三

Android学习笔记十二之Android基础UI三

Huawen的博客 5762

android 自定义view滚动,Android自定义View实现等级滑动条的实例

Android自定义View实现等级滑动条的实例实现效果图:思路:首先绘制直线,然后等分直线绘制点;绘制点的时候把X值存到集合中。然后绘制背景图片,以及图片上的数字。点击事件down的时候,换小图片为大图片。move的时候跟随手指移动。up的时候根据此时的X计算最近的集合中的点,然后自动吸附回去。1,自定义属性然后获取属性:/*** 获得我们所定义的自定义样式属性*/TypedArray a = ...

weixin_30581253的博客 542

Android 基础知识4-3.8 SeekBar(拖动)详解

拖动类似进度,不同的是用户可以控制,比如,应用程序中用户可以对音效进行控制,这就可以使用拖动来实现。由于拖动可以被用户控制,所以需要对其进行事件监听,这就需要实现SeekBar.onSeekBarChangeListener接口。在SeekBar中共需要监听3个事件,分别是:数值的改变(onProgressChanged)、开始拖动(onStartTrackingTouch)、停止拖动(onStopTrackingTouch)。在onProgressChanged中我们可以得到当前数值的大小。

yyxhzdm的博客 1万+

Android 垂直拖动,垂直SeekBar实现

自定义垂直SeekBar及样式

Benlve的博客 2808

Android弧形SeekBar的设计与实现

现在很多相机都会有zoom的功能,就是可以通过一个选择器设置焦距,来实现将远处的事物放大以达到能看清楚的目的,实现zoom除了可以通过双指滑动屏幕放大缩小来调整焦距外,还可以通过一个选择器。本文中要讲的就是实现一个弧形的选择器,这个弧形的选择器会随着设置的不同而改变UI的显示。因为随着googlecamera2架构的普及,相机可以通过设置更多的拍照参数来获取需要的图像,比如iso、曝光值、白平衡、快门时间等。...

知识应该共享,创造才应收费 2928
上一篇: Android文件操作工具类
下一篇: OkHttp Wiki翻译(一)使用OkHttp
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值