在商顯懸浮按鈕開發過程中遇到的問題,懸浮按鈕即要實現隨手指移動而移動(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;
}
});