Android的自定义长按
16lz
2021-01-23
android的弹出菜单,使用activity来实现,但是长按的时间太短,容易与其他view的触摸逻辑相冲突,代码如下
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_draw); //其他代码 _view.setOnCreateContextMenuListener(this); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { menu.add(1, 10001, 0, "添加"); menu.add(1, 10002, 1, "删除"); menu.add(1, 10003, 2, "切换"); super.onCreateContextMenu(menu, v, menuInfo); } @Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case 10001: { //添加 break; } case 10002: { //删除 break; } case 10003: { //切换; break; } default: break; } return super.onContextItemSelected(item); }
为此,我们需要对长按进行额外的处理,于是需要对_view的onTouch事件进行相应的处理,为了便于调用,将长按的检测逻辑封装成了相应的类,代码如下
/** * 长按工作器 */ class LongTouchWorker{ /** * 长按时两次点差的最大偏移量,超过此偏移量则不是长按 */ private int _longTouchOffset = 50; private int _lastMotionX; private int _lastMotionY; private int _longTouchDelay_ms; private LongTouchCallback _longTouchCallback=null; public LongTouchWorker(int longTouchDelay_ms,LongTouchCallback longTouchCallback){ _longTouchDelay_ms =longTouchDelay_ms; _longTouchCallback=longTouchCallback; } private Handler _longTouchHandle=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); Log.d(TAG,"LongTouchHandle"); } }; private Runnable _longTouchRunnable=new Runnable() { @Override public void run() { if(_longTouchCallback!=null) { _longTouchCallback.longTouch(_lastMotionX,_lastMotionY); } } }; public void onTouch(View v, MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); int pointerCount = event.getPointerCount(); if(pointerCount>1){ //多点触控,直接取消长按 cancelLongTouch(); } else { switch (event.getAction()) { case MotionEvent.ACTION_UP: // 弹起时,移除已有Runnable回调,弹起就算长按结束了(不需要考虑用户是否长按了超过预设的时间) cancelLongTouch(); Log.d(TAG, "LongTouch UP"); break; case MotionEvent.ACTION_MOVE: if (Math.abs(_lastMotionX - x) > _longTouchOffset || Math.abs(_lastMotionY - y) > _longTouchOffset) { // 移动误差阈值 // xy方向判断 // 移动超过阈值,则表示移动了,就不是长按(看需求),移除 已有的Runnable回调 cancelLongTouch(); } Log.d(TAG, "LongTouch Move"); break; case MotionEvent.ACTION_DOWN: // 每次按下重新计时 // 按下前,先移除 已有的Runnable回调,防止用户多次单击导致多次回调长按事件的bug cancelLongTouch(); _lastMotionX = x; _lastMotionY = y; // 按下时,开始计时 _longTouchHandle.postDelayed(_longTouchRunnable, _longTouchDelay_ms); Log.d(TAG, "LongTouch Down"); break; } } } private void cancelLongTouch(){ _longTouchHandle.removeCallbacks(_longTouchRunnable); if(_longTouchCallback!=null){ _longTouchCallback.cancelLongTouch(); } } } /** * 长按的回调 */ public interface LongTouchCallback{ /** * 取消长按 */ void cancelLongTouch(); /** * 长按 */ void longTouch(int x,int y); }
在LongTouchWorker中通过onTouch的检测来判断是否为长按,判断过程要注意几点
1.弹起(UP)、按下(DOWN)、移动(MOVE)的逻辑,尤其是MOVE时要设置感应的偏移量,因为手指按下时,点的位置是有可能偏移的。
2.Handle和Runnable的配合,remove和postDelay的控制
3.通过接口LongTouchCallback来回调,触发相应的longTouch和cancelLongTouch事件。
那要如何使用LongTouchWorker呢?假如我们的view是自定义的,比如LongTouchView,在LongTouchView的onTouch事件调用LongTouchWorker,示例代码如下
/** * 自定义LongTouchView */public class LongTouchView extends View { private LongTouchWorker _longTouchWorker=null; /** * 设置长按工作器 * @param longTouchDelay_ms 长按的延迟时间(毫秒) * @param longTouchCallback 长按的回调 */ public void set_longTouchWorker(int longTouchDelay_ms,LongTouchCallback longTouchCallback){ _longTouchWorker=new LongTouchWorker(longTouchDelay_ms,longTouchCallback); }@Override public boolean onTouchEvent(MotionEvent event) { if( _longTouchWorker!=null) { _longTouchWorker.onTouch(this,event); } return super.onTouchEvent(event); }}
有了LongTouchWorker之后,我们就可以解决前面弹出菜单时,长按时间太短的问题,示例代码如下
_longTouchView.set_longTouchWorker(_longTouchDelay_ms, new LongTouchCallback() { @Override public void cancelLongTouch() { } @Override public void longTouch(int x, int y) { showPopupMenu(x, y); } });
对于showPopupMenu弹出菜单的位置控制,可以参看《PopupMenu弹出位置的控制》
更多相关文章
- Android发送短信功能代码
- [置顶] Android源代码下载
- Android 代码混淆 选项说明
- 反抗金山毒霸的代码
- Android应用程序组件Content Provider的启动过程源代码分析(2)
- android开发之res下的menu (xml+代码的形式)
- 【源代码】一键分享各个社交平台_android
- Android常用框架混淆代码
- Android之GLES2.0显示图片测试代码