編輯:關於Android編程
1.android布局層次
在我們的布局之上還存在四層布局, 所以我們應該減少布局的嵌套
2.事件分發
Android 中與 Touch 事件相關的方法包括:dispatchTouchEvent(MotionEvent ev)、onInterceptTouchEvent(MotionEvent ev)、onTouchEvent(MotionEvent ev);能夠響應這些方法的控件包括:ViewGroup 及其子類、Activity。
@1
其中:
dispatchTouchEvent(MotionEvent ev) 事件分發 Activity ViewGroup View 都有此方法
onInterceptTouchEvent(MotionEvent ev) 事件攔截 ViewGroup 有此方法
onTouchEvent(MotionEvent ev) 事件響應 Activity ViewGroup View 都有此方法
onTouch:
onTouch()是OnTouchListener接口的方法,它是獲取某一個控件的觸摸事件,因此使用時,必須使用setOnTouchListener綁定到控件,然後才能鑒定該控件的觸摸事件。當一個View綁定了OnTouchLister後,當有touch事件觸發時,就會調用onTouch方法。通過getAction()方法可以獲取當前觸摸事件的狀態:
ACTION_DOWN:表示按下了屏幕的狀態。
ACTION_MOVE :表示為移動手勢
ACTION_UP :表示為離開屏幕
ACTION_CANCEL :表示取消手勢,不會由用戶產生,而是由程序產生的
onTouch方法的優先級高於onTouchEvent。當onTouch 方法返回true時,會進行觸摸事件處理,onTouchEvent不會處理。當onTouch返回false的時候,onTouchEvent擦會處理
@2
正常情況下:activitydispatchTouchEvent -->> layoutdispatchTouchEvent ->> buttondispatchTouchEvent -->button onTouchevent
@--1當被onInterceptTouchEvent攔截時,會執行當前的onTouchEvent
@--2 當onTouchEvent 返回false時,返回給上一層的onTouchEvent ,如果還返回false,繼續返回上一層的onTouchEvent ,直至拋出
事件分發:public boolean dispatchTouchEvent(MotionEvent ev)
當有監聽到事件時,首先由Activity的捕獲到,進入事件分發處理流程。無論是Activity還是View,如前文所說,事件分發自身也具有消費能力,
如果事件分發返回true,表示改事件在本層不再進行分發且已經在事件分發自身中被消費了。至此,事件已經完結。如果你不想Activity中的任何控件具有任何的事件消費能力,
最簡答的方法可以重寫此Activity的dispatchTouchEvent方法,直接返回true就ok。
如果事件分發返回 false,表明事件在本層不再繼續進行分發,並交由上層控件的onTouchEvent方法進行消費。
當然了,如果本層控件已經是Activity,那麼事件將被系統消費或處理。
如果事件分發返回系統默認的 super.dispatchTouchEvent(ev),事件將分發給本層的事件攔截onInterceptTouchEvent 方法進行處理
(如果本層控件是Activity,由於其沒有事件攔截,因此將直接將事件傳遞到子View,並交給子View的事件分發進行處理)。
事件攔截:public boolean onInterceptTouchEvent(MotionEvent ev)
如果 onInterceptTouchEvent 返回 true,則表示將事件進行攔截,並將攔截到的事件交由本層控件 的 onTouchEvent 進行處理;
如果返回結果是false;則表示不對事件進行攔截,事件得以成功分發到子View。並由子View的dispatchTouchEvent進行處理。
如果返回super.onInterceptTouchEvent(ev),事件默認不會被攔截,交由子View的dispatchTouchEvent進行處理。
事件響應:public boolean onTouchEvent(MotionEvent ev)
在 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev) 並且 onInterceptTouchEvent 返回 true 或返回 super.onInterceptTouchEvent(ev) 的情況下 onTouchEvent 會被調用。
onTouchEvent 的事件響應邏輯如下:
如果事件傳遞到當前 View 的 onTouchEvent 方法,而該方法返回了 false,那麼這個事件會從當前 View 向上傳遞,並且都是由上層 View 的 onTouchEvent 來接收,如果傳遞到上面的 onTouchEvent 也返回 false,這個事件就會“消失”,而且接收不到下一次事件。
如果返回了 true 則會接收並消費該事件。
如果返回 super.onTouchEvent(ev) 默認處理事件的邏輯和返回 false 時相同。
(我個人的判斷是最裡面的 返回false 則 其上層所有的onTouchEvent的的super 默認為false)
ScrollView 和 ListView的沖突(@1 ScrollView 嵌套Listview @2 ScrollView 嵌套一個ScrollView)
@1 ScrollView 嵌套一個ListView
原因:
@1. 因為ListView需要支持長按操作,所以ListView本身的ACTION_MOVE,會有一定的初始距離檢測,小於這個距離,代表沒有移動,只有從按下到移動之間坐標位置相差大 一點,才回認為ListView需要移動;
@2. ScrollView 在檢測滾動事件的時候,如果ScrollView的內容的高度>ScrollView顯示的高度,就認為內部的內容可以滾動,是整體滾動;ScrollView在上下滾動的時候如果 DOWN的位置與當前MOVE的位置相差很小,認為沒有滾動;
@3. 當按下位置與移動的位置超過一個固定的距離之後,ScrollView再分發事件的時候,就會檢測出可以滾動,那麼因為ScrollView內容高度可以滾動,那麼就直接滾動自身 內 容,而不把滾動事件,傳遞給ListView了
@4. 根據代碼的分析,ScrollView判斷是否開始滾動,采用的是 滾動幅度是否大於8dp的方式,ListView也是采用滾動幅度>8dp的檢測;只要>8的時候,ScrollView就會先收到 事件,然後把事件就給攔截了;不再給 ListView 了;
解決方案:
@1. 重寫 ListView 的 onMeasure() 讓ListView計算自身所有內容的高度,全部填滿ScrollView
@2. 這種方案會產生效率的問題,因為一次會把所有的Item全部顯示出來;沒有復用;一定要注意,通常都是顯示簡單的文字信息和小圖片;
@3. ListView在ScrollView中,高度測量的時候,傳遞的模式就是 “未指定”,所以ListView默認就會計算一行的高度;
@4. 解決方案就是在ListView計算尺寸之前,強制把 未指定 調整為AT_MOST, 指定的高度可以是一個非常大的數值,這樣全部顯示出來;
不可取的方法(原因:需要計算出ListView的高度,全部展現出來,這就有一個隱患:不敢加圖片 否則卡出翔)
原始方法,易理解:
要在listView添加完adapter後 計算高度,在之前好像貌似沒用
public static void setListViewHeight(ListView listView){ if (listView == null){ return; } ListAdapter adapter = listView.getAdapter(); if (adapter == null) { return; } int Height = 0; /** * 內容的長度 */ for (int i = 0; i < adapter.getCount(); i++) { View adapterView = adapter.getView(i, null, listView); adapterView.measure(0,0); Height += adapterView.getMeasuredHeight(); } ViewGroup.LayoutParams params = listView.getLayoutParams(); /** * (listView.getDividerHeight()*(adapter.getCount() - 1) * ListView各個item的間隙長度 */ params.height = Height + (listView.getDividerHeight()*(adapter.getCount() - 1)); listView.setLayoutParams(params); }簡單方法,只需要重寫ListView裡的onMeasure方法即可
package com.treasure_ct.android_xt.seniorcontrols.eventdistribution.widgets; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.AbsListView; import android.widget.ListView; /** * Created by treasure on 2016.09.27. */ public class MyListView extends ListView{ public MyListView(Context context) { super(context); } public MyListView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int spec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, spec); } }
重寫ListView裡的onInterceptTouchEvent方法
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: setParentScrollAble(false);//手指觸到listview的時候,讓父ScrollView交出ontouch權限,也就是讓父scrollview停住不能滾動 Log.d(TAG, "onInterceptTouchEvent: down"); break; case MotionEvent.ACTION_MOVE: Log.d(TAG, "onInterceptTouchEvent: move"); break; case MotionEvent.ACTION_UP: Log.d(TAG, "onInterceptTouchEvent: up"); break; case MotionEvent.ACTION_CANCEL: setParentScrollAble(true);//當手指松開時,讓父ScrollView重新拿到onTouch權限 Log.d(TAG, "onInterceptTouchEvent: cancel"); break; default: break; } return super.onInterceptTouchEvent(ev); } /** * 是否把滾動事件交給父ScrollView */ private void setParentScrollAble(boolean flag){ getParent().requestDisallowInterceptTouchEvent(!flag); }@2 ScrollView嵌套一個HorizontalScrollView 解決卡頓情況
網上的辦法
package com.treasure_ct.android_xt.seniorcontrols.eventdistribution.widgets; import android.content.Context; import android.util.AttributeSet; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.widget.ScrollView; /** * Created by treasure on 2016.09.27. */ public class MyScrollView2 extends ScrollView { private GestureDetector mGestureDetector; View.OnTouchListener mOnTouchListener; public MyScrollView2(Context context) { super(context); } public MyScrollView2(Context context, AttributeSet attrs) { super(context, attrs); mGestureDetector = new GestureDetector(new YScrollDetector()); setFadingEdgeLength(0); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return super.onInterceptTouchEvent(ev) && mGestureDetector.onTouchEvent(ev); } //如果Y角移動的絕對值大於X軸移動的絕對值,即縱向滑動返回true class YScrollDetector extends GestureDetector.SimpleOnGestureListener { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { if (Math.abs(distanceY) > Math.abs(distanceX)){ return true; } return false; } } }
本文實例講述了Android使用ActionBar和ViewPager切換頁面,分享給大家供大家參考。具體如下:運行效果截圖如下:項目布局如下:具體代碼如下:MainAc
春節放假回老家,發現家裡的貓換型號了,具備無線功能,但是悲劇的是連接到無線網絡後還得撥號上網,依據經驗,只能使用超級管理員開通自動撥號功能,知己知彼,我們首
好久沒有寫文章了,本來想寫的東西,時間一長,就感覺不想寫了,沒什麼用,到用時,又不知道去哪找了或怎麼解決。 有一句話說的好啊,好記性不如爛筆頭。 我要做到善於總結,及時整
Android用戶界面設計:基本按鈕 本文向你展示了在你的Android應用程序中創建一個簡單的Button或ImageButton控件的步驟。首先,你會