Android自定义可长按 可点击不可拖动的SeekBar

转载自:https://blog.csdn.net/yangbo437993234/article/details/51506895

项目中遇见一个奇怪的需求就是搜索栏不可点击,可长按和拉着拖拽点拖动。一开始想着很简单嘛。屏蔽吊点击事件,搜索栏自带长按事件,差不多就搞定了,然而是我太天真啊,搜索栏自带的长按监听是无效的。我通过网上查找资料有一些简单的方法实现不可单击的有实现长按的,然后我根据这些方式自己写了一个满足需求的自定义控件。现在依次说下吧 

。1.不可点击的SeekBar 
这个可以直接通过seekBar的监听修改SeekBar的进度让其达到显示的效果。 
可以重写SeekBar设置其setOnSeekBarChangeListener监听方法 
此方式点击SeekBar是触发了3个方法的只是进度条没让他跳过去而已 
可以看看打印的日志
 /**
 * 不可点击 长按无效的seekbar
 */
public class MySeekBar extends SeekBar  {
    private  int oldsign;

    public MySeekBar(Context context) {
        super(context);
        init();
    }
    public MySeekBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public MySeekBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    private void init() {
        setOnSeekBarChangeListener(new OnSeekBarChangeListener(){
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress,
                    boolean fromUser) {
                if(progress>oldsign+3||progress<oldsign-3){
                    seekBar.setProgress(oldsign);
                    return;
                }
                seekBar.setProgress(progress);
                oldsign = progress;
            }
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                seekBar.setProgress(oldsign);
            }
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }

        });
    }

}
  • 1
  • 2
  • 3
  • 4
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 三十
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

也可以直接在活动中用普通的搜索栏进行设置

        //sb为原生的SeekBar
        oldsign = sb.getProgress();
        sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener(){
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress,
                    boolean fromUser) {
//              Toast.makeText(MainActivity.this, "onProgressChanged"+progress, 0).show();
                Log.e("Chuck", "onProgressChanged");
                if(progress>oldsign+3||progress<oldsign-3){
                    seekBar.setProgress(oldsign);
                    return;
                }
                seekBar.setProgress(progress);
                oldsign = progress;
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                Log.e("Chuck", "onStartTrackingTouch");
                    seekBar.setProgress(oldsign);
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                Log.e("Chuck", "onStopTrackingTouch");
            }

        });
  • 1
  • 2
  • 3
  • 4
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

这样都是可以达到不可点击可拖拽的效果的,接下来看看可长按的SeekBar。 
长按监听的话是自己通过onTouch事件监听判断的然后写了一个接口把长按事件传递出来,详细代码如下:

public class SeekBarLongClick extends SeekBar implements OnTouchListener {

    private onLong longClick;
    private  int oldsign;//获取上次更改后的点击状态
    /**
     * 长按接口
     */
    public interface onLong {
        public boolean onLongClick(SeekBarLongClick seekBar);
    }

    private onChange SeekBarChange;

    /**
     * 进度改变接口
     */
    public interface onChange {
        public void onStopTrackingTouch(SeekBarLongClick seekBar);

        public void onStartTrackingTouch(SeekBarLongClick seekBar);

        public void onProgressChanged(SeekBarLongClick seekBar, int progress,
                                      boolean fromUser);
    }


    private Handler hand;
    private Runnable runable;
    private Thread th;
    public static int i = 0;
    private boolean isStop = false;
    public static int pp = 0;
    public int index = 0;

    public SeekBarLongClick(Context context) {
        this(context, null);
        // TODO Auto-generated constructor stub
    }

    public SeekBarLongClick(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setOnTouchListener(this);
        this.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                // TODO Auto-generated method stub
                if (SeekBarChange != null) {
                    SeekBarChange.onStopTrackingTouch(SeekBarLongClick.this);
                }
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                // TODO Auto-generated method stub
                seekBar.setProgress(oldsign);
                if (SeekBarChange != null) {
                    SeekBarChange.onStartTrackingTouch(SeekBarLongClick.this);
                }
            }

            @Override
            public void onProgressChanged(final SeekBar seekBar,
                    final int progress, boolean fromUser) {

                if(progress>oldsign+3||progress<oldsign-3){
                    seekBar.setProgress(oldsign);
                }else{
                seekBar.setProgress(progress);
                oldsign = progress;
                }
                if (SeekBarChange != null) {
                    SeekBarChange.onProgressChanged(SeekBarLongClick.this, oldsign,
                            fromUser);
                }
                hand = getHandler(1, SeekBarLongClick.this, oldsign);
            }
        });
        /**
         * 为runable 赋值
         */
        runable = new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                do {
                    i++;
                    try {
                        Thread.sleep(400);
                        Message msg = hand.obtainMessage();
                        msg.arg1 = i;
                        msg.sendToTarget();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                } while (isStop);
            }
        };
    }

    /**
     * 获取一个handler 对象
     * @param  j 0代表onTouch 1代表onChange
     * @param  v 视图对象
     * @param progress 进度
     * @return 返回一个handler对象
     */
    public Handler getHandler(final int j, final View v, final int progress) {
        Handler h = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (j) {
                case 0:
                    if (msg.arg1 == 3) {
                        if (longClick != null) {
                            longClick.onLongClick(SeekBarLongClick.this);
                            isStop = false;
                        }
                    }
                    break;
                case 1:
                    if (msg.arg1 == 1) {
                        pp = progress;
                    }
                    if (msg.arg1 == 2) {
                        if (pp != progress) {
                            i = 0;
                        }
                    }
                    if (msg.arg1 == 3) {
                        i = 0;
                        if (pp == progress) {
                            if (longClick != null) {
                                longClick.onLongClick(SeekBarLongClick.this);
                                isStop = false;
                            }
                        }
                    }
                    break;
                }
                super.handleMessage(msg);
            }
        };
        return h;
    }
    /**
     * 设置长按事件
     * @param longClick
     */
    public void setOnLongSeekBarClick(onLong longClick) {
        this.longClick = longClick;
    }

    /**
     * 设置进度改变事件
     * @param change
     */
    public void setOnSeekBarChange(onChange change) {
        this.SeekBarChange = change;
    }

    @Override
    public boolean onTouch(final View v, MotionEvent event) {
        // TODO Auto-generated method stub
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            float x2 = event.getX();
            float y2 = event.getY();

            isStop = true;
            th = new Thread(runable);
            th.start();
            i = 0;
            hand = getHandler(0, v, 0);
            break;
        case MotionEvent.ACTION_UP:
            isStop = false;
            break;
        }
        return false;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 三十
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183

接下来就是可长按可拖动不可触点,而且点击不会触发SeekBar监听的自定义SeekBar了。控件继承FrameLayout,在SeekBar上面盖上了一层透明的ImageView,通过ImageView的onTouch事件相应的对SeekBar进行操作,控件中还添加了一个添加关键点的功能,主要用于点击关键点时才跳到对应的进度,不添加关键点看起来用起来就和普通的seekbar一模一样。拖动进度是根据SeekBar控件的宽度来的,所以要计算一些坐标和控件宽高,使用时在Activity的onWindowFocusChanged()方法中设置。如果是固定宽度高可直接写死。详细代码如下:

public class SeekBarView extends FrameLayout {

    private onLong longClick; // 长按监听
    private MotionEvent motionEvent;// 移动监听的对象
    private float scale; // 当前比例
    private Context context;
    boolean isMove = false; // 当前是否是移动动作

    float xDown, yDown, xUp;
    private SeekBar seekBar;
    private ImageView image;
    private RelativeLayout rl_container;
    private int marginLeft;
    private int seekBarWidth;
    private int moveWidth;
    private boolean longClicked;
    /**
     * 长按接口
     * 
     * @author terry
     * 
     */
    public interface onLong {
        public boolean onLongClick(SeekBarView seekBar);
    }

    private onChange SeekBarChange;// SeekBar进度监听

    /**
     * 进度改变接口,仿SeekBar
     * 
     * @author terry
     * 
     */
    public interface onChange {
        public void onStopTrackingTouch(SeekBarView seekBar);

        public void onStartTrackingTouch(SeekBarView seekBar);

        /**
         * @param seekBar
         *            SeekBarView对象
         * @param progress
         *            进度条
         * @param fromUser
         *            只有拖动 为true,长按 不触发此方法,点击关键点为false.
         */
        public void onProgressChanged(SeekBarView seekBar, int progress,
                boolean fromUser);
    }

    public SeekBarView(Context context) {
        super(context);
    }

    public SeekBarView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        View view = LayoutInflater.from(context).inflate(R.layout.view_seekbar,
                null);
//      initView(view);
        addView(view);

    }

    public SeekBarView(Context context, AttributeSet attrs, int defStyle) {
        this(context, attrs);
    }

    public void initView(View view) {
        seekBarWidth = getWidth();
        int [] ints=new int[2];
        getLocationOnScreen(ints); 
        marginLeft = ints[0];

        DisplayMetrics displayMetrics = new DisplayMetrics();
        ((Activity) context).getWindowManager().getDefaultDisplay()
                .getMetrics(displayMetrics);
        moveWidth = seekBarWidth - dip2px(context, 20);
        // 播放时间为1000秒,
        seekBar = (SeekBar) view.findViewById(R.id.seekbar);
        scale = (float) seekBar.getMax() / (float) moveWidth;
        rl_container = (RelativeLayout) view.findViewById(R.id.rl_container);
        image = (ImageView) view.findViewById(R.id.image);
        //motionEvent获取到的是Activity 的 坐标······ 与Seekbar的坐标 x 有margin距离
        image.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                int x = (int) motionEvent.getX();
                if (Math.abs(x - xDown - marginLeft) < 10) {
                    seekBar.setProgress((int) ((int) (x - marginLeft) * scale));
                    isMove = false;
                    if (longClick != null) {
                        longClick.onLongClick(SeekBarView.this);
                        longClicked=true;
                    }
                }
                return false;
            }
        });
        image.setOnTouchListener(new View.OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {
                if (motionEvent == null) {
                    motionEvent = event;
                }
                // 当按下时处理
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    xDown = event.getX();
                    yDown = event.getY();

                }// 松开处理
                if (event.getAction() == MotionEvent.ACTION_UP) {
                    isMove = false;
                    xUp = event.getX();
                    if (SeekBarChange != null&&!longClicked) {
                        SeekBarChange.onStopTrackingTouch(SeekBarView.this);
                    }
                } else if (event.getAction() == MotionEvent.ACTION_MOVE) {

                    float x = event.getX();
                    final int progress = seekBar.getProgress();
                    // 如果点击位置是当前进度位置对应坐标的20px以内就认为点击到了当前位置 ,拖动可调整进度条
                    if (!isMove && Math.abs(progress - scale * xDown) <= 20) {
                        isMove = true;
                    }
                    if (isMove) {
                        seekBar.setProgress((int) (scale * x));
                        if (SeekBarChange != null) {
                            SeekBarChange.onProgressChanged(SeekBarView.this,
                                    (int) (scale * x), true);
                        }
                    } else {
                        // 其他模式
                    }
                }
                return false;
            }
        });
    }
    public void setMax(int max) {
        seekBar.setMax(max);
        scale= (float) seekBar.getMax() / (float) moveWidth ;
    }

    public int getMax() {
        return seekBar.getMax();
    }

    public void setProgress(int progress) {
        seekBar.setProgress(progress);
    }

    public int getProgress() {
        return seekBar.getProgress();
    }

    public void addKeyPoint(final int[] pointIndexs) {
        for (int i = 0; i < pointIndexs.length; i++) {
            final int tempI = i;
            ImageView imageView = new ImageView(context);
            int imgSize = dip2px(context, 20);
            RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(imgSize, imgSize);
            // 距离左边的位置···因为图标本身长度为20dp 所以这里需要减去10dp
            int marginLeft = (int) (pointIndexs[i] / scale);
            layoutParams.leftMargin = marginLeft;
            imageView.setLayoutParams(layoutParams);
            imageView.setImageResource(R.drawable.main_homework_up);
            imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
            rl_container.addView(imageView);
            imageView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    seekBar.setProgress(pointIndexs[tempI]);
                    if (SeekBarChange != null) {
                        SeekBarChange.onProgressChanged(SeekBarView.this,
                                pointIndexs[tempI], false);
                    }
                }
            });
        }
    }

    /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     */
    private int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    /**
     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
     */
    private int px2dip(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }
    /**
     * 设置长按事件
     * 
     * @param longClick
     */
    public void setOnLongSeekBarClick(onLong longClick) {
        this.longClick = longClick;
    }

    /**
     * 设置进度改变事件
     * 
     * @param change
     */
    public void setOnSeekBarChange(onChange change) {
        this.SeekBarChange = change;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 三十
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
//对应的xml布局
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
   <SeekBar
       android:progressDrawable="@drawable/seekbar_img"
        android:thumb="@drawable/public_play_volume_dragpoint"
        android:id="@+id/seekbar"
        android:background="#00ff0000"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:maxHeight="8dp"
        android:minHeight="8dp"
         android:layout_gravity="center"
        />
    <ImageView
        android:id="@+id/image"
         android:layout_gravity="center"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="#0000ff00"
  />
     <RelativeLayout
        android:background="#000000ff"
        android:id="@+id/rl_container"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_centerInParent="true"
        android:gravity="center_vertical"/>


</FrameLayout>
  • 1
  • 2
  • 3
  • 4
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 三十
  • 31
  • 32
  • 33
  • 34
//在Activity中调用
    /**
     * @param hasFocus
     *
     * 第一次界面渲染完成时 对自定义的SeekBarView进行初始化 和 测量。
     */
    boolean isOne=false;
    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        if(isOne){
            isOne=false;
            barView.initView(barView);
            barView.setMax(1000);
            //添加关键点。不添加即无效果
            barView.addKeyPoint(new int[]{100,300,620,530,1000,700});

            barView.setOnLongSeekBarClick(new SeekBarView.onLong() {
                @Override
                public boolean onLongClick(SeekBarView seekBar) {
                    Log.e("Chuck", "onLongClick() 方法触发  progress = " +seekBar. getProgress());
                    return false;
                }
            });
            barView.setOnSeekBarChange(new SeekBarView.onChange() {

                //手指离开屏幕,可能长按,可能拖动,判断按下屏幕之前 计时器的状态 进行相应的操作
                @Override
                public void onStopTrackingTouch(SeekBarView seekBar) {
                    Log.e("Chuck", "onStopTrackingTouch()方法触发    progress = " + seekBar.getProgress()); 
                    if(!playerTimer.isStarted()){
                           playerTimer.start();
                        }
                }
                @Override
                public void onStartTrackingTouch(SeekBarView seekBar) {
                }


                //fromUser 只有拖动的时候为true,长按不触发此方法,点击关键点时为false.
                @Override
                public void onProgressChanged(SeekBarView seekBar, int progress,
                        boolean fromUser) {
                    if(fromUser){
                        if(playerTimer.isStarted()){
                           playerTimer.stop();
                        }
                        tv.setText(progress+"----------------"+barView.getMax());
                    }

                    Log.e("Chuck", "onProgressChanged()方法触发  progress=" + progress + "  "+"fromUser="+fromUser );
                }
            });
            playerTimer.start();
        }
        super.onWindowFocusChanged(hasFocus);
    }
  • 1
  • 2
  • 3
  • 4
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 三十
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

最终的效果 
这里写图片描述

Demo下载地址(AndroidStudio写的比较大额) 
GitHub地址 
CSDN地址

猜你喜欢

转载自blog.csdn.net/jiankeufo/article/details/80597518