android layout 点击,Tips_Android点击事件(Down、Move、Up)的分发_重写Layout响应拖动事件...
首先是點(diǎn)擊事件在不同的布局層次中傳遞的。
理解Down事件再哪個(gè)層次被消費(fèi)(攔截),后續(xù)的Move、Up的點(diǎn)擊事件如何傳遞。
其中ViewGroup中onInterceptTouchEvent方法用來(lái)對(duì)事件作預(yù)處理的,對(duì)于Down事件返回true表示要消費(fèi)這個(gè)事件,不再向子View傳遞。
onInterceptTouchEvent用于改變事件的傳遞方向。決定傳遞方向的是返回值,返回為false時(shí)事件會(huì)傳遞給子控件,返回值為true時(shí)事件會(huì)傳遞給當(dāng)前控件的onTouchEvent(),這就是所謂的Intercept(攔截)。
[tisa ps:正確的使用方法是,在此方法內(nèi)僅判斷事件是否需要攔截,然后返回。即便需要攔截也應(yīng)該直接返回true,然后由onTouchEvent方法進(jìn)行處理。]
onTouchEvent用于處理事件,返回值決定當(dāng)前控件是否消費(fèi)(consume)了這個(gè)事件。尤其對(duì)于ACTION_DOWN事件,返回true,表示我想要處理后續(xù)事件;返回false,表示不關(guān)心此事件,并返回由父類(lèi)進(jìn)行處理。
可能你要問(wèn)是否消費(fèi)了又區(qū)別嗎,反正我已經(jīng)針對(duì)事件編寫(xiě)了處理代碼?答案是有區(qū)別!比如ACTION_MOVE或者ACTION_UP發(fā)生的前提是一定曾經(jīng)發(fā)生了ACTION_DOWN,如果你沒(méi)有消費(fèi)ACTION_DOWN,那么系統(tǒng)會(huì)認(rèn)為ACTION_DOWN沒(méi)有發(fā)生過(guò),所以ACTION_MOVE或者ACTION_UP就不能被捕獲。
在沒(méi)有重寫(xiě)onInterceptTouchEvent()和onTouchEvent()的情況下(他們的返回值都是false),?對(duì)上面這個(gè)布局,MotionEvent事件的傳遞順序如下:
當(dāng)某個(gè)控件的onInterceptTouchEvent()返回值為true時(shí),就會(huì)發(fā)生截?cái)?#xff0c;事件被傳到當(dāng)前控件的onTouchEvent()。如我們將LayoutView2的onInterceptTouchEvent()返回值為true,則傳遞流程變成:
如果我們同時(shí)將LayoutView2的onInterceptTouchEvent()和onTouchEvent()設(shè)置成true,那么LayoutView2將消費(fèi)被傳遞的事件,同時(shí)后續(xù)事件(如跟著ACTION_DOWN的ACTION_MOVE或者ACTION_UP)會(huì)直接傳給LayoutView2的onTouchEvent(),不傳給其他任何控件的任何函數(shù)。同時(shí)傳遞給子空間一個(gè)ACTION_CANCEL事件。傳遞流程變成(圖中沒(méi)有畫(huà)出ACTION_CANCEL事件):
?? ? ? ??
[tisa ps:總體來(lái)看,?onInterceptTouchEvent是自rootview向下傳遞, onTouchEvent正好相反。]
基于以上點(diǎn)擊事件的傳遞,可以重寫(xiě)一些ViewGroup,響應(yīng)其拖動(dòng)的事件,比如LinearLayout,重寫(xiě)其onInterceptTouchEvent()和onTouchEvent()兩個(gè)方法可以達(dá)到效果(具體看實(shí)際布局中子view對(duì)事件的消費(fèi)情況而定)
//true是攔截,false是不攔截。這里只是預(yù)處理判斷點(diǎn)擊的位置,不攔截。
@Override
public?boolean?onInterceptTouchEvent(MotionEvent?ev)?{
if?(ev.getAction()?==?MotionEvent.ACTION_DOWN)?{
int?x?=?(int)?ev.getX();
int?y?=?(int)?ev.getY();
dragSrcPointY?=?y;
FTLog.d(_TAG,?"x="?+?x?+?",y="?+?y);
}
return?super.onInterceptTouchEvent(ev);
}
@Override
public?boolean?onTouchEvent(MotionEvent?ev)?{
//只有判斷是點(diǎn)擊觸發(fā)拖動(dòng)的區(qū)域時(shí),才進(jìn)行處理。否則不處理,交予FTBounceListView舊邏輯處理。
int?action?=?ev.getAction();
switch?(action)?{
case?MotionEvent.ACTION_DOWN:
//FTLog.e("TMS===down==",?"tms");
//bConsumeDown?=?true;
return?true;
//case?MotionEvent.ACTION_MOVE:
//FTLog.e("TMS===move==",?"tms");
//if?(bConsumeDown?==?false)
//{
//super.onTouchEvent(ev);
//}
//break;
case?MotionEvent.ACTION_UP:
FTLog.d(_TAG,?"x="+ev.getX()+",y="+ev.getY());
if?(ev.getY()?
{//向上拖動(dòng)距離超過(guò)20dip,才finish,動(dòng)畫(huà)效果。
try?{
((Activity)?context).finish();
((Activity)?context).overridePendingTransition(
R.anim.move_bottom_in,?R.anim.move_top_out);
}?catch?(Exception?e)?{
e.printStackTrace();
}
}
return?true;
default:
break;
}
return?super.onTouchEvent(ev);
}
其他視具體情況而定,比如listview的最后一條,某中間區(qū)域響應(yīng)拖動(dòng)的事件:
//true是攔截,false是不攔截。這里只是預(yù)處理判斷點(diǎn)擊的位置,不攔截。
@Override
public?boolean?onInterceptTouchEvent(MotionEvent?ev)?{
if?(ev.getAction()?==?MotionEvent.ACTION_DOWN)?{
bConsumeDown?=?false;
int?x?=?(int)?ev.getX();
int?y?=?(int)?ev.getY();
dragSrcPosition?=?pointToPosition(x,?y);
dragSrcPointY?=?y;
if?(dragSrcPosition?==?AdapterView.INVALID_POSITION)?{
return?super.onInterceptTouchEvent(ev);
}
FTLog.d(_TAG,?"x="?+?x?+?",y="?+?y);
FTLog.d(_TAG,?"dragSrcPosition=="?+?dragSrcPosition
+?"getAdapter().getCount()=="?+?getAdapter().getCount());
if?(dragSrcPosition?==?getAdapter().getCount()?-?1
||?dragSrcPosition?==?getAdapter().getCount()?-?2)
{//?最后一條是footer,倒數(shù)第二條是數(shù)據(jù)
ViewGroup?itemView?=?(ViewGroup)?getChildAt(dragSrcPosition
-?getFirstVisiblePosition());
int?itemLeft?=?itemView.getLeft();
int?itemRight?=?itemView.getRight();
int?itemMid?=?(itemRight?+?itemLeft)?/?2;
FTLog.d(_TAG,?"itemLeft=="?+?itemLeft?+?",?itemRight="
+?itemRight?+?",itemMid="?+?itemMid);
if?(x?>?itemMid?-?60?&&?x?
bConsumeDown?=?true;//預(yù)處理,判斷是點(diǎn)擊觸發(fā)拖動(dòng)的區(qū)域,并不攔截事件
return?false;
}
}
}
return?super.onInterceptTouchEvent(ev);
}
/**
*?觸摸事件
*/
@Override
public?boolean?onTouchEvent(MotionEvent?ev)?{
if?(bConsumeDown?==?true?&&?dragSrcPosition?!=?INVALID_POSITION)?{
//只有判斷是點(diǎn)擊觸發(fā)拖動(dòng)的區(qū)域時(shí),才進(jìn)行處理。否則不處理,交予FTBounceListView舊邏輯處理。
int?action?=?ev.getAction();
switch?(action)?{
case?MotionEvent.ACTION_DOWN:
//FTLog.e("TMS===down==",?"tms");
//bConsumeDown?=?true;
break;
//case?MotionEvent.ACTION_MOVE:
//FTLog.e("TMS===move==",?"tms");
//if?(bConsumeDown?==?false)
//{
//super.onTouchEvent(ev);
//}
//break;
case?MotionEvent.ACTION_UP:
FTLog.d(_TAG,?"x="+ev.getX()+",y="+ev.getY());
if?(ev.getY()?
{//向上拖動(dòng)距離超過(guò)20dip,才finish,動(dòng)畫(huà)效果。
try?{
((Activity)?context).finish();
((Activity)?context).overridePendingTransition(
R.anim.move_bottom_in,?R.anim.move_top_out);
}?catch?(Exception?e)?{
e.printStackTrace();
}
}
break;
default:
break;
}
return?true;
}
return?super.onTouchEvent(ev);
}
以上重寫(xiě)ViewGroup的兩個(gè)方法,對(duì)于具體的View來(lái)講,可以setOnTouchLinstener方法,再其OnTouch方法中,用mGestureDetectorOpen.onTouchEvent(event);來(lái)響應(yīng)。
_imageview_room_op_item_open.setOnTouchListener(new?OnTouchListener()?{
@Override
public?boolean?onTouch(View?v,?MotionEvent?event)?{
mGestureDetectorOpen.onTouchEvent(event);
return?true;
}
});
mGestureDetectorOpen?=?new?GestureDetector(this,?new?OnGestureListener()
{
@Override
public?boolean?onFling(MotionEvent?e1,?MotionEvent?e2,?float?velocityX,
float?velocityY)?{//判斷在_imageview_room_op_item_open控件上移動(dòng)的距離,do?something}
}
總結(jié)
以上是生活随笔為你收集整理的android layout 点击,Tips_Android点击事件(Down、Move、Up)的分发_重写Layout响应拖动事件...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: linux 编程博客,Linux系统编程
- 下一篇: android 百度大头针,百度地图所有