成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

怎么在Android應(yīng)用中利用RecyclerView實(shí)現(xiàn)一個(gè)分頁滾動(dòng)功能

怎么在Android應(yīng)用中利用RecyclerView實(shí)現(xiàn)一個(gè)分頁滾動(dòng)功能?針對(duì)這個(gè)問題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡(jiǎn)單易行的方法。

創(chuàng)新互聯(lián)是專業(yè)的雞西網(wǎng)站建設(shè)公司,雞西接單;提供做網(wǎng)站、成都網(wǎng)站設(shè)計(jì),網(wǎng)頁設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行雞西網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來合作!

一、需求分析

最近公司項(xiàng)目要實(shí)現(xiàn)一個(gè)需求要滿足以下功能:

      1)顯示一個(gè) list 列表, item 數(shù)量不固定。

      2)實(shí)現(xiàn)翻頁功能,一次翻一頁。

      3)實(shí)現(xiàn)翻至某一頁功能。

二、功能實(shí)現(xiàn)

2.1 OnTouchListener 記錄當(dāng)前開始滑動(dòng)位置

要實(shí)現(xiàn)翻頁滑動(dòng)首先我們要確定是向前翻頁還是向后翻頁,這里通過記錄開始翻頁前當(dāng)前的位置和滑動(dòng)后的位置比較即可得知,下面選擇手指觸摸按下時(shí)滑動(dòng)的位置為當(dāng)前開始滑動(dòng)位置:

 //當(dāng)前滑動(dòng)距離
 private int offsetY = 0;
 private int offsetX = 0;
 //按下屏幕點(diǎn)
 private int startY = 0;
 private int startX = 0;
@Override
  public boolean onTouch(View v, MotionEvent event) {
   //手指按下的時(shí)候記錄開始滾動(dòng)的坐標(biāo)
   if (event.getAction() == MotionEvent.ACTION_DOWN) {
    //手指按下的開始坐標(biāo)
    startY = offsetY;
    startX = offsetX;
   }
   return false;
  }
 }

好了,當(dāng)我們確定了滑動(dòng)方向,下面要考慮的就是如何實(shí)現(xiàn)滑動(dòng)?

2.2 scrollTo(int x, int y) 和 scrollBy(int x, int y) 實(shí)現(xiàn)滑動(dòng)

滑動(dòng)我們最容易想到的方法就是 scrollTo(int x, int y)scrollBy(int x, int y) 這兩個(gè)方法, scrollTo(int x, int y) 是將當(dāng)前 View 的內(nèi)容滑動(dòng)至某一位置, scrollBy(int x, int y) 是將當(dāng)前 View 內(nèi)容相對(duì)于當(dāng)前位置滑動(dòng)一定的距離,其實(shí) scrollBy(int x, int y) 內(nèi)部是調(diào)用了 scrollTo(int x, int y) 方法實(shí)現(xiàn)的 一開始想用 scrollTo(int x, int y) 去實(shí)現(xiàn),但是簡(jiǎn)單看了下源碼發(fā)現(xiàn), RecyclerView 不支持這個(gè)方法:

@Override
 public void scrollTo(int x, int y) {
  Log.w(TAG, "RecyclerView does not support scrolling to an absolute position. "
    + "Use scrollToPosition instead");
 }

所以這里我們就選擇使用 scrollBy(int x, int y) 去實(shí)現(xiàn)滑動(dòng)。

2.3 OnFlingListener 和 OnScrollListener 調(diào)用滑動(dòng)時(shí)機(jī)

上面我們決定使用 scrollBy(int x, int y) 去實(shí)現(xiàn)滑動(dòng),那么現(xiàn)在我們就要確定 scrollBy(int x, int y) 這個(gè)方法的調(diào)用時(shí)機(jī),我們知道當(dāng)我們滑動(dòng) RecyclerView 的時(shí)候一般分為兩種情況,一種是手指在屏幕上面緩慢滑動(dòng)(Scroll),另一種是飛速滑動(dòng)(onFling),經(jīng)過一番查閱,發(fā)現(xiàn) RecyclerView 中有這兩種狀態(tài)的監(jiān)聽,那么我們一起看一下這兩種狀態(tài)的方法定義,先看 onFling(int velocityX, int velocityY)

Note: 由于使用了 RecyclerView 的 OnFlingListener,所以 RecycleView 的版本必須要 recyclerview-v7:25.0.0 以上。

/**
 * This class defines the behavior of fling if the developer wishes to handle it.
 * <p>
 * Subclasses of {@link OnFlingListener} can be used to implement custom fling behavior.
 *
 * @see #setOnFlingListener(OnFlingListener)
 */
 public static abstract class OnFlingListener {
  /**
  * Override this to handle a fling given the velocities in both x and y directions.
  * Note that this method will only be called if the associated {@link LayoutManager}
  * supports scrolling and the fling is not handled by nested scrolls first.
  *
  * @param velocityX the fling velocity on the X axis
  * @param velocityY the fling velocity on the Y axis
  *
  * @return true if the fling washandled, false otherwise.
  */
  public abstract boolean onFling(int velocityX, int velocityY);
 }

方法的注釋寫的也很清楚,當(dāng)這個(gè)方法被調(diào)用并且返回 true 的時(shí)候系統(tǒng)就不處理滑動(dòng)了,而是將滑動(dòng)交給我們自己處理。所以我們可以監(jiān)聽這個(gè)方法,當(dāng)我們執(zhí)行快速滑動(dòng)的時(shí)候在這個(gè)方法里面計(jì)算要滑動(dòng)的距離并執(zhí)行 scrollBy(int x, int y) 實(shí)現(xiàn)滑動(dòng),然后直接返回 true,表示滑動(dòng)我們自己處理了,不需要系統(tǒng)處理。

處理代碼如下:

 //當(dāng)前滑動(dòng)距離
 private int offsetY = 0;
 private int offsetX = 0;
 //按下屏幕點(diǎn)
 private int startY = 0;
 private int startX = 0;
 //最后一個(gè)可見 view 位置
 private int lastItemPosition = -1;
 //第一個(gè)可見view的位置
 private int firstItemPosition = -2;
 //總 itemView 數(shù)量
 private int totalNum;
@Override
  public boolean onFling(int velocityX, int velocityY) {
   if (mOrientation == ORIENTATION.NULL) {
    return false;
   }
   //獲取開始滾動(dòng)時(shí)所在頁面的index
   int page = getStartPageIndex();
   //記錄滾動(dòng)開始和結(jié)束的位置
   int endPoint = 0;
   int startPoint = 0;
   //如果是垂直方向
   if (mOrientation == ORIENTATION.VERTICAL) {
    //開始滾動(dòng)位置,當(dāng)前開始執(zhí)行 scrollBy 位置
    startPoint = offsetY;
    if (velocityY < 0) {
     page--;
    } else if (velocityY > 0) {
     page++;
    } else if (pageNum != -1) {
     if (lastItemPosition + 1 == totalNum) {
      mRecyclerView.scrollToPosition(0);
     }
     page = pageNum - 1;
    }
    //更具不同的速度判斷需要滾動(dòng)的方向
    //一次滾動(dòng)一個(gè) mRecyclerView 高度
    endPoint = page * mRecyclerView.getHeight();
   } else {
    startPoint = offsetX;
    if (velocityX < 0) {
     page--;
    } else if (velocityX > 0) {
     page++;
    } else if (pageNum != -1) {
     if (lastItemPosition + 1 == totalNum) {
      mRecyclerView.scrollToPosition(0);
     }
     page = pageNum - 1;
    }
    endPoint = page * mRecyclerView.getWidth();
   }
   //使用動(dòng)畫處理滾動(dòng)
   if (mAnimator == null) {
    mAnimator = ValueAnimator.ofInt(startPoint, endPoint);
    mAnimator.setDuration(300);
    mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
     @Override
     public void onAnimationUpdate(ValueAnimator animation) {
      int nowPoint = (int) animation.getAnimatedValue();
      if (mOrientation == ORIENTATION.VERTICAL) {
       int dy = nowPoint - offsetY;
       if (dy == 0) return;
       //這里通過RecyclerView的scrollBy方法實(shí)現(xiàn)滾動(dòng)。
       mRecyclerView.scrollBy(0, dy);
      } else {
       int dx = nowPoint - offsetX;
       mRecyclerView.scrollBy(dx, 0);
      }
     }
    });
    mAnimator.addListener(new AnimatorListenerAdapter() {
     //動(dòng)畫結(jié)束
     @Override
     public void onAnimationEnd(Animator animation) {
      //回調(diào)監(jiān)聽
      if (null != mOnPageChangeListener) {
       mOnPageChangeListener.onPageChange(getPageIndex());
      }
      //滾動(dòng)完成,進(jìn)行判斷是否滾到頭了或者滾到尾部了
      RecyclerView.LayoutManager layoutManager = mRecyclerView.getLayoutManager();
      //判斷是當(dāng)前l(fā)ayoutManager是否為LinearLayoutManager
      // 只有LinearLayoutManager才有查找第一個(gè)和最后一個(gè)可見view位置的方法
      if (layoutManager instanceof LinearLayoutManager) {
       LinearLayoutManager linearManager = (LinearLayoutManager) layoutManager;
       //獲取最后一個(gè)可見view的位置
       lastItemPosition = linearManager.findLastVisibleItemPosition();
       //獲取第一個(gè)可見view的位置
       firstItemPosition = linearManager.findFirstVisibleItemPosition();
      }
      totalNum = mRecyclerView.getAdapter().getItemCount();
      if (totalNum == lastItemPosition + 1) {
       updateLayoutManger();
      }
      if (firstItemPosition == 0) {
       updateLayoutManger();
      }
     }
    });
   } else {
    mAnimator.cancel();
    mAnimator.setIntValues(startPoint, endPoint);
   }
   mAnimator.start();
   return true;
  }
 }

再看 OnScrollListener 滾動(dòng)監(jiān)聽方法:

public abstract static class OnScrollListener {
  /**
  * Callback method to be invoked when RecyclerView's scroll state changes.
  *
  * @param recyclerView The RecyclerView whose scroll state has changed.
  * @param newState  The updated scroll state. One of {@link #SCROLL_STATE_IDLE},
  *      {@link #SCROLL_STATE_DRAGGING} or {@link #SCROLL_STATE_SETTLING}.
  */
  public void onScrollStateChanged(RecyclerView recyclerView, int newState){}
  /**
  * Callback method to be invoked when the RecyclerView has been scrolled. This will be
  * called after the scroll has completed.
  * <p>
  * This callback will also be called if visible item range changes after a layout
  * calculation. In that case, dx and dy will be 0.
  * 滾動(dòng)完成調(diào)用
  * @param recyclerView The RecyclerView which scrolled.
  * @param dx The amount of horizontal scroll.
  * @param dy The amount of vertical scroll.
  */
  public void onScrolled(RecyclerView recyclerView, int dx, int dy){}
 }

這個(gè)監(jiān)聽類主要有兩個(gè)方法一個(gè)是 onScrollStateChanged(RecyclerView recyclerView, int newState) 滾動(dòng)狀態(tài)發(fā)生變化調(diào)用, onScrolled(RecyclerView recyclerView, int dx, int dy) RecyclerView 發(fā)生滾動(dòng)和滾動(dòng)完成調(diào)用。有了這兩個(gè)監(jiān)聽,當(dāng)我們進(jìn)行緩慢滑動(dòng)我們就可以在 onScrollStateChanged(RecyclerView recyclerView, int newState) 中監(jiān)聽滑動(dòng)如果結(jié)束并且超過一定距離去執(zhí)行翻頁,而通過 onScrolled(RecyclerView recyclerView, int dx, int dy) 方法可以記錄當(dāng)前的滑動(dòng)距離。

處理方法如下:

@Override
  public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
   //如果滑動(dòng)停止
   if (newState == RecyclerView.SCROLL_STATE_IDLE && mOrientation != ORIENTATION.NULL) {
    boolean move;
    int vX = 0, vY = 0;
    if (mOrientation == ORIENTATION.VERTICAL) {
     int absY = Math.abs(offsetY - startY);
     //如果滑動(dòng)的距離超過屏幕的一半表示需要滑動(dòng)到下一頁
     move = absY > recyclerView.getHeight() / 2;
     vY = 0;
     if (move) {
      vY = offsetY - startY < 0 &#63; -1000 : 1000;
     }
    } else {
     int absX = Math.abs(offsetX - startX);
     move = absX > recyclerView.getWidth() / 2;
     if (move) {
      vX = offsetX - startX < 0 &#63; -1000 : 1000;
     }
    }
    //調(diào)用滑動(dòng)
    mOnFlingListener.onFling(vX, vY);
   }
  }
 @Override
  public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
   //滾動(dòng)結(jié)束記錄滾動(dòng)的偏移量
   //記錄當(dāng)前滾動(dòng)到的位置
   offsetY += dy;
   offsetX += dx;
  }
 }

到這里我們要實(shí)現(xiàn)滑動(dòng)的方法和時(shí)機(jī)基本就搞定了,剩下的就是滑動(dòng)位置計(jì)算和滑動(dòng)效果實(shí)現(xiàn),滑動(dòng)位置計(jì)算就是一次滑動(dòng)一整頁,這個(gè)沒什么可說的,所以簡(jiǎn)單說下實(shí)現(xiàn)彈性滑動(dòng)效果。

2.4 ValueAnimator 實(shí)現(xiàn)彈性滑動(dòng)效果

我們知道如果我們直接調(diào)用 scrollBy(int x, int y) 這個(gè)方法去滑動(dòng),那么是沒有緩慢滑動(dòng)的效果,看著有點(diǎn)愣,所以這里我們通過 ValueAnimator 這個(gè)類來實(shí)現(xiàn)緩慢滑動(dòng)的效果,這個(gè)就很簡(jiǎn)單了,直接貼代碼:

if (mAnimator == null) {
    mAnimator = ValueAnimator.ofInt(startPoint, endPoint);
    mAnimator.setDuration(300);
    mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
     @Override
     public void onAnimationUpdate(ValueAnimator animation) {
      int nowPoint = (int) animation.getAnimatedValue();
      if (mOrientation == ORIENTATION.VERTICAL) {
       int dy = nowPoint - offsetY;
       if (dy == 0) return;
       //這里通過RecyclerView的scrollBy方法實(shí)現(xiàn)滾動(dòng)。
       mRecyclerView.scrollBy(0, dy);
      } else {
       int dx = nowPoint - offsetX;
       mRecyclerView.scrollBy(dx, 0);
      }
     }
    });

2.5 翻頁至某一頁

這里翻頁至某一頁的實(shí)現(xiàn)有了上面的基礎(chǔ)就很好實(shí)現(xiàn)了,就是直接調(diào)用 我們已經(jīng)實(shí)現(xiàn)好了的 onFling(int velocityX, int velocityY) 方法,然后把頁數(shù)傳遞過去計(jì)算一下就可以了 :

public void setPageNum(int page) {
 this.pageNum = page;
 mOnFlingListener.onFling(0, 0);
}

關(guān)于怎么在Android應(yīng)用中利用RecyclerView實(shí)現(xiàn)一個(gè)分頁滾動(dòng)功能問題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

分享名稱:怎么在Android應(yīng)用中利用RecyclerView實(shí)現(xiàn)一個(gè)分頁滾動(dòng)功能
URL地址:http://jinyejixie.com/article8/ghddip.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站建設(shè)、域名注冊(cè)、定制網(wǎng)站、微信小程序全網(wǎng)營銷推廣、網(wǎng)站導(dǎo)航

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運(yùn)營
宜丰县| 武胜县| 浮梁县| 湄潭县| 上栗县| 罗田县| 尉犁县| 当雄县| 麟游县| 澄江县| 邵阳县| 华安县| 西丰县| 古浪县| 乌什县| 五华县| 桐乡市| 海阳市| 娱乐| 台中县| 甘德县| 利川市| 铁岭县| 墨竹工卡县| 准格尔旗| 丰镇市| 珠海市| 庆安县| 巴中市| 中西区| 高唐县| 汉寿县| 剑阁县| 安泽县| 正阳县| 儋州市| 积石山| 油尖旺区| 抚州市| 九江县| 常山县|