想整个双向的进度条,就是可以选取播放范围的。

像这样:

20170905165905.png

然而官方控件里只有单向的。不要慌,我们自己画一个。

绘制一个进度条主要是三方面。1.样式,2.尺寸,3.操作监听。

完整代码来一遍:

注释基本上就把原理说明了一下。

package util;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.drawable.Drawable;

import android.support.v4.content.ContextCompat;

import android.util.AttributeSet;

import android.util.Log;

import android.view.MotionEvent;

import android.view.View;

import com.example.qzd.utildemo.R;

import java.math.BigDecimal;

/**

* 双向滑块的进度条(区域选择)

*/

public class SeekRangeBar extends View {

private Context _context;

private static final int CLICK_ON_LOW = 1; //手指在前滑块上滑动

private static final int CLICK_ON_HIGH = 2; //手指在后滑块上滑动

private static final int CLICK_IN_LOW_AREA = 3; //手指点击离前滑块近

private static final int CLICK_IN_HIGH_AREA = 4; //手指点击离后滑块近

private static final int CLICK_OUT_AREA = 5; //手指点击在view外

private static final int CLICK_INVAILD = 0;

private static final int[] STATE_NORMAL = {};

private static final int[] STATE_PRESSED =

{android.R.attr.state_pressed,android.R.attr.state_window_focused,};

private static int mThumbMarginTop = 0; //滑动块顶部离view顶部的距离

private static int mTextViewMarginTop = 0; //当前滑块文字距离view顶部距离

private Drawable hasScrollBarBg; //滑动条滑动后背景图

private Drawable notScrollBarBg; //滑动条未滑动背景图

private Drawable mThumbLow; //前滑块

private Drawable mThumbHigh; //后滑块

private int mScollBarWidth; //控件宽度 = 滑动条宽度 + 滑动块宽度

private int mScollBarHeight; //控件高度

private int mThumbWidth; //滑动块直径

private double mOffsetLow = 0; //前滑块中心坐标

private double mOffsetHigh = 0; //后滑块中心坐标

private int mDistance=0; //总刻度是固定距离 两边各去掉半个滑块距离

private int mFlag = CLICK_INVAILD; //手指按下的类型

private double defaultScreenLow = 0; //默认前滑块位置百分比

private double defaultScreenHigh = 100; //默认后滑块位置百分比

private OnSeekBarChangeListener mBarChangeListener;

private boolean editable=false;//是否处于可编辑状态

private int miniGap=5;//AB的最小间隔

private double progressLow;//起点(百分比)

private double progressHigh;//终点

public SeekRangeBar(Context context) {

this(context, null);

}

public SeekRangeBar(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public SeekRangeBar(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

_context=context;

//这里设置背景图及滑块图,自定义过进度条的同学应该很熟悉了

notScrollBarBg = ContextCompat.getDrawable(_context,R.mipmap.hp_wbf);

hasScrollBarBg = ContextCompat.getDrawable(_context, R.mipmap.hp_ybf);

mThumbLow = ContextCompat.getDrawable(_context,R.mipmap.hp_a);

mThumbHigh = ContextCompat.getDrawable(_context,R.mipmap.hp_b);

mThumbLow.setState(STATE_NORMAL);

mThumbHigh.setState(STATE_NORMAL);

//设置滑动条高度

mScollBarHeight = notScrollBarBg.getIntrinsicHeight();

//设置滑动块直径

mThumbWidth = mThumbLow.getIntrinsicWidth();

}

/**

* 测量view尺寸(在onDraw()之前)

* @param widthMeasureSpec

* @param heightMeasureSpec

*/

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int width = MeasureSpec.getSize(widthMeasureSpec);

mScollBarWidth = width;

if(mDistance==0) {//这里滑块中心坐标初始化的时候测量一下(根据mDistance是否赋值判断),并不需要不停地去测量。后面会根据进度计算滑块位置。

mOffsetLow = mThumbWidth / 2;

mOffsetHigh = width - mThumbWidth / 2;

}

mDistance = width - mThumbWidth;

if(defaultScreenLow != 0) {

mOffsetLow = formatInt(defaultScreenLow / 100 * (mDistance)) + mThumbWidth / 2;

}

if(defaultScreenHigh != 100) {

mOffsetHigh = formatInt(defaultScreenHigh / 100 * (mDistance)) + mThumbWidth / 2;

}

setMeasuredDimension(width, mThumbWidth + mThumbMarginTop + 2);

}

protected void onLayout(boolean changed, int l, int t, int r, int b) {

super.onLayout(changed, l, t, r, b);

}

/**

* 绘制进度条

*/

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

//设置绘制样式

Paint text_Paint = new Paint();

text_Paint.setTextAlign(Paint.Align.CENTER);

text_Paint.setColor(Color.RED);

text_Paint.setTextSize(20);

int top = mThumbMarginTop + mThumbWidth / 2 - mScollBarHeight / 2;

int bottom = top + mScollBarHeight;

//绘制是否可操作状态的下的不同样式,仅可编辑状态下显示进度条

if(editable) {

//白色滑动条,两个滑块各两边部分

notScrollBarBg.setBounds(mThumbWidth / 2, top, mScollBarWidth - mThumbWidth / 2, bottom);

notScrollBarBg.draw(canvas);

//红色滑动条,两个滑块中间部分

hasScrollBarBg.setBounds((int) mOffsetLow, top, (int) mOffsetHigh, bottom);

hasScrollBarBg.draw(canvas);

}

//前滑块

mThumbLow.setBounds((int) (mOffsetLow - mThumbWidth / 2), mThumbMarginTop, (int) (mOffsetLow + mThumbWidth / 2), mThumbWidth + mThumbMarginTop);

mThumbLow.draw(canvas);

//后滑块

mThumbHigh.setBounds((int) (mOffsetHigh - mThumbWidth / 2), mThumbMarginTop, (int) (mOffsetHigh + mThumbWidth / 2), mThumbWidth + mThumbMarginTop);

mThumbHigh.draw(canvas);

//当前滑块刻度

progressLow = formatInt((mOffsetLow - mThumbWidth / 2) * 100 / mDistance);

progressHigh = formatInt((mOffsetHigh - mThumbWidth / 2) * 100 / mDistance);

canvas.drawText((int) progressLow + "", (int) mOffsetLow - 2 - 2, mTextViewMarginTop, text_Paint);

canvas.drawText((int) progressHigh + "", (int) mOffsetHigh - 2, mTextViewMarginTop, text_Paint);

if (mBarChangeListener != null) {

mBarChangeListener.onProgressChanged(this, progressLow, progressHigh);

}

}

//手势监听

@Override

public boolean onTouchEvent(MotionEvent e) {

if(!editable) {

return false;

}

if (e.getAction() == MotionEvent.ACTION_DOWN) {

mFlag = getAreaFlag(e);

if (mFlag == CLICK_ON_LOW) {

mThumbLow.setState(STATE_PRESSED);

} else if (mFlag == CLICK_ON_HIGH) {

mThumbHigh.setState(STATE_PRESSED);

} else if (mFlag == CLICK_IN_LOW_AREA) {

mThumbLow.setState(STATE_PRESSED);

mThumbHigh.setState(STATE_NORMAL);

//如果点击0-mThumbWidth/2坐标

if (e.getX() < 0 || e.getX() <= mThumbWidth / 2) {

mOffsetLow = mThumbWidth / 2;

} else if (e.getX() > mScollBarWidth - mThumbWidth / 2) {

mOffsetLow = mThumbWidth / 2 + mDistance;

} else {

mOffsetLow = formatInt(e.getX());

}

} else if (mFlag == CLICK_IN_HIGH_AREA) {

mThumbHigh.setState(STATE_PRESSED);

mThumbLow.setState(STATE_NORMAL);

if (e.getX() >= mScollBarWidth - mThumbWidth / 2) {

mOffsetHigh = mDistance + mThumbWidth / 2;

} else {

mOffsetHigh = formatInt(e.getX());

}

}

//更新滑块

invalidate();

} else if (e.getAction() == MotionEvent.ACTION_MOVE) {

if (mFlag == CLICK_ON_LOW) {

if (e.getX() < 0 || e.getX() <= mThumbWidth / 2) {

mOffsetLow = mThumbWidth / 2;

} else if (e.getX() >= mScollBarWidth - mThumbWidth / 2) {

mOffsetLow = mThumbWidth / 2 + mDistance;

mOffsetHigh = mOffsetLow;

} else {

mOffsetLow = formatInt(e.getX());

if (mOffsetHigh - mOffsetLow <= 0) {

mOffsetHigh = (mOffsetLow <= mDistance + mThumbWidth / 2) ? (mOffsetLow) : (mDistance + mThumbWidth / 2);

}

}

} else if (mFlag == CLICK_ON_HIGH) {

if (e.getX() < mThumbWidth / 2) {

mOffsetHigh = mThumbWidth / 2;

mOffsetLow = mThumbWidth / 2;

} else if (e.getX() > mScollBarWidth - mThumbWidth / 2) {

mOffsetHigh = mThumbWidth / 2 + mDistance;

} else {

mOffsetHigh = formatInt(e.getX());

if (mOffsetHigh - mOffsetLow <= 0) {

mOffsetLow = (mOffsetHigh >= mThumbWidth / 2) ? (mOffsetHigh) : mThumbWidth / 2;

}

}

}

//更新滑块,每次滑块有动作都要执行此函数触发onDraw方法绘制新图片

invalidate();

} else if (e.getAction() == MotionEvent.ACTION_UP) {

Log.d("LOGCAT","ACTION UP:"+progressHigh+"-"+progressLow);

mThumbLow.setState(STATE_NORMAL);

mThumbHigh.setState(STATE_NORMAL);

if(miniGap>0 && progressHigh

progressHigh=progressLow+miniGap;

this.defaultScreenHigh = progressHigh;

mOffsetHigh = formatInt(progressHigh / 100 * (mDistance)) + mThumbWidth / 2;

invalidate();

}

}

return true;

}

/**

* 设置是否可编辑状态,非可编辑状态将不能对AB点进行操作

* @param _b

*/

public void setEditable(boolean _b){

editable=_b;

invalidate();

}

/**

* 获取当前手指位置

*/

public int getAreaFlag(MotionEvent e) {

int top = mThumbMarginTop;

int bottom = mThumbWidth + mThumbMarginTop;

if (e.getY() >= top && e.getY() <= bottom && e.getX() >= (mOffsetLow - mThumbWidth / 2) && e.getX() <= mOffsetLow + mThumbWidth / 2) {

return CLICK_ON_LOW;

} else if (e.getY() >= top && e.getY() <= bottom && e.getX() >= (mOffsetHigh - mThumbWidth / 2) && e.getX() <= (mOffsetHigh + mThumbWidth / 2)) {

return CLICK_ON_HIGH;

} else if (e.getY() >= top

&& e.getY() <= bottom

&& ((e.getX() >= 0 && e.getX() < (mOffsetLow - mThumbWidth / 2)) || ((e.getX() > (mOffsetLow + mThumbWidth / 2))

&& e.getX() <= ((double) mOffsetHigh + mOffsetLow) / 2))) {

return CLICK_IN_LOW_AREA;

} else if (e.getY() >= top && e.getY() <= bottom && (((e.getX() > ((double) mOffsetHigh + mOffsetLow) / 2) && e.getX() < (mOffsetHigh - mThumbWidth / 2)) || (e.getX() > (mOffsetHigh + mThumbWidth / 2) && e.getX() <= mScollBarWidth))) {

return CLICK_IN_HIGH_AREA;

} else if (!(e.getX() >= 0 && e.getX() <= mScollBarWidth && e.getY() >= top && e.getY() <= bottom)) {

return CLICK_OUT_AREA;

} else {

return CLICK_INVAILD;

}

}

/**

* 设置前滑块位置

* @param progressLow

*/

public void setProgressLow(double progressLow) {

this.defaultScreenLow = progressLow;

mOffsetLow = formatInt(progressLow / 100 * (mDistance)) + mThumbWidth / 2;

invalidate();

}

/**

* 设置后滑块位置

* @param progressHigh

*/

public void setProgressHigh(double progressHigh) {

this.defaultScreenHigh = progressHigh;

mOffsetHigh = formatInt(progressHigh / 100 * (mDistance)) + mThumbWidth / 2;

invalidate();

}

/**

* 设置滑动监听

* @param mListener

*/

public void setOnSeekBarChangeListener(OnSeekBarChangeListener mListener) {

this.mBarChangeListener = mListener;

}

/**

* 滑动监听,改变输入框的值

*/

public interface OnSeekBarChangeListener {

//滑动时

public void onProgressChanged(SeekRangeBar seekBar, double progressLow, double progressHigh);

}

/**

* 设置滑动结果为整数

*/

private int formatInt(double value) {

BigDecimal bd = new BigDecimal(value);

BigDecimal bd1 = bd.setScale(0, BigDecimal.ROUND_HALF_UP);

return bd1.intValue();

}

}

然后就可以在程序中使用了。

布局中

android:id="@+id/doubleSeekbar"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_centerVertical="true"/>

调用

private SeekRangeBar doubleSeekbar;//双向进度条

doubleSeekbar = (SeekRangeBar) findViewById(R.id.doubleSeekbar);

//监听进度范围变化

doubleSeekbar.setOnSeekBarChangeListener(new SeekRangeBar.OnSeekBarChangeListener() {

@Override

public void onProgressChanged(SeekRangeBar seekBar, double progressLow, double progressHigh) {

Log.d("LOGCAT","低:" + progressLow + "高:" + progressHigh);

}

});

android 双向进度条,Android自定义双向进度条相关推荐

  1. android绘制环形进度_Android动态自定义圆形进度条

    这篇文章主要介绍了Android动态自定义圆形进度条,需要的朋友可以参考下 效果图: A.绘制圆环,圆弧,文本 //1.画圆环 //原点坐标 float circleX = width / 2; fl ...

  2. Android学习笔记18:自定义Seekbar拖动条式样

    SeekBar拖动条可以由用户控制,进行拖动操作.比如,应用程序中用户需要对音量进行控制,就可以使用拖动条来实现. 1.SeekBar控件的使用 1.1SeekBar常用属性 SeekBar的常用属性 ...

  3. Android自定义半圆进度条 半圆渐变色进度条带指示 半圆开口大小可自由修改

    Android自定义半圆进度条 半圆渐变色进度条带指示 半圆开口大小可自由修改 首先我们来看下效果图 不同的开口大小只需要修改一个参数即可 半圆1: 半圆2: 半圆3: 如果是你想要的效果,就直接滑动 ...

  4. android绘制心形_Android自定义View系列(一)——打造一个爱心进度条

    写作原因:Android进阶过程中有一个绕不开的话题--自定义View.这一块是安卓程序员更好地实现功能自主化必须迈出的一步.下面这个系列博主将通过实现几个例子来认识安卓自定义View的方法.从自定义 ...

  5. 【Android 应用开发】 自定义 圆形进度条 组件

    转载著名出处 : http://blog.csdn.net/shulianghan/article/details/40351487 代码下载 : -- CSDN 下载地址 : http://down ...

  6. Android自定义圆形进度条

    Android自定义圆形进度条 github地址:https://github.com/opq1289/CircleProgressView 效果图: 无动画: 有动画: 整圆: 切割圆: 具体步骤: ...

  7. Android中用图片自定义一个进度条(实现蒙板效果)

    问题概述 对于进度条我相信大家不陌生,这里我就不再多说什么了.因为这个不是重点.我们要说的是如何去自定义一个不一样的进度条.这里用到两张图片(背景和前景),其实是三张(背景.前景和蒙图).当我们的蒙图 ...

  8. android 自定义背景园,Android 自定义ProgressBar 进度条颜色和背景颜色

    Android 自定义ProgressBar 进度条颜色和背景颜色 首先,在drawable目录下新建文件 personal_center_level_progress_bg.xmlandroid a ...

  9. android 自定义 进度条 旋转,Android_Android ProgressBar进度条使用详解,ProgressBar进度条,分为旋转进 - phpStudy...

    Android ProgressBar进度条使用详解 ProgressBar进度条,分为旋转进度条和水平进度条,进度条的样式根据需要自定义,之前一直不明白进度条如何在实际项目中使用,网上演示进度条的案 ...

  10. Android 自定义View,自定义属性--自定义圆形进度条(整理)

    很多的时候,系统自带的View满足不了我们的功能需求,那么我们就需要自定义View来满足我们的需求 自定义View时要先继承View,添加类的构造方法,重写父类View的一些方法,例如onDraw,为 ...

最新文章

  1. Gmapping 乱七八糟
  2. 人脑动态功能网络连接模式能够鉴别个体并预测其认知功能
  3. 四级嵌入式系统开发工程师-计算题题库
  4. BootStrap的下载及使用方法
  5. 常用的SAP系统FM
  6. 在Eclipse中使用OpenCV Java
  7. Qt Creator使用其他构建系统
  8. Spring Boot (一)Spring Boot 概述
  9. html网页动态显示效果,html的table用法(让网页的视觉效果显示出来)
  10. Android下播放YUV视频文件
  11. 通过vba代码将excel转换为PDF
  12. Fluent UDF中调用Matlab函数(以误差函数erf为例)
  13. 修复SSH Weak Algorithms Supported漏洞
  14. 静态测试和动态测试相关知识点
  15. 路由控制配置route-policy命令解析
  16. 绿皮车里的温馨服务 情暖回家路
  17. visualSVN server的安装和使用
  18. R与结构方程模型(2):潜变量
  19. 服务器系统重启和断电重启,服务器设置断电重启吗
  20. java怎么添加商品信息_Javaweb网上商城项目实战(20)添加商品到购物车

热门文章

  1. 家用千兆路由器排行榜前十名_家庭用哪款路由器好 2017最适合家用路由器排行榜...
  2. AIOT:基于智能家居谈AIOT
  3. LeetCode-自除数
  4. 流量贵?裂变营销或是低成本营销的最佳选择!
  5. 在线模拟装机大学计算机,模拟装机实验.doc
  6. java获取本地磁盘文件_java如何读取本地磁盘目录下的所有文件或者文件夹
  7. 手机浏览器打不开php,php 判断是否是手机浏览器访问?
  8. 设置android应用闪屏图片_android 闪屏设计
  9. http://www.cnblogs.com/Jackie-zhang/p/6071769.html
  10. 【独立后台】2021全新最火表情包小程序源码,无限裂变,斗图小程序,头像壁纸,外卖服务内附详细搭建教程