android 双向滑动 seekbar

实现原理:
1、自定义View,在onDraw(Canvas canvas)中,画出2个Drawable滑动块,2个Drawable滑动条,2个Paint(text)
2、监听onTouchEvent()事件,修改滑块和滑动条的坐标,调用invalidate()来更新界面
使用方法
1、自定义View   SeekBarPressure.class
package xxxxxxxxximport android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.math.BigDecimal;
import com.zjcpo.mobileapp.R;public class SeekBarPressure extends View {private static final String TAG = "SeekBarPressure";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;private static final int CLICK_INVAILD = 0;/** private static final int[] PRESSED_STATE_SET = {* android.R.attr.state_focused, android.R.attr.state_pressed,* android.R.attr.state_selected, android.R.attr.state_window_focused, };*/private static final int[] STATE_NORMAL = {};private static final int[] STATE_PRESSED = {android.R.attr.state_pressed, android.R.attr.state_window_focused,};private Drawable hasScrollBarBg;        //滑动条滑动后背景图private Drawable notScrollBarBg;        //滑动条未滑动背景图private Drawable mThumbLow;         //前滑块private Drawable mThumbHigh;        //后滑块private int mScollBarWidth;     //控件宽度=滑动条宽度+滑动块宽度private int mScollBarHeight;    //滑动条高度private int mThumbWidth;        //滑动块宽度private int mThumbHeight;       //滑动块高度private double mOffsetLow = 0;     //前滑块中心坐标private double mOffsetHigh = 0;    //后滑块中心坐标private int mDistance = 0;      //总刻度是固定距离 两边各去掉半个滑块距离private int mThumbMarginTop = 30;   //滑动块顶部距离上边框距离,也就是距离字体顶部的距离private int mFlag = CLICK_INVAILD;private OnSeekBarChangeListener mBarChangeListener;private double defaultScreenLow = 0;    //默认前滑块位置百分比private double defaultScreenHigh = 100;  //默认后滑块位置百分比private boolean isEdit = false;     //输入框是否正在输入public SeekBarPressure(Context context) {this(context, null);}public SeekBarPressure(Context context, AttributeSet attrs) {this(context, attrs, 0);}public SeekBarPressure(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);
//        this.setBackgroundColor(Color.BLACK);
Resources resources = getResources();notScrollBarBg = resources.getDrawable(R.drawable.seekbarpressure_bg_progress);hasScrollBarBg = resources.getDrawable(R.drawable.seekbarpressure_bg_normal);mThumbLow = resources.getDrawable(R.drawable.seekbarpressure_thumb);mThumbHigh = resources.getDrawable(R.drawable.seekbarpressure_thumb);mThumbLow.setState(STATE_NORMAL);mThumbHigh.setState(STATE_NORMAL);mScollBarWidth = notScrollBarBg.getIntrinsicWidth();mScollBarHeight = notScrollBarBg.getIntrinsicHeight();mThumbWidth = mThumbLow.getIntrinsicWidth();mThumbHeight = mThumbLow.getIntrinsicHeight();}//默认执行,计算view的宽高,在onDraw()之前protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int width = measureWidth(widthMeasureSpec);
//        int height = measureHeight(heightMeasureSpec);mScollBarWidth = width;mOffsetHigh = width - mThumbWidth / 2;mOffsetLow = mThumbWidth / 2;mDistance = width - mThumbWidth;mOffsetLow = formatDouble(defaultScreenLow / 100 * (mDistance ))+ mThumbWidth / 2;mOffsetHigh = formatDouble(defaultScreenHigh / 100 * (mDistance)) + mThumbWidth / 2;setMeasuredDimension(width, mThumbHeight + mThumbMarginTop+2);}private int measureWidth(int measureSpec) {int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);//wrap_contentif (specMode == MeasureSpec.AT_MOST) {}//fill_parent或者精确值else if (specMode == MeasureSpec.EXACTLY) {}return specSize;}private int measureHeight(int measureSpec) {int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);int defaultHeight = 100;//wrap_contentif (specMode == MeasureSpec.AT_MOST) {}//fill_parent或者精确值else if (specMode == MeasureSpec.EXACTLY) {defaultHeight = specSize;}return defaultHeight;}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 aaa = mThumbMarginTop + mThumbHeight / 2 - mScollBarHeight / 2;int bbb = aaa + mScollBarHeight;//白色,不会动notScrollBarBg.setBounds(mThumbWidth / 2, aaa, mScollBarWidth - mThumbWidth / 2, bbb);notScrollBarBg.draw(canvas);//蓝色,中间部分会动hasScrollBarBg.setBounds((int)mOffsetLow, aaa, (int)mOffsetHigh, bbb);hasScrollBarBg.draw(canvas);//前滑块mThumbLow.setBounds((int)(mOffsetLow - mThumbWidth / 2), mThumbMarginTop, (int)(mOffsetLow + mThumbWidth / 2), mThumbHeight + mThumbMarginTop);mThumbLow.draw(canvas);//后滑块mThumbHigh.setBounds((int)(mOffsetHigh - mThumbWidth / 2), mThumbMarginTop, (int)(mOffsetHigh + mThumbWidth / 2), mThumbHeight + mThumbMarginTop);mThumbHigh.draw(canvas);double progressLow = formatDouble((mOffsetLow - mThumbWidth / 2) * 100 / mDistance);double progressHigh = formatDouble((mOffsetHigh - mThumbWidth / 2) * 100 / mDistance);
//            Log.d(TAG, "onDraw-->mOffsetLow: " + mOffsetLow + "  mOffsetHigh: " + mOffsetHigh   + "  progressLow: " + progressLow + "  progressHigh: " + progressHigh);canvas.drawText((int) progressLow + "", (int)mOffsetLow - 2 - 2, 15, text_Paint);canvas.drawText((int) progressHigh + "", (int)mOffsetHigh - 2, 15, text_Paint);if (mBarChangeListener != null) {if (!isEdit) {mBarChangeListener.onProgressChanged(this, progressLow, progressHigh);}}}@Overridepublic boolean onTouchEvent(MotionEvent e) {//按下if (e.getAction() == MotionEvent.ACTION_DOWN) {if (mBarChangeListener != null) {mBarChangeListener.onProgressBefore();isEdit = false;}mFlag = getAreaFlag(e);
//            Log.d(TAG, "e.getX: " + e.getX() + "mFlag: " + mFlag);
//            Log.d("ACTION_DOWN", "------------------");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);//如果点击0-mThumbWidth/2坐标if (e.getX() < 0 || e.getX() <= mThumbWidth/2) {mOffsetLow = mThumbWidth/2;} else if (e.getX() > mScollBarWidth - mThumbWidth/2) {
//                    mOffsetLow = mDistance - mDuration;mOffsetLow = mThumbWidth/2 + mDistance;} else {mOffsetLow = formatDouble(e.getX());
//                    if (mOffsetHigh<= mOffsetLow) {
//                        mOffsetHigh = (mOffsetLow + mDuration <= mDistance) ? (mOffsetLow + mDuration)
//                                : mDistance;
//                        mOffsetLow = mOffsetHigh - mDuration;
//                    }
                }} else if (mFlag == CLICK_IN_HIGH_AREA) {mThumbHigh.setState(STATE_PRESSED);
//                if (e.getX() < mDuration) {
//                    mOffsetHigh = mDuration;
//                    mOffsetLow = mOffsetHigh - mDuration;
//                } else if (e.getX() >= mScollBarWidth - mThumbWidth/2) {
//                    mOffsetHigh = mDistance + mThumbWidth/2;if(e.getX() >= mScollBarWidth - mThumbWidth/2) {mOffsetHigh = mDistance + mThumbWidth/2;} else {mOffsetHigh = formatDouble(e.getX());
//                    if (mOffsetHigh <= mOffsetLow) {
//                        mOffsetLow = (mOffsetHigh - mDuration >= 0) ? (mOffsetHigh - mDuration) : 0;
//                        mOffsetHigh = mOffsetLow + mDuration;
//                    }
                }}//设置进度条
            refresh();//移动move} else if (e.getAction() == MotionEvent.ACTION_MOVE) {
//            Log.d("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 = formatDouble(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 = formatDouble(e.getX());if (mOffsetHigh - mOffsetLow <= 0) {mOffsetLow = (mOffsetHigh >= mThumbWidth/2) ? (mOffsetHigh) : mThumbWidth/2;}}}//设置进度条
            refresh();//抬起} else if (e.getAction() == MotionEvent.ACTION_UP) {
//            Log.d("ACTION_UP", "------------------");
            mThumbLow.setState(STATE_NORMAL);mThumbHigh.setState(STATE_NORMAL);if (mBarChangeListener != null) {mBarChangeListener.onProgressAfter();}//这两个for循环 是用来自动对齐刻度的,注释后,就可以自由滑动到任意位置
//            for (int i = 0; i < money.length; i++) {
//                 if(Math.abs(mOffsetLow-i* ((mScollBarWidth-mThumbWidth)/ (money.length-1)))<=(mScollBarWidth-mThumbWidth)/(money.length-1)/2){
//                     mprogressLow=i;
//                     mOffsetLow =i* ((mScollBarWidth-mThumbWidth)/(money.length-1));
//                     invalidate();
//                     break;
//                }
//            }
//
//            for (int i = 0; i < money.length; i++) {
//                  if(Math.abs(mOffsetHigh-i* ((mScollBarWidth-mThumbWidth)/(money.length-1) ))<(mScollBarWidth-mThumbWidth)/(money.length-1)/2){
//                      mprogressHigh=i;
//                       mOffsetHigh =i* ((mScollBarWidth-mThumbWidth)/(money.length-1));
//                       invalidate();
//                       break;
//                }
//            }
        }return true;}public int getAreaFlag(MotionEvent e) {int top = mThumbMarginTop;int bottom = mThumbHeight + 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;}}//更新滑块private void refresh() {invalidate();}//设置前滑块的值    public void setProgressLow(double  progressLow) {this.defaultScreenLow = progressLow;mOffsetLow = formatDouble(progressLow / 100 * (mDistance ))+ mThumbWidth / 2;isEdit = true;refresh();}//设置后滑块的值public void setProgressHigh(double  progressHigh) {this.defaultScreenHigh = progressHigh;mOffsetHigh = formatDouble(progressHigh / 100 * (mDistance)) + mThumbWidth / 2;isEdit = true;refresh();}public void setOnSeekBarChangeListener(OnSeekBarChangeListener mListener) {this.mBarChangeListener = mListener;}//回调函数,在滑动时实时调用,改变输入框的值public interface OnSeekBarChangeListener {//滑动前public void onProgressBefore();//滑动时public void onProgressChanged(SeekBarPressure seekBar, double progressLow,double progressHigh);//滑动后public void onProgressAfter();}/*    private int formatInt(double value) {BigDecimal bd = new BigDecimal(value);BigDecimal bd1 = bd.setScale(0, BigDecimal.ROUND_HALF_UP);return bd1.intValue();}*/public static double formatDouble(double pDouble) {BigDecimal bd = new BigDecimal(pDouble);BigDecimal bd1 = bd.setScale(2, BigDecimal.ROUND_HALF_UP);pDouble = bd1.doubleValue();return pDouble;}}

2、布局调用 xxx.xml

        <com.xxx.SeekBarPressureandroid:id="@+id/seekBar_tg2"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentTop="true"android:layout_marginBottom="10dp"android:layout_marginLeft="10dp"android:layout_marginRight="10dp" />

3、在Activity中实现XxxActivity.class

seekBarPressures = (SeekBarPressure) findViewById(R.id.seekBar_tg2);seekBarPressures.setOnSeekBarChangeListener(new SeekBarPressure.OnSeekBarChangeListener() {@Overridepublic void onProgressBefore() {isScreen = true;}@Overridepublic void onProgressChanged(SeekBarPressure seekBar, double progressLow, double progressHigh) {editTexts_min.setText((int) progressLow + "");editTexts_max.setText((int) progressHigh + "");}@Overridepublic void onProgressAfter() {isScreen = false;}});

注意:seekBar的父容器必须LinearLayout,别问我为什么,我也不知道。反正如果是Rinearlayout的话,滑动会不正常,我曹了,为这问题搞了整整3个小时

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/398028.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java开发区块链只需150行代码

本文目的是通过java实战开发教程理解区块链是什么。将通过实战入门学习&#xff0c;用Java自学开发一个很基本的区块链&#xff0c;并在此基础上能扩展如web框架应用等。这个基本的java区块链也实现简单的工作量证明系统。本文用一个java例子,演示了开发一个区块链应用的过程,涉…

按钮长按

2019独角兽企业重金招聘Python工程师标准>>> 用update来实现定时 //长按处理update: function (delta) {cc.log("update "delta);this.totalTimedelta;if(this.totalTime>TOUCH_LONG_TIMER_INVOKE){this.stopTimer();this.invokeTouchLong();}},stop…

Git-如何将已存在的项目提交到git

1.首先在码云或者github上创建一个不带README.md的项目&#xff0c;然后复制远程库的地址&#xff08;下面以码云为例&#xff09;&#xff1a;   2.进入本地已存在的项目目录&#xff1a;house    touch README.md //新建说明文件 git init //在当前项目目录中生成本地git…

ggplot2 theme相关设置—文本调整

在geom设置和scale设置之后&#xff0c;要想把图画的漂亮&#xff0c;theme设置是比不可少的 在theme 设置中element_text()是一项很重要的内容 element_text(family NULL, face NULL, colour NULL, size NULL, hjust NULL, vjust NULL, angle NULL, lineheight NULL) …

window10 mysql5.7 解压版 安装

1. 解压mysql-5.7.11-winx64.zip 到某文件夹&#xff0c; 如C:\DevelopCommon\mysql-5.7.11-winx64。 2. 配置环境变量 变量名 &#xff1a; MYSQL_HOME 变量值 &#xff1a; C:\DevelopCommon\mysql-5.7.11-winx64 -------------- 变量名 &#xff1a; Path 变量值 &#xff…

java zero copy 实现,关于Zero Copy

概述很多web应用都会有大量的静态文件。我们通常是从硬盘读取这些静态文件&#xff0c;并将完全相同的文件数据写到response socket。这样的操作需要较少的CPU&#xff0c;但是效率有些低&#xff0c;它需要经过如下的过程&#xff1a;kernel从硬盘读取数据&#xff0c;越过ker…

Java量与变量的区别

2019独角兽企业重金招聘Python工程师标准>>> 常量&#xff1a;其值不变即为常量。 语法&#xff1a; 数据类型 常量名 值; double PI 3.14;    备注&#xff1a; 一般默认常量名大写。 变量与常量之间关系(量间关系) 先来一个简单的实例&#xff0c;好了解 Java…

团队作业6

Alpha版本展示 一、 刘阳航|201521123026&#xff08;组长&#xff09; 博客地址&#xff1a;http://www.cnblogs.com/lyhooo/ 负责图形的创建和移动部分&#xff0c; 游戏区操作的实现&#xff0c;部分算法的编写 陈文俊|201521123047 博客地址&#xff1a;http://www.cnblogs…

java 新浪短网址生成器,新浪短链接接口被限制?最新新浪短网址api接口

背景新浪短网址api是sina平台官对外公开的短网址生成接口&#xff0c;可以将长链接通过接口生成t.cn样式的短链接&#xff0c;可以说是非常好用的。但近期新浪官方开始对已经公布的接口做出了多重限制&#xff0c;很多之前能用的功能现在都频频被限制&#xff0c;甚至有的时候接…

Sql Server 部署SSIS包完成远程数据传输

本篇介绍如何使用SSIS和作业完成自动更新目标数据任务。 ** 温馨提示&#xff1a;如需转载本文&#xff0c;请注明内容出处。** 本文链接:https://www.cnblogs.com/grom/p/9018978.html 笔者需要定期从服务器更新N家客户的远程服务器数据&#xff0c;上一篇的存储过程是其中一…

java值类型和引用类型 == 比较,Java中值类型和引用类型的比较与问题解决

一、问题描述前几天因为一个需求出现了Bug。说高级点也挺高级&#xff0c;说白点也很简单。其实也就是一个很简单的Java基础入门时候的值类型和引用类型的区别。只是开发的时候由于自己的问题&#xff0c;导致小问题的出现。还好突然想起来以前看过一篇对于该问题讲解的博客&am…

用最简单的例子说明设计模式(三)之责任链、建造者、适配器、代理模式、享元模式...

责任链模式一个请求有多个对象来处理&#xff0c;这些对象是一条链&#xff0c;但具体由哪个对象来处理&#xff0c;根据条件判断来确定&#xff0c;如果不能处理会传递给该链中的下一个对象&#xff0c;直到有对象处理它为止使用场景1)有多个对象可以处理同一个请求&#xff0…

利用Java针对MySql封装的jdbc框架类 JdbcUtils 完整实现(包含增删改查、JavaBean反射原理,附源码)...

最近看老罗的视频&#xff0c;跟着完成了利用Java操作MySQL数据库的一个框架类JdbcUtils.java,完成对数据库的增删改查。其中查询这块&#xff0c;包括普通的查询和利用反射完成的查询&#xff0c;主要包括以下几个函数接口: 1、public Connection getConnection() 获得数据库…

Linux启动提示Kernel panic - not syncing: Attempted to kill init解决办法

系统类型&#xff1a;CentOS 6.5(x64) 启动提示&#xff1a;Kernel panic - not syncing: Attempted to kill init 解决办法&#xff1a; 系统启动的时候&#xff0c;按下‘e’键进入grub编辑界面&#xff0c;编辑grub菜单&#xff0c;选择“kernel /vmlinuz-XXXXro root/dev/v…

vuex和vuejs

前言&#xff1a;在最近学习 Vue.js 的时候&#xff0c;看到国外一篇讲述了如何使用 Vue.js 和 Vuex 来构建一个简单笔记的单页应用的文章。感觉收获挺多&#xff0c;自己在它的例子的基础上进行了一些优化和自定义功能&#xff0c;在这里和大家分享下学习心得。 在这篇教程中我…

laravel mysql 配置,laravel5数据库配置及其注意事项

今天分享一个Laravel5数据库配置上的坑。Laravel5作为一套简洁、优雅的PHP Web开发框架(笑)&#xff0c;唯一不足的一点就是中文手册或者说是资料比较少&#xff0c;虽然现在很多大神也开始普及这些东西&#xff0c;但是大神一遍也会忽略一下小坑。今天配置了一下数据库&#x…

React开发中常用的工具集锦

本文从属于笔者的React入门与最佳实践系列。本文记录了笔者在React开发中常见的一些工具插件&#xff0c;如果你想寻找合适的项目生成器或者模板&#xff0c;请参考笔者的使用Facebook的create-react-app快速构建React开发环境 React Devtools React Devtools是React官方提供的…

9-[记录操作]--数据的增删改,权限管理

1、数据操作语言&#xff1a; DML&#xff08;data manage language&#xff09; 在MySQL管理软件中&#xff0c;可以通过SQL语句中的DML语言来实现数据的操作&#xff0c;包括 使用INSERT实现数据的插入UPDATE实现数据的更新使用DELETE实现数据的删除使用SELECT查询数据以及。…

hdu 1023 Train Problem II

题目连接 http://acm.hdu.edu.cn/showproblem.php?pid1212 Train Problem II Description As we all know the Train Problem I, the boss of the Ignatius Train Station want to know if all the trains come in strict-increasing order, how many orders that all the tra…

Nginx自建CDN加速节点 实现DNS智能解析网站项目

如今&#xff0c;网站项目越来越多的会使用CDN加速&#xff0c;如果需要便捷一点的可以直接用第三方提供的CDN加速服务&#xff0c;比如百度CDN、七牛、又拍云、腾讯云、阿里云等等服务商都有提供这类服务。但是前提条件是需要一定的成本&#xff0c;以及网站域名是需要BA才可以…