在商显悬浮按钮开发过程中遇到的问题,悬浮按钮即要实现随手指移动而移动(onTouch),也要实现点击事件(onClick事件),这里会遇到一个问题,在onTouch方法return false的时候,在滑动过程中抬起的时候会触发 MotionEvent.ACTION_UP 事件,同时也会触发onClick事件,如果onTouch方法return true,则view的onClick事件不会执行。
通过查看View的源码,View的listener都存在一个静态内部类里面,
static class ListenerInfo {
/**
* Listener used to dispatch focus change events.
* This field should be made private, so it is hidden from the SDK.
* {@hide}
*/
protected OnFocusChangeListener mOnFocusChangeListener;
/**
* Listeners for layout change events.
*/
private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;
protected OnScrollChangeListener mOnScrollChangeListener;
/**
* Listeners for attach events.
*/
private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners;
/**
* Listener used to dispatch click events.
* This field should be made private, so it is hidden from the SDK.
* {@hide}
*/
public OnClickListener mOnClickListener;
/**
* Listener used to dispatch long click events.
* This field should be made private, so it is hidden from the SDK.
* {@hide}
*/
protected OnLongClickListener mOnLongClickListener;
/**
* Listener used to dispatch context click events. This field should be made private, so it
* is hidden from the SDK.
* {@hide}
*/
protected OnContextClickListener mOnContextClickListener;
/**
* Listener used to build the context menu.
* This field should be made private, so it is hidden from the SDK.
* {@hide}
*/
protected OnCreateContextMenuListener mOnCreateContextMenuListener;
private OnKeyListener mOnKeyListener;
private OnTouchListener mOnTouchListener;
private OnHoverListener mOnHoverListener;
private OnGenericMotionListener mOnGenericMotionListener;
private OnDragListener mOnDragListener;
private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;
OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;
}
ListenerInfo mListenerInfo;
通过反射获取mListenerInfo实例,再获取mListenerInfo里面的mOnClickListener,最后调用mOnClickListener.onClick()方法即可,修改后的onTouch代码如下
button.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN: {
Log.i("mandroid.cn", "button按下");
//记录按下时的位置
x = motionEvent.getRawX();
y = motionEvent.getRawY();
break;
}
case MotionEvent.ACTION_MOVE: {
Log.i("mandroid.cn", "button移动");
break;
}
case MotionEvent.ACTION_UP: {
//检测移动的距离,如果很微小可以认为是点击事件
if (Math.abs(motionEvent.getRawX() - x) < 10 && Math.abs(motionEvent.getRawY() - y) < 10) {
try {
Field field = View.class.getDeclaredField("mListenerInfo");
field.setAccessible(true);
Object object = field.get(view);
field = object.getClass().getDeclaredField("mOnClickListener");
field.setAccessible(true);
object = field.get(object);
if (object != null && object instanceof View.OnClickListener) {
((View.OnClickListener) object).onClick(view);
}
} catch (Exception e) {
}
} else {
Log.i("mandroid.cn", "button已移动");
}
break;
}
}
return true;
}
});