Android自定义双向滑动控件

本文实例为大家分享了Android自定义双向滑动控件的具体代码,供大家参考,具体内容如下

Posted in Java/Android onApril 19, 2022

先看一下效果图

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);
        }
    }
}

以上就是本文的全部内容。

Java/Android 相关文章推荐
Java基于字符界面的简易收银台
Jun 26 Java/Android
mybatis 解决从列名到属性名的自动映射失败问题
Jun 30 Java/Android
spring cloud gateway中如何读取请求参数
Jul 15 Java/Android
spring cloud 配置中心native配置方式
Sep 25 Java/Android
Java8中Stream的一些神操作
Nov 02 Java/Android
OpenCV实现反阈值二值化
Nov 17 Java/Android
JVM之方法返回地址详解
Feb 28 Java/Android
JavaWeb Servlet开发注册页面实例
Apr 11 Java/Android
详细介绍Java中的CyclicBarrier
Apr 13 Java/Android
mybatis-plus模糊查询指定字段
Apr 28 Java/Android
Java实现扫雷游戏详细代码讲解
May 25 Java/Android
利用Java连接Hadoop进行编程
Jun 28 Java/Android
java高级用法JNA强大的Memory和Pointer
Apr 19 #Java/Android
Java后端 Dubbo retries 超时重试机制的解决方案
Apr 14 #Java/Android
Java数组详细介绍及相关工具类
Apr 14 #Java/Android
Java8利用Stream对列表进行去除重复的方法详解
Apr 14 #Java/Android
详解Flutter网络请求Dio库的使用及封装
Apr 14 #Java/Android
详细介绍Java中的CyclicBarrier
Apr 13 #Java/Android
Java8 Stream API 提供了一种高效且易于使用的处理数据的方式
Apr 13 #Java/Android
You might like
无数据库的详细域名查询程序PHP版(3)
2006/10/09 PHP
一个用php实现的获取URL信息的类
2007/01/02 PHP
PHP学习之正则表达式
2011/04/17 PHP
php解析xml方法实例详解
2015/05/12 PHP
PHP7匿名类的用法示例
2019/04/05 PHP
PHP常用函数之base64图片上传功能详解
2019/10/21 PHP
关于PhpStorm设置点击编辑文件自动定位源文件的实现方式
2020/12/30 PHP
jQuery学习5 jQuery事件模型
2010/02/07 Javascript
潜说js对象和数组
2011/05/25 Javascript
JQuery+JS实现仿百度搜索结果中关键字变色效果
2011/08/02 Javascript
常常会用到的截取字符串substr()、substring()、slice()方法详解
2015/12/16 Javascript
基于JavaScript实现瀑布流效果(循环渐近)
2016/01/27 Javascript
JS基于构造函数实现的菜单滑动显隐效果【测试可用】
2016/06/21 Javascript
基于Angularjs+mybatis实现二级评论系统(仿简书)
2017/02/13 Javascript
令按钮悬浮在(手机)页面底部的实现方法
2017/05/02 Javascript
layui 监听表格复选框选中值的方法
2018/08/15 Javascript
webpack file-loader和url-loader的区别
2019/01/15 Javascript
Django中间件实现拦截器的方法
2018/06/01 Python
python打印异常信息的两种实现方式
2019/12/24 Python
Python3标准库glob文件名模式匹配的问题
2020/03/13 Python
基于SQLAlchemy实现操作MySQL并执行原生sql语句
2020/06/10 Python
详解python tkinter包获取本地绝对路径(以获取图片并展示)
2020/09/04 Python
详解canvas drawImage()方法绘制图片不显示的问题
2018/10/08 HTML / CSS
翻新二手苹果产品的网络领导者:Mac of all Trades
2017/12/19 全球购物
伦敦一家领先的精品零售商:IRIS Fashion
2019/05/24 全球购物
法国亚马逊官方网站:Amazon.fr
2020/12/19 全球购物
大学生职业生涯规划书的基本内容
2014/01/06 职场文书
前台文员我鉴定
2014/01/12 职场文书
中学生2014国庆节演讲稿:不屈的民族
2014/09/21 职场文书
2015年社区计生工作总结
2015/04/21 职场文书
新学期小学班主任工作计划
2019/06/21 职场文书
python四种出行路线规划的实现
2021/06/23 Python
MySQL数据库查询进阶之多表查询详解
2022/04/08 MySQL
阿里云国际版 使用Nginx作为HTTPS转发代理服务器
2022/05/11 Servers
详解Mysql数据库平滑扩容解决高并发和大数据量问题
2022/05/25 MySQL
如何利用python实现列表嵌套字典取值
2022/06/10 Python