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

創(chuàng)新互聯(lián)是專業(yè)的雞西網(wǎng)站建設公司,雞西接單;提供做網(wǎng)站、成都網(wǎng)站設計,網(wǎng)頁設計,網(wǎng)站設計,建網(wǎng)站,PHP網(wǎng)站建設等專業(yè)做網(wǎng)站服務;采用PHP框架,可快速的進行雞西網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團隊,希望更多企業(yè)前來合作!
一、需求分析
最近公司項目要實現(xiàn)一個需求要滿足以下功能:
1)顯示一個 list 列表, item 數(shù)量不固定。
2)實現(xiàn)翻頁功能,一次翻一頁。
3)實現(xiàn)翻至某一頁功能。
二、功能實現(xiàn)
2.1 OnTouchListener 記錄當前開始滑動位置
要實現(xiàn)翻頁滑動首先我們要確定是向前翻頁還是向后翻頁,這里通過記錄開始翻頁前當前的位置和滑動后的位置比較即可得知,下面選擇手指觸摸按下時滑動的位置為當前開始滑動位置:
//當前滑動距離
private int offsetY = 0;
private int offsetX = 0;
//按下屏幕點
private int startY = 0;
private int startX = 0;
@Override
public boolean onTouch(View v, MotionEvent event) {
//手指按下的時候記錄開始滾動的坐標
if (event.getAction() == MotionEvent.ACTION_DOWN) {
//手指按下的開始坐標
startY = offsetY;
startX = offsetX;
}
return false;
}
}好了,當我們確定了滑動方向,下面要考慮的就是如何實現(xiàn)滑動?
2.2 scrollTo(int x, int y) 和 scrollBy(int x, int y) 實現(xiàn)滑動
滑動我們最容易想到的方法就是 scrollTo(int x, int y) 和 scrollBy(int x, int y) 這兩個方法, scrollTo(int x, int y) 是將當前 View 的內(nèi)容滑動至某一位置, scrollBy(int x, int y) 是將當前 View 內(nèi)容相對于當前位置滑動一定的距離,其實 scrollBy(int x, int y) 內(nèi)部是調(diào)用了 scrollTo(int x, int y) 方法實現(xiàn)的 一開始想用 scrollTo(int x, int y) 去實現(xiàn),但是簡單看了下源碼發(fā)現(xiàn), RecyclerView 不支持這個方法:
@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) 去實現(xiàn)滑動。
2.3 OnFlingListener 和 OnScrollListener 調(diào)用滑動時機
上面我們決定使用 scrollBy(int x, int y) 去實現(xiàn)滑動,那么現(xiàn)在我們就要確定 scrollBy(int x, int y) 這個方法的調(diào)用時機,我們知道當我們滑動 RecyclerView 的時候一般分為兩種情況,一種是手指在屏幕上面緩慢滑動(Scroll),另一種是飛速滑動(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);
}方法的注釋寫的也很清楚,當這個方法被調(diào)用并且返回 true 的時候系統(tǒng)就不處理滑動了,而是將滑動交給我們自己處理。所以我們可以監(jiān)聽這個方法,當我們執(zhí)行快速滑動的時候在這個方法里面計算要滑動的距離并執(zhí)行 scrollBy(int x, int y) 實現(xiàn)滑動,然后直接返回 true,表示滑動我們自己處理了,不需要系統(tǒng)處理。
處理代碼如下:
//當前滑動距離
private int offsetY = 0;
private int offsetX = 0;
//按下屏幕點
private int startY = 0;
private int startX = 0;
//最后一個可見 view 位置
private int lastItemPosition = -1;
//第一個可見view的位置
private int firstItemPosition = -2;
//總 itemView 數(shù)量
private int totalNum;
@Override
public boolean onFling(int velocityX, int velocityY) {
if (mOrientation == ORIENTATION.NULL) {
return false;
}
//獲取開始滾動時所在頁面的index
int page = getStartPageIndex();
//記錄滾動開始和結(jié)束的位置
int endPoint = 0;
int startPoint = 0;
//如果是垂直方向
if (mOrientation == ORIENTATION.VERTICAL) {
//開始滾動位置,當前開始執(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;
}
//更具不同的速度判斷需要滾動的方向
//一次滾動一個 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();
}
//使用動畫處理滾動
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方法實現(xiàn)滾動。
mRecyclerView.scrollBy(0, dy);
} else {
int dx = nowPoint - offsetX;
mRecyclerView.scrollBy(dx, 0);
}
}
});
mAnimator.addListener(new AnimatorListenerAdapter() {
//動畫結(jié)束
@Override
public void onAnimationEnd(Animator animation) {
//回調(diào)監(jiān)聽
if (null != mOnPageChangeListener) {
mOnPageChangeListener.onPageChange(getPageIndex());
}
//滾動完成,進行判斷是否滾到頭了或者滾到尾部了
RecyclerView.LayoutManager layoutManager = mRecyclerView.getLayoutManager();
//判斷是當前l(fā)ayoutManager是否為LinearLayoutManager
// 只有LinearLayoutManager才有查找第一個和最后一個可見view位置的方法
if (layoutManager instanceof LinearLayoutManager) {
LinearLayoutManager linearManager = (LinearLayoutManager) layoutManager;
//獲取最后一個可見view的位置
lastItemPosition = linearManager.findLastVisibleItemPosition();
//獲取第一個可見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 滾動監(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.
* 滾動完成調(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){}
}這個監(jiān)聽類主要有兩個方法一個是 onScrollStateChanged(RecyclerView recyclerView, int newState) 滾動狀態(tài)發(fā)生變化調(diào)用, onScrolled(RecyclerView recyclerView, int dx, int dy) RecyclerView 發(fā)生滾動和滾動完成調(diào)用。有了這兩個監(jiān)聽,當我們進行緩慢滑動我們就可以在 onScrollStateChanged(RecyclerView recyclerView, int newState) 中監(jiān)聽滑動如果結(jié)束并且超過一定距離去執(zhí)行翻頁,而通過 onScrolled(RecyclerView recyclerView, int dx, int dy) 方法可以記錄當前的滑動距離。
處理方法如下:
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
//如果滑動停止
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);
//如果滑動的距離超過屏幕的一半表示需要滑動到下一頁
move = absY > recyclerView.getHeight() / 2;
vY = 0;
if (move) {
vY = offsetY - startY < 0 ? -1000 : 1000;
}
} else {
int absX = Math.abs(offsetX - startX);
move = absX > recyclerView.getWidth() / 2;
if (move) {
vX = offsetX - startX < 0 ? -1000 : 1000;
}
}
//調(diào)用滑動
mOnFlingListener.onFling(vX, vY);
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
//滾動結(jié)束記錄滾動的偏移量
//記錄當前滾動到的位置
offsetY += dy;
offsetX += dx;
}
}到這里我們要實現(xiàn)滑動的方法和時機基本就搞定了,剩下的就是滑動位置計算和滑動效果實現(xiàn),滑動位置計算就是一次滑動一整頁,這個沒什么可說的,所以簡單說下實現(xiàn)彈性滑動效果。
2.4 ValueAnimator 實現(xiàn)彈性滑動效果
我們知道如果我們直接調(diào)用 scrollBy(int x, int y) 這個方法去滑動,那么是沒有緩慢滑動的效果,看著有點愣,所以這里我們通過 ValueAnimator 這個類來實現(xià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方法實現(xiàn)滾動。
mRecyclerView.scrollBy(0, dy);
} else {
int dx = nowPoint - offsetX;
mRecyclerView.scrollBy(dx, 0);
}
}
});2.5 翻頁至某一頁
這里翻頁至某一頁的實現(xiàn)有了上面的基礎就很好實現(xiàn)了,就是直接調(diào)用 我們已經(jīng)實現(xiàn)好了的 onFling(int velocityX, int velocityY) 方法,然后把頁數(shù)傳遞過去計算一下就可以了 :
public void setPageNum(int page) {
this.pageNum = page;
mOnFlingListener.onFling(0, 0);
}關(guān)于怎么在Android應用中利用RecyclerView實現(xiàn)一個分頁滾動功能問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識。
分享名稱:怎么在Android應用中利用RecyclerView實現(xiàn)一個分頁滾動功能
URL地址:http://www.yijiale78.com/article8/ghddip.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站建設、域名注冊、定制網(wǎng)站、微信小程序、全網(wǎng)營銷推廣、網(wǎng)站導航
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)