国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android仿微信列表滑動刪除之可滑動控件(一)

2019-12-12 05:28:23
字體:
來源:轉載
供稿:網友

這次是列表滑動刪除的第三波,仿微信的列表滑動刪除。先上個效果圖: 

 前面的文章里面說過開源框架SwipeListView的實現原理是每個列表item中包含上下兩層view,普通狀態下上層的view覆蓋著下層的view,當用戶滑開上層的view,下層的view就顯示出來了。但是仔細觀察微信列表的item,很明顯并非這個實現方案,微信的item應該一個單層view,只不過這個item超出了所在的ListView的寬度,在用戶滑動item的時候,item超出屏幕的view則會顯示在屏幕之上,這種滑動實現也很不錯。

既然推測出微信的實現原理,現在就要尋找具體的實現方案了,我最開始想的比較簡單,以為寫一個橫向線性布局LinearLayout,讓其包含兩個子布局,左邊的子布局寬度設置為填充父布局的寬度,以為另一個子布局就自然而然的會超出父布局的顯示范圍,但是具體測試的時候,發現就算左邊的子布局設置為填充父布局的寬度,但實際顯示的時候還是兩個子布局被包含在父布局的顯示范圍內,右邊的子布局無法做到超出父布局的顯示范圍。

糾結了一段時間,偶然情況下想起了ScrollView還有一種類型是HorizontalScrollView,,這個android提供的HorizontalScrollView可以做到其子view超出它的顯示范圍,那我可以直接使用HorizontalScrollView來實現這個item,我決定自定義一個控件,繼承自HorizontalScrollView,在代碼里面直接添加兩個子布局,并讓左邊的布局寬度填充這個控件的自身寬度,以便讓右邊的布局超出控件的顯示范圍,不過很不辛,HorizontalScrollView比較傲嬌,很難駕馭,奇葩bug層出不窮,譬如左邊的子布局渲染出來了,但是右邊的子布局愣是沒初始化,更別說滑動了,弄的焦頭爛額,最后實在沒辦法,只得暫時放下。

最后則是想到了使用一個自定義的ViewGroup來實現這個item。現在很多app在第一次啟動的時候,會出現一個介紹性的導航界面,用戶一頁一頁的滑動,看完導航的介紹之后再正式進入app,現在這種導航介紹應該大多數是用ViewPager實現的,ViewPager可以做到兩個滑動的子頁同時顯示在屏幕范圍內,具有很好的體驗效果。但是ViewPager是在之后的support.v4里面引入的,最初并沒有,那一開始這種導航介紹使用什么方案實現的呢?當然就是自定義的ViewGroup了,其實supprot.v4.ViewPager本身就是一個自定義的ViewGroup。關于使用自定義的ViewGroup實現導航介紹,csdn上有個大牛有專門寫過一個文章介紹了,這里就不詳細說了。

本篇的要講的是如何使用自定義的ViewGroup實現item的子view可以超出父布局的顯示范圍這樣的效果。

寫一個SwipeItemView,繼承自ViewGroup,構造方法里面,傳入左邊布局的引用id和右邊布局的引用id,初始化左子布局和右子布局,并將它們添加到SwipeItemView中作為子view,代碼如下:

private void init(Context context, AttributeSet attrs) {    mScroller = new Scroller(context);    ......    if(mPrimaryViewID == -1)      throw new RuntimeException(          "Illegal attribute 'primaryView', make sure you have set it");    mPrimaryView = LayoutInflater.from(getContext()).inflate(        mPrimaryViewID, null);    mPrimaryView.setClickable(false);    addView(mPrimaryView, 0);    if(mSlidingViewID != -1) {      mSlidingView = LayoutInflater.from(getContext()).inflate(          mSlidingViewID, null);      mSlidingView.setClickable(false);      addView(mSlidingView, 1);    }  }  

接下來需要重寫VIewGroup的onMeasure()方法,用來測量這個SwipeItemView及其子view的寬高,其中先獲取轉入的heightMeasureSpec中包含的heightSize,當heightSize的值和heightMeasureSpec相同的時候,是測量整個SwipeItemView的寬高,這是我們不做額外的處理,當heightSize不等于的傳入的heightMeasureSpec的時候,是用于測量SwipeItemView它包含的子view的寬高,這里我們做一下額外的處理,主要是針對超出SwipeItemView顯示范圍的右邊的mSlidingView,我想要它的寬只是包裹其內容就行,不想它的寬和屏幕范圍等寬,所以構造一個這樣的參數MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),具體代碼如下:

@Override  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    super.onMeasure(widthMeasureSpec, heightMeasureSpec);    int heightSize = MeasureSpec.getSize(heightMeasureSpec);    int widthSize = MeasureSpec.getSize(widthMeasureSpec);    int heightMode = MeasureSpec.getMode(heightMeasureSpec);    int widthMode = MeasureSpec.getMode(widthMeasureSpec);    if(heightSize != heightMeasureSpec) {      mPrimaryView.measure(MeasureSpec.makeMeasureSpec(widthSize, widthMode),          MeasureSpec.makeMeasureSpec(heightSize, heightMode));      if(mSlidingView != null) {        mSlidingView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),            MeasureSpec.makeMeasureSpec(heightSize, heightMode));      }    } else {      mPrimaryView.measure(widthMeasureSpec, heightMeasureSpec);      if(mSlidingView != null)        mSlidingView.measure(widthMeasureSpec, heightMeasureSpec);    }  } 
     

然后是重寫ViewGroup的onLayout()方法,用來放置子view在SwipeItemView中的具體位置,主要就是讓右邊的mSlidingView排列在左邊的mPrimaryView的右邊,具體代碼如下:

@Override  protected void onLayout(boolean changed, int l, int t, int r, int b) {    mPrimaryView.layout(l, t, r, b);    if(mSlidingView != null)      mSlidingView.layout(r, t, r + mSlidingView.getMeasuredWidth(), b);  }  

 好了,具體的SwipeItemView的初始化完成了,接下來需要做什么工作呢,看一下上面的構造方法,有沒有看到mScroller = new Scroller(context)這行代碼,我們需要使用這個mScroller來做這個SwipeItemView滑動的動畫效果。我們知道ViewGroup中提供了scrollBy()和scrollTo()兩個方法用來移動這個ViewGroup視圖內容的位置,其中scrollBy()移動參數指定的距離,scrollTo()方法移動到參數指定的位置。但是scrollBy()還好,如果每次都是移動一小段距離的話,給用戶的感覺就是一段連續的動畫效果了,但是scrollTo()則是瞬間移動,中間沒有任何動畫效果,會讓人感覺到非常突兀,這樣我們就需要用到mScroller這個對象了。

Scroller是android提供的用來實現我們需要的移動動畫效果的。Scroller本身并非去執行移動的動畫的,感覺上Scroller更多是作為一個指揮者,當我們調用它的Scroller.startScroll()方法的時候,這個方法我們需要傳入移動初始的位置、移動的距離以及花費的時間,簡單理解的話,我們假設指定的時間是10s,那第3s的時候,ViewGroup視圖內容應該移動到什么位置,第7s,應該移動到哪個位置,而且這個時刻Scroller計算出來的位置可以通過Scroller.getCurrX()和Scroller.getCurrY()獲取到,這個過程,Scroller會回調ViewGroup中的computeScroll()方法,在這個回調方法中,我們調用scrollTo()執行具體的移動操作。而我們實現的這個scrollToWithAnimation()方法就是提供給后面的SwipeListView用來移動某個item并且使其移動過程帶有動畫效果的方法。代碼如下:

 @Override  public void computeScroll() {    if(mScroller.computeScrollOffset()) {      scrollTo(mScroller.getCurrX(), mScroller.getCurrY());    }  }  /**   * just like scrollTo(), but with animation :D   * */  public void scrollToWithAnimation(int scrollX, int scrollY) {    mScroller.abortAnimation();    mScroller.startScroll(getScrollX(), getScrollY(),        scrollX - getScrollX(), getScrollY() - scrollY, 300);  }

 接下來需要實現一個自定義的ListView,暫且命名為SwipeListView。下一篇繼續。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 江西省| 曲周县| 当涂县| 鸡东县| 博客| 静乐县| 东城区| 汶上县| 遵义县| 宣化县| 上虞市| 天台县| 寿宁县| 体育| 寿阳县| 延吉市| 漳平市| 大名县| 茂名市| 江西省| 乐至县| 黑山县| 泸溪县| 乌拉特后旗| 南丹县| 西畴县| 武山县| 神池县| 榆树市| 财经| 新化县| 洪江市| 大姚县| 新蔡县| 泰兴市| 碌曲县| 翼城县| 新密市| 凤冈县| 泾阳县| 阳高县|