Android RecyclerView 滾動(dòng)到中間位置的方法示例
最近看到QQ音樂(lè)的歌詞每次滑動(dòng)后都可以滾回到中間位置。覺(jué)得甚是神奇,打開(kāi)開(kāi)發(fā)者模式顯示布局,發(fā)現(xiàn)歌詞部分不是采用 android 控件的寫的,應(yīng)該是前端寫的。于是,我想,能不能用 recyclerView 實(shí)現(xiàn)這個(gè)自動(dòng)回滾到中間位置呢。
功夫不負(fù)有心人,查找了一些資料之后,終于搞定了。
下面由我細(xì)細(xì)講來(lái)。
目標(biāo)
點(diǎn)擊某個(gè)條目,在經(jīng)過(guò)4s無(wú)任何操作之后,該條目滾動(dòng)到中間位置顯示。點(diǎn)擊后,用戶在滑動(dòng),等用戶不操作后再開(kāi)始延時(shí)。用戶多次點(diǎn)擊,記最后一次點(diǎn)擊位置。
分析
首先先考慮,滾動(dòng)到指定位置是如何操作的?
// 滾動(dòng)到指定位置 recyclerView.scrollToPosition(position); // 平滑滾動(dòng)到指定位置 recyclerView.smoothScrollToPosition(position);
有沒(méi)有滾動(dòng)到制定像素位置呢?
// scrollBy(x, y)這個(gè)方法是自己去控制移動(dòng)的距離,單位是像素,所以在使用scrollBy(x, y)需要自己去計(jì)算移動(dòng)的高度或?qū)挾取? recyclerView.scrollBy(x, y)
可是,問(wèn)題是滾動(dòng)到中間位置啊?這個(gè)怎么辦呢?這樣子行不行呢?
mRecyclerView.scrollToPosition(0); mRecyclerView.scrollBy(0,400);
先滾動(dòng)到制定位置,在滾動(dòng)一段距離不就好了?運(yùn)行發(fā)現(xiàn),這兩行代碼只執(zhí)行第一行,第二行無(wú)效。
debug 調(diào)試看了下,還是沒(méi)有弄懂,實(shí)現(xiàn)太復(fù)雜。
那就是說(shuō)這樣是不行的,那有沒(méi)有其他辦法呢?
RecyclerView 有一個(gè)滾動(dòng)監(jiān)聽(tīng)方法:
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
});
onScrollStateChanged 方法對(duì)應(yīng)三種狀態(tài):靜止(SCROLL_STATE_IDLE),拖動(dòng)滾動(dòng)(SCROLL_STATE_DRAGGING),滑動(dòng)(SCROLL_STATE_SETTLING)。
當(dāng)手動(dòng)緩慢滑動(dòng)的時(shí)候,會(huì)觸發(fā): onScrollStateChanged (拖動(dòng)滾動(dòng)) --> (n個(gè))onScrolled -->onScrollStateChanged(靜止);
當(dāng)手快速滑動(dòng)的時(shí)候,會(huì)觸發(fā): onScrollStateChanged (拖動(dòng)滾動(dòng)) --> (n個(gè))onScrolled --> onScrollStateChanged (滑動(dòng)) -->
(n個(gè))onScrolled --> onScrollStateChanged (靜止);
有想法了,點(diǎn)擊的時(shí)候,先運(yùn)行 scrollToPosition,在 onScrolled 方法里面 運(yùn)行 scrollBy 方法。寫代碼,運(yùn)行,通過(guò)。
下面就是中間位置的計(jì)算了。
首先計(jì)算出 recylerview 的展現(xiàn)高度。
Rect rect = new Rect();
mRecyclerView.getGlobalVisibleRect(rect);
reHeight = rect.bottom - rect.top - vHeight;
當(dāng)運(yùn)行 scrollToPosition 后,點(diǎn)擊條目就會(huì)出現(xiàn)在視野當(dāng)中,這時(shí)候,計(jì)算出相應(yīng)的位移即可。需要注意一點(diǎn)的是,當(dāng)點(diǎn)擊條目在視野內(nèi)的時(shí)候,是不會(huì)運(yùn)行 scrollToPosition 方法的。
int top = mRecyclerView.getChildAt(position - firstPosition).getTop();
int half = reHeight / 2;
mRecyclerView.scrollBy(0, top - half);
最后就是延時(shí)的設(shè)定,采用Handler 進(jìn)行延時(shí)。
代碼
核心代碼如下:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private RecyclerView mRecyclerView;
private LinearLayoutManager mLayoutManager;
private RecyclerView.Adapter mAdapter;
private String[] data;
private Handler handler;
private boolean isClick = false;
private static int vHeight = -1;
private static int reHeight = -1;
private static int position = 0;
private static final int target = 10;
private static boolean isMove = false;
private Runnable runnable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler = new Handler();
mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
//創(chuàng)建默認(rèn)的線性LayoutManager
mLayoutManager = new LinearLayoutManager(this);
mLayoutManager.setAutoMeasureEnabled(true);
mRecyclerView.setLayoutManager(mLayoutManager);
//如果可以確定每個(gè)item的高度是固定的,設(shè)置這個(gè)選項(xiàng)可以提高性能
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setNestedScrollingEnabled(false);
data = new String[]{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21"};
runnable = new Runnable() {
@Override
public void run() {
if (isVisible()) {
scrollToMiddle();
} else {
mRecyclerView.scrollToPosition(position);
isMove = true;
isClick = false;
}
}
};
mAdapter = new MyAdapter(data, new MyAdapter.onRecyclerViewItemClick() {
@Override
public void onItemClick(View v, int pos) {
Toast.makeText(MainActivity.this, "第" + pos + "行", Toast.LENGTH_SHORT).show();
position = pos;
vHeight = v.getHeight();
Rect rect = new Rect();
mRecyclerView.getGlobalVisibleRect(rect);
reHeight = rect.bottom - rect.top - vHeight;
// handler.removeCallbacksAndMessages(null);
handler.removeCallbacks(runnable);
handler.postDelayed(runnable, 4000);
isClick = true;
}
});
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
Log.d(TAG, "" + newState);
if (newState == RecyclerView.SCROLL_STATE_DRAGGING && !isMove) {
handler.removeCallbacks(runnable);
}
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (isClick) {
handler.postDelayed(runnable, 4000);
}
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (isMove) {
if (vHeight < 0) {
isMove = false;
return;
}
scrollToMiddle();
}
}
});
public void scrollToMiddle() {
final int firstPosition = mLayoutManager.findFirstVisibleItemPosition();
int top = mRecyclerView.getChildAt(position - firstPosition).getTop();
Log.d(TAG, " position" + position + " " + top);
int half = reHeight / 2;
mRecyclerView.scrollBy(0, top - half);
isMove = false;
}
public boolean isVisible() {
final int firstPosition = mLayoutManager.findFirstVisibleItemPosition();
final int lastPosition = mLayoutManager.findLastVisibleItemPosition();
return position <= lastPosition && position >= firstPosition;
}
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);
handler = null;
}
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- RecyclerView實(shí)現(xiàn)縱向和橫向滾動(dòng)
- RecyclerView實(shí)現(xiàn)抖音縱向滾動(dòng)ViewPager效果
- Android RecyclerView 實(shí)現(xiàn)快速滾動(dòng)的示例代碼
- Android使用Recyclerview實(shí)現(xiàn)圖片水平自動(dòng)循環(huán)滾動(dòng)效果
- XRecyclerView實(shí)現(xiàn)下拉刷新、滾動(dòng)到底部加載更多等功能
- Android_RecyclerView實(shí)現(xiàn)上下滾動(dòng)廣告條實(shí)例(帶圖片)
- Android中RecyclerView實(shí)現(xiàn)分頁(yè)滾動(dòng)的方法詳解
- Android使用RecyclerView實(shí)現(xiàn)水平滾動(dòng)控件
- Android代碼實(shí)現(xiàn)AdapterViews和RecyclerView無(wú)限滾動(dòng)
- RecyclerView實(shí)現(xiàn)橫向滾動(dòng)效果
相關(guān)文章
Android實(shí)現(xiàn)淘寶商品列表切換效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)淘寶商品列表切換效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01
Android中分析Jetpack?Compose動(dòng)畫內(nèi)部的實(shí)現(xiàn)原理
這篇文章主要介紹了Android中分析Jetpack?Compose動(dòng)畫內(nèi)部的實(shí)現(xiàn)原理,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下2022-09-09
Android 仿蘋果IOS6開(kāi)關(guān)按鈕
這篇文章主要介紹了Android 仿蘋果IOS6開(kāi)關(guān)按鈕的實(shí)現(xiàn)代碼,代碼簡(jiǎn)單易懂非常不錯(cuò)具有參考借鑒價(jià)值,需要的朋友可以參考下2016-10-10
Android開(kāi)源項(xiàng)目PullToRefresh下拉刷新功能詳解2
這篇文章主要為大家進(jìn)一步的介紹了Android開(kāi)源項(xiàng)目PullToRefresh下拉刷新功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09
Android Popupwindow彈出窗口的簡(jiǎn)單使用方法
這篇文章主要為大家詳細(xì)介紹了Android Popupwindow彈出窗口的簡(jiǎn)單使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07
Android實(shí)現(xiàn)下拉菜單Spinner效果
這篇文章主要介紹了Android實(shí)現(xiàn)下拉菜單Spinner效果,學(xué)習(xí)Spinner組件的使用方法,非常好用的一款組件,相當(dāng)于從下拉列表中選擇項(xiàng)目,感興趣的小伙伴們可以參考一下2016-04-04
Android中App字體大小不隨系統(tǒng)改變而改變
這篇文章主要介紹了Android中App字體大小不隨系統(tǒng)改變而改變,需要的朋友可以參考下2017-04-04

