Android自定义双向滑动控件
作者:抱着回忆旅行 发布时间:2022-04-30 04:11:18
标签:Android,滑动控件
本文实例为大家分享了Android自定义双向滑动控件的具体代码,供大家参考,具体内容如下
先看一下效果图
1.SeekBarPressure工具类
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.color.red);
hasScrollBarBg = resources.getDrawable(R.color.blue);
mThumbLow = resources.getDrawable(R.drawable.blue);
mThumbHigh = resources.getDrawable(R.drawable.red);
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_content
if (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_content
if (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(50);
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);
}
}
}
@Override
public 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.activity_main.xml 布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:background="#000"
android:orientation="vertical">
<com.yjjk.doubleseekbarsss.SeekBarPressure
android: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" />
<TextView
android:id="@+id/editTexts_min"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:textColor="#fff"></TextView>
<TextView
android:id="@+id/editTexts_max"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:textColor="#fff"></TextView>
</LinearLayout>
3.MainActivity
public class MainActivity extends AppCompatActivity {
private boolean isScreen;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//id
final SeekBarPressure seekBarPressures = findViewById(R.id.seekBar_tg2);
final TextView editTexts_min = findViewById(R.id.editTexts_min);
final TextView editTexts_max = findViewById(R.id.editTexts_max);
seekBarPressures.setOnSeekBarChangeListener(new SeekBarPressure.OnSeekBarChangeListener() {
@Override
public void onProgressBefore() {
isScreen = true;
}
@Override
public void onProgressChanged(SeekBarPressure seekBar, double progressLow, double progressHigh) {
editTexts_min.setText((int) progressLow + "");
editTexts_max.setText((int) progressHigh + "");
//获取SharedPreferences对象
SharedPreferences sharedPre=getSharedPreferences("config", MODE_PRIVATE);
//获取Editor对象
SharedPreferences.Editor edit = sharedPre.edit();
edit.clear();
//设置参数
edit.putString("progressHigh", String.valueOf(progressHigh));
edit.putString("progressLow", String.valueOf(progressLow));
//提交
edit.commit();
}
@Override
public void onProgressAfter() {
isScreen = false;
}
});
//取值
SharedPreferences sharedPre=getSharedPreferences("config",MODE_PRIVATE);
String progressHighs = sharedPre.getString("progressHigh", "");
String progressLows = sharedPre.getString("progressLow", "");
if (progressHighs.length()!=0){
seekBarPressures.setProgressHigh(Double.parseDouble(progressHighs));
seekBarPressures.setProgressLow(Double.parseDouble(progressLows));
editTexts_max.setText(progressHighs);
editTexts_min.setText(progressLows);
}else {
seekBarPressures.setProgressLow(30);
seekBarPressures.setProgressHigh(70);
editTexts_min.setText("最小值:"+30);
editTexts_max.setText("最大值:"+70);
}
}
}
来源:https://blog.csdn.net/weixin_42630638/article/details/108751790
0
投稿
猜你喜欢
- 一、稀疏数组1、什么是稀疏数组当一个数组中大部分元素为0,或者为同一个值的数组时,可以用稀疏数组来保存该数组。稀疏数组,记录一共有几行几列,
- 文章主要涉及到以下几个问题:怎么实现Java的序列化为什么实现了java.io.Serializable接口才能被序列化transient的
- 参考 java查找无向连通图中两点间所有路径的算法,对代码进行了部分修改,并编写了测试用例。算法要求:1. 在一个无向连通图中求出
- EntityWrapper的常用方法#WHERE (issue_type = ?) AND (status = ? OR status =
- 前言随着敏捷开发的流行,编写单元测试已经成为业界共识。但如何来衡量单元测试的质量呢?有些管理者片面追求单元测试的数量,导致底下的开发人员投机
- 自动登录,是为了帮助用户多次使用这个网页时,不用再次输入用户名和密码就可以登录。自动登录是指用户将用户的登录信息,人,保存到本地的文件中Co
- springBoot所有依赖和配置文件都写好的情况下1、dao接口的实现方法package com.cy.pj.sys.dao;import
- 今天新建项目的时候突然发现编译后运行按钮为灰色。解决方案:第一步:点击图中的Add Configuration,出来如下界面第二步:点+号,
- SpringBoot读取外置logback配置文件springboot项目可以读取外置配置文件,避免了修改配置文件需要重新打包部署的问题。部
- 一、程序运行环境编译环境:IntelliJ IDEA所需测试文件:PDF、.pfx数字证书及密钥、PDF Jar包(Free Spire.P
- 一直使用Eclipse环境开发Android,也尝鲜使用过Android Studio去开发,各种IDE配合Android SDK及SDK原
- 1、锁优化在JDK6之前,通过synchronized来实现同步效率是很低的,被synchronized包裹的代码块经过javac编译后,会
- FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文传协议”。用于Internet上的控制文件
- 在使用他人代码时,为不保留文件头部版权信息,需要一个个删掉,费时费力,写了个脚本,简单清除掉目录下所有的文件的头部版权信息。# -*- co
- 前言最近新整了个博客网站,同事在gitee上找的,还不错,gitee上的地址在这里:拾壹博客管理系统。别人的业务,再好也有不满足自己的地方,
- 我们在编写完Spring的代码后,往往需要测试代码的正确性,这个时候就需要用到单元测试了。我们这里使用的版本是junit4.一个程序的入口是
- 本文实例讲述了Java实现的zip工具类。分享给大家供大家参考,具体如下:实现把zip解压到指定路径,把文件夹压缩到zip,把文件列表压缩为
- 功能介绍功能:群聊+私发+上线提醒+下线提醒+查询在线用户文件Utils需要用maven导入下面两个包 <dependency>
- 参考文献:https://www.jb51.net/article/232858.htm使用springboot 2 构建项目,调试代码的时
- 最近在鼓捣spring -boot ,真好用,学习到jpa.通过生成Entity 文件,能够快速的生成数据库,并且使用JpaReposito