简单的横向ListView实现(version 3.0)
版本號2僅僅是簡單的實現了當手指按下的時候listView的Item向左移動一定的距離,并沒有隨著手指的左右移動而左右滾動。在這個版本號3.0中將會實現隨著手指的移動而滾動的目標:當手指向左移動的時候。listView向左滾動;當手指向右移動的時候。listView向右滾動;在開始進入正題之前,先說說預備的知識和涉及到的方法。
在version2.0之前加入View的時候用的都是addView終于輾轉調用了addViewInner方法,經過查詢viewGroup的源代碼發現有一個addViewInLayout方法。api的說明例如以下:Adds a view during layout,this is usefule if in your onLayout method.而我們這個橫向listView正好是在onLayout里面加入的View,所以從如今開始加入View的時候就改為addViewInLayout了。ViewGrouup里面提供一個View的數組mChildren,在addView方法中調用了addVew(view view,index)index默認傳的是-1。表明加入到View數組mChildren最后面。
而addViewInLaout的方法的第二個參數就是這個index,假設index為負數的話就把該View方法數組的最后面(實際代碼處理中就是數組的插入操作,非常easy的源代碼),當index為正數的時候就把該View插入到數組中的index的位置,相應的View數組mChildren里面的元素后移。當然相應的刪除View的時候也有removeViewInLayout方法;事實上getChildAt(int index)就是從數組mChildrenCount獲取返回相應索引的View,所以左右滑動的核心思想就出來了:
?? 1)當向左滾動的時候,把右邊即將要滾動出來的View加入到mChildren數組的最后面。在頁面上的顯示為在屏幕的右邊的View,同一時候提供一個rightIndex來表示adapter.getView的position。即addViewInlayout(view,-1,view.getLayoutParams,true),
?? 2)當向右滾動的時候。把左邊即將滾動出來的View加入的mChildren數組的最前面數組0的位置,在頁面上的顯示為在屏幕左邊的View,同事提供一個left來表示adapter.getView?的position參數。
即addViewInlayout(view,0,view.getLayoutParams,true)。用代碼體現例如以下
leftChildView.getLeft() : 0; ?? ??? ?while (leftEdge + dianceX > 0 && leftIndex >= 0) { ?? ??? ??? ?View child = listAdapter.getView(leftIndex, null, null); ?? ??? ??? ?child = measureChild(child); ?? ??? ??? ?addViewInLayout(child, 0, child.getLayoutParams(), true); ?? ??? ??? ?leftEdge -= child.getMeasuredWidth(); ?? ??? ??? ?leftIndex--; ?? ??? ??? //此處省略了一個重要的代碼 ?? ??? ?} ?? ?}
該篇博客就是環繞著這兩個核心思路進行拓展和改動進而實現左右滾動的。
在版本號2.0中向左移動的時候須要在合適的時機移除左邊符合某些條件的View(詳細見簡單的橫向ListView實現(version 2.0) 相同,在想右滾動的時候也須要把超出右邊屏幕的View從Viewgroup里面刪除出去(當child.getLeft()+移動偏移量大于parent.getWidth()的時候進行刪除):簡而言之就是向左滾動時。須要刪除滾動過后左邊的看不見View。當向右滾動時,須要刪除滾動過后右邊的看不見的View。用代碼表演示樣例如以下:
到此為止在考慮左右滾動的條件下什么時候加入左邊的View、什么時候加入右邊的View以及在什么時候刪除左右兩邊看不見的View的思路以及代碼都實現了。之前的版本號的滾動值都是寫死的。如今這個版本號將用GestureDetector來處理手指的移動,至于GestureDetector的使用方法在這里不再贅述。網上好多資料能夠查閱在.SimpleOnGestureListener()里面有一個?onScroll(MotionEvent e1, MotionEvent e2,? float distanceX, float distanceY)方法。由于是水平滾動。所以第三個參數distanceX使我們所須要的,該參數指的是距離上次調用onScroll方法的時候x軸滾動的距離。所以在代碼中我用變量distanceX來記錄下了:
public boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY) {//記錄滾動的距離HListView.this.distanceX= (int) distanceX;// 仍然須要重繪requestLayout();return true;};這里有個須要注意的小地方,手指向左的時候distanceX>0,而手指向右的時候distanceX<0.所以在用的時候我們要取反,所以在onLayout里面這么調用(較版本號2.0之前對這種方法進行了重構處理): @Overrideprotected void onLayout(boolean changed, int left, int top, int right,int bottom) {if (listAdapter == null) {return;}removeAnvisiableViews(-distanceX);addRightChildViews(-distanceX);addLeftChildViews(-distanceX);layoutChildViews(-distanceX);}到此為止基本上該說的都說了,執行一把試試,我屮艸芔茻,發現動不了。怎么回事?各種抓耳撓腮。終于吃飯的時候靈光一閃知道問題出如今哪兒了!我們知道橫向listView滾動的邏輯就是反復addView和removeView的操作,可是最重要的一點就是終于都要調用layoutChildViews方法進行處理,而在version2.0版本號的代碼中layoutChildViews代碼是這么樣的:
int childLeft = 0;for(int i=0;i<getChildCount();i++) {View child = getChildAt(i);int childWidth = child.getMeasuredWidth();child.layout(childLeft, 0, childWidth+childLeft, child.getMeasuredHeight());//只是最好的寫法是childLeft += childWidth+child.getPaddingRight();}layout方法的第一個三處我們總是讓它從0開始。!
!!問題就出在這兒。。!
簡單的想象一下,當向右滾動的時候左邊會出現半個Item的情況(或者不完整的Item)。怎么可能是從0開始呢??隙〞霈FchildLeft<0的情況。所以當處理左邊第一個能夠看見的子View的時候,layout第一個參數是隨著滾動而發生變化的。并非固定為0的死的值!事實上上面的代碼中我有寫到:此處省略了一行重要的代碼,事實上這行代碼就是解決問題的!
我在類里面定義了個leftOffset=0的變量來進行控制表示下一個即將加入的子View的起始位置(注意要加上distanceX),(這個變量的作用想了半天不好用語言描寫敘述,郁悶).當調用addleftChildView方法的時候每加入一個View時對該變量進行leftOffset -= child.getMeasuredWidth();。
對應的當刪除左邊的一個View的時候leftOffset += child.getMeasuredWidth();所以layoutchildView的代碼改動為:
private void layoutChildViews(int distanceX) {if(getChildCount()==0) {return;}leftOffset += distanceX;int childLeft = leftOffset;for (int i = 0; i < getChildCount(); i++) {View child = getChildAt(i);int childWidth = child.getMeasuredWidth();child.layout(childLeft, 0, childWidth + childLeft,child.getMeasuredHeight());// 只是最好的寫法是childLeft += childWidth + child.getPaddingRight();}}執行一把。OK,爽歪歪!version3.0到此位置完畢了。只是功能仍然不夠完好:比方當左邊已經是第一個Item的時候仍然能夠想右邊滾動。同理當右邊是最后一個View的時候仍然能夠向左滾動、相同的當手指離開的時候沒有慣性滾動,比方每次getView的時候都須要對xml文件進行解析,沒有非常好的重用已經解析過的xml等,這些豐富的功能將在下一個版本號中實現。(此處為源碼)
轉載于:https://www.cnblogs.com/liguangsunls/p/7089381.html
總結
以上是生活随笔為你收集整理的简单的横向ListView实现(version 3.0)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jQuery初步
- 下一篇: iptables日志探秘