第一項目組 道理解析
IOS上的bounce功能給人的感觸感染很爽,當一個能夠遷移轉變的區域被拖到鴻溝時,它允許用戶將內容拖過界,甩手後再彈回來,以一種非常棒的體式格式提示了用戶鴻溝的存在,是IOS的一大特色。android2.3新增了overscroll功能,聽名字就知道應當是bounce功能的翻版,但也許是出於專利方面的推敲,google的默認實現跟IOS有所不合,它只是在list拖到鴻溝處時作了一個發光的動畫,小我感受體驗比IOS差遠了。而且這個的發光在黑色靠山下當然結果不錯,在其它靠山下可就難說了,是以不少人想要關掉它。
日前google上搜刮「android overscroll」,對此結果的先允不少,但關於其具體應用體式格式和實現,則不多涉及,偶有提及,也常常答非所問或貌同實異,反而誤導了別人。因而我查閱了android相干源碼,並作了一些測試,在此講講個人懂得。
起首是overscroll功能自己,在最頂層的View類供給了支撐,可經由過程setOverScrollMode函數把握其呈現前提。但其實View中並無實現overscroll功能,它僅僅供給了一個幫助函數overScrollBy,該函數按照overScrollMode和內容是否需要遷移轉變把握最大遷移轉變侷限,最後將策畫成果傳給onOverScrolled實現具體的overscroll功能,但此函數在View類中是全空的。
overscroll功能真正的實現分別在ScrollView、AbsListView、HorizontalScrollView和WebView中各有一份,代碼根蒂根基同樣。以ScrollView爲例,它在處理懲罰筆點移動消息時調用overScrollBy來遷移轉變視圖,而後重載了overScrollBy函數來實現具體功能,其地位策畫經由過程OverScroller類實現。OverScroller做爲一個策畫引擎,應當是一個自力的模塊,具體遷移轉變結果和侷限都不成能經由過程它來設置,我感受沒有需要細看。但遷移轉變地位終極是它給出的,那相干數據必然要傳遞給它,回頭看overScrollBy函數,它有兩個把握overScroll出界侷限的參數,幾個實現裏面都是取自ViewConfiguration.getScaledOverscrollDistance,而這個參數的值在個人源碼中都是0,而且我沒找到任何能夠影響其成果的設置。
真悲催,繞了半天,android的默認實現裏面底子沒有給出overscroll功能,它只是供給了實現機制,要想用起來還得應用法度自己顯式重寫相干控件,估計還有一層隱含的意思,法令風險自大。在個人體系中一試,果然一個像素都不克不及拉出界。但那個閃光是怎麼回事呢?
在處理懲罰筆點消息處,overScrollBy後面不遠處有一段mEdgeGlowTop的操縱代碼,看名字就像,用它一搜,相干機制就全熟悉打聽了。mEdgeGlowTop在setOverScrollMode函數時建立,它應用的都是體系中固有的,甚至不克不及經由過程theme改變。它的實現道理也很簡單,僅僅是兩張png的合成,經由過程透明度的變動建造閃光的結果。更無語的是它既不克不及被應用法度接見,也不受任何把握,要封閉它的獨一辦法是setOverScrollMode(View.OVER_SCROLL_NEVER)。否則就重寫onTouchEvent函數吧,想幹啥均可以,只是得自己作。
談到overScroll,不少文章都提到了ListView的setOverscrollHeader和setOverscrollFooter,不少人想經由過程這個來把握那個閃光結果。這兩玩意不單能夠經由過程函數設置,也能夠在xml中指定,至關便利。但最後不少人發明沒有任何感化,百思不得其解。其實這兩張是用來做爲overScroll拖過界時的靠山的,默認體系不克不及拖過界,自然永遠都看不到,有些定製的體系中能拖出界幾個像素,但也很丟臉清。
第二項目組 代碼實現
1. 在View中增加了overSrollBy辦法,用於記錄x, y 軸上遷移轉變。
2. 在AbsListView的onTouchEvent中判定是否達到鴻溝(頂部 或 底部) ,而後調用view.overScrollBy ,傳入 mScrollY等參數
3. overScrollBy 終極賦值給View的mScrollX, mScrollY 兩個變量
4. 在AbsListView中調用完overScrollBy以後,調用invalidate重繪
自定義ListView java
public class BounceListView extends ListView{ private static final int MAX_Y_OVERSCROLL_DISTANCE = 200; private Context mContext; private int mMaxYOverscrollDistance; public BounceListView(Context context){ super(context); mContext = context; initBounceListView(); } public BounceListView(Context context, AttributeSet attrs){ super(context, attrs); mContext = context; initBounceListView(); } public BounceListView(Context context, AttributeSet attrs, int defStyle){ super(context, attrs, defStyle); mContext = context; initBounceListView(); } private void initBounceListView(){ //get the density of the screen and do some maths with it on the max overscroll distance //variable so that you get similar behaviors no matter what the screen size final DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); final float density = metrics.density; mMaxYOverscrollDistance = (int) (density * MAX_Y_OVERSCROLL_DISTANCE); } @Override protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent){ //This is where the magic happens, we have replaced the incoming maxOverScrollY with our own custom variable mMaxYOverscrollDistance; return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, mMaxYOverscrollDistance, isTouchEvent); } } public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LinearLayout linearLayout = new LinearLayout(this); linearLayout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); setContentView(linearLayout); BounceListView bounceListView = new BounceListView(this); String[] data = new String[30]; for (int i = 0; i < data.length; i++) { data[i] = "回彈結果 " + i; } ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, data); bounceListView.setAdapter(arrayAdapter); linearLayout.addView(bounceListView); } }