Android自定义可长按 可点击不可拖动的SeekBar
来源:互联网 发布:mac webstorm使用 编辑:程序博客网 时间:2024/06/05 03:45
项目中遇见一个奇怪的需求 就是SeekBar不可点击 ,可长按 和拉着拖拽点拖动。一开始想着很简单嘛。屏蔽吊点击事件,SeekBar自带长按事件,差不多就搞定了,然而是我太天真啊,SeekBar自带的长按监听是无效的。我通过网上查寻资料 有一些简单的方法实现不可单击的 有实现长按的,然后我根据这些方式自己写了一个 满足需求的自定义控件。现在依次说下吧。
1. 不可点击的SeekBar
这个可以直接通过seekBar的监听 修改SeekBar的进度 让其达到显示的效果。
可以重写SeekBar 设置其setOnSeekBarChangeListener监听方法
此方式点击SeekBar是触发了 3个方法的 只是进度条没让他跳过去而已
可以看看打印的Log
/** * 不可点击 长按无效的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) { } }); }}
也可以直接在Activity中用普通的SeekBar进行设置
//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"); } });
这样都是可以达到 不可点击 可拖拽的效果的,接下来看看 可长按的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; }}
接下来就是可长按 可拖动 不可点击,而且点击不会触发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; }}
//对应的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>
//在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); }
最终的效果
Demo下载地址(AndroidStudio写的比较大额)
GitHub地址
CSDN地址
- Android自定义可长按 可点击不可拖动的SeekBar
- android自定义进度值可拖动的seekbar
- Android 可拖动进度条:SeekBar之自定义进度条
- Android 可拖动进度条:SeekBar之自定义进度条
- android 自定义SeekBar(拖动条)
- Android 可拖动的进度条:SeekBar之简单使用
- 自定义漂亮的Android SeekBar(拖动条)样式
- android EditText 的不可编辑可点击
- 使用SeekBar制作可拖动的进度条
- 带标题可拖动的SeekBar
- 使用SeekBar制作可拖动的进度条
- Android 简单实现可全屏拖动,可点击的View
- Android拖动控件的实现,自定义可拖动的LinearLayout
- Android 可拖动可点击悬浮窗
- Android SeekBar 禁止拖动和点击的实现(可能是最简单完美的实现)
- Android入门(37)——第十四章 使用SeekBar制作可拖动的进度条
- Android-基本控件(SeekBar 可拖动 滚动条的使用)
- Android自定义可拖动进度条
- Cannot make a static reference to the non-static method getLocalActivityManager() from the type Acti
- 从svn下载项目后build path替灰色,应该如何解决呢?
- iOS CocoaPods安装和使用
- IOS页面跳转卡顿问题
- Matlab 笔记之6
- Android自定义可长按 可点击不可拖动的SeekBar
- android log丢失研究
- 缓存策略在工作上的实际应用
- 自定义的webview
- cf676c Vasya and String 尺取法裸题
- 实现View滑动的3种方法
- 关于程序设计中INF和MOD值的设定
- codeforces #Round354-div2-B
- struts2+spring+hibernate整合步骤《开源》