RecyclerView 滑動到指定下標(biāo)驯妄、快速導(dǎo)航

需求

城市列表快速定位:通過右邊的地區(qū)字母快速導(dǎo)航到特定位置
通訊錄的快速定位

分析思路

網(wǎng)上查看的文章說:分三種情況,即屏幕上方合砂、屏幕中青扔、屏幕下方;分別處理代碼邏輯翩伪;
實(shí)際分析后發(fā)現(xiàn)完全可以使用比較簡單的方式實(shí)現(xiàn):

默認(rèn)API

RecyclerView 提供了3種方法用于滑動到特定位置的API

API 區(qū)別
scrollBy(int x, int y) 根據(jù)x赎懦、y軸的距離,滑動
smoothScrollToPosition(int position) 平滑滾動到特定 position
scrollToPosition(int position) 滾動到特定position

但是通過具體代碼的實(shí)踐:均不能達(dá)到預(yù)期效果

  • scrollBy() 方法可以通計(jì)算 child.getTop() 獲得其需要滑動的距離幻工,但是如果 child 在屏幕之外励两,需要的 child 未創(chuàng)建,無法獲得
  • scrollToPosition(int position)囊颅、smoothScrollToPosition(int position)方法可以通過 position 滑動到特定下標(biāo)当悔,但是有個特點(diǎn):
    • position < firstViewItemPosition,則列表向下滾動 目標(biāo) position 滾動到頂部位置
    • firstVisibleItemPosition < position < lastVisibleItemPosition :列表不會滾動
    • position > lastVisibleItemPosition : 列表向上滾動踢代, 目標(biāo)position 滾動到屏幕底部位置

可見均不能達(dá)到我們的預(yù)期盲憎;
那我們?nèi)シ治鲆幌?smoothScrollToPosition() 的具體實(shí)現(xiàn),看下我們是否可以干預(yù)一下其滾動規(guī)則

源碼分析

// RecyclerView.java

public void smoothScrollToPosition(int position) {
    if (mLayoutFrozen) {
        return;
    }
    if (mLayout == null) {
        Log.e(TAG, "Cannot smooth scroll without a LayoutManager set. " +
                "Call setLayoutManager with a non-null argument.");
        return;
    }
    
    // @VisibleForTesting LayoutManager mLayout;
    // 這里調(diào)用了 LayouManager 去實(shí)現(xiàn)滾動胳挎。
    mLayout.smoothScrollToPosition(this, mState, position);
}
// LayoutManager 類

public void smoothScrollToPosition(RecyclerView recyclerView, State state, int position) {
    // LayoutManager 中并沒有實(shí)現(xiàn)代碼饼疙,而是由 我們設(shè)置的 其子類來具體的實(shí)現(xiàn)的
    Log.e(TAG, "You must override smoothScrollToPosition to support smooth scrolling");
}
// LinearLayoutManager 類

@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
    // 滾動控制器
    LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext());
    // 設(shè)置滾動目標(biāo) position
    linearSmoothScroller.setTargetPosition(position);
    // 由 LineraManager 調(diào)用
    startSmoothScroll(linearSmoothScroller);
}
// LayoutManager 類

public void startSmoothScroll(SmoothScroller smoothScroller) {
    
    // 數(shù)據(jù)以及狀態(tài)的校驗(yàn)
    if (mSmoothScroller != null && smoothScroller != mSmoothScroller && mSmoothScroller.isRunning()) {
        mSmoothScroller.stop();
    }
    mSmoothScroller = smoothScroller;
    
    // 觸發(fā)滾動
    mSmoothScroller.start(mRecyclerView, this);
}

到這里,我們可以發(fā)現(xiàn)慕爬,RecyclerView 的滾動觸發(fā)是由 LayoutManager 調(diào)用窑眯,其控制器的定義是由具體的 Manager 來設(shè)置;

繼續(xù)來分析 SmoothScroller 的源碼

// 抽象類
public static abstract class SmoothScroller{}
/**
 * 線性平滑滾動控制器医窿。
 */
public class LinearSmoothScroller extends RecyclerView.SmoothScroller {
    
    // 其他源碼 ...
    
    /**
     * 當(dāng)滾動到子視圖時,這種方法定義了:child 與 parent 是否應(yīng)該左對齊或右對齊磅甩。
     * 
     * When scrolling towards a child view, this method defines whether we should align the left
     * or the right edge of the child with the parent RecyclerView.
     *
     * @return SNAP_TO_START, SNAP_TO_END or SNAP_TO_ANY;
     */
    protected int getHorizontalSnapPreference() {
        return mTargetVector == null || mTargetVector.x == 0 ? SNAP_TO_ANY :
                mTargetVector.x > 0 ? SNAP_TO_END : SNAP_TO_START;
    }

    /**
     * 當(dāng)滾動到子視圖時,這種方法定義了:child 與 parent 是否應(yīng)該頂對齊或底對齊。
     * 
     * When scrolling towards a child view, this method defines whether we should align the top
     * or the bottom edge of the child with the parent RecyclerView.
     *
     * @return SNAP_TO_START, SNAP_TO_END or SNAP_TO_ANY;
     */
    protected int getVerticalSnapPreference() {
        return mTargetVector == null || mTargetVector.y == 0 ? SNAP_TO_ANY :
                mTargetVector.y > 0 ? SNAP_TO_END : SNAP_TO_START;
    }
    
    // 其他源碼 ... 
}

通過注釋就可以看出:上面兩個方法控制了 childView 的對齊方式姥卢,且是 protected 修飾的方法卷要,那我們完全可以通過自定義返回對齊方式

具體實(shí)現(xiàn)

// 定義滾動控制器
private LinearSmoothScroller smoothScroller;
smoothScroller= new LinearSmoothScroller(inflater.getContext()) {

    // 這里考慮的是垂直列表
    @Override
    protected int getVerticalSnapPreference() {
        
        // 固定返回頂對齊方式
        return SNAP_TO_START;
    }
};

// 設(shè)置滾動目標(biāo) position
smoothScroller.setTargetPosition(index);
// 主動觸發(fā)滾動
recyclerView.getLayoutManager().startSmoothScroll(smoothScroller);

至此渣聚,即可實(shí)現(xiàn)文頭的需求方案;

效果圖

recyclerView導(dǎo)航效果圖.gif
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末僧叉,一起剝皮案震驚了整個濱河市奕枝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瓶堕,老刑警劉巖倍权,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異捞烟,居然都是意外死亡薄声,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門题画,熙熙樓的掌柜王于貴愁眉苦臉地迎上來默辨,“玉大人,你說我怎么就攤上這事苍息∷跣遥” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵竞思,是天一觀的道長表谊。 經(jīng)常有香客問我,道長盖喷,這世上最難降的妖魔是什么爆办? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮课梳,結(jié)果婚禮上距辆,老公的妹妹穿的比我還像新娘。我一直安慰自己暮刃,他們只是感情好跨算,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著椭懊,像睡著了一般诸蚕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上氧猬,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天背犯,我揣著相機(jī)與錄音,去河邊找鬼狂窑。 笑死媳板,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的泉哈。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼丛晦!你這毒婦竟也來了奕纫?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤烫沙,失蹤者是張志新(化名)和其女友劉穎匹层,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體锌蓄,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡升筏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了瘸爽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片您访。...
    茶點(diǎn)故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖剪决,靈堂內(nèi)的尸體忽然破棺而出灵汪,到底是詐尸還是另有隱情,我是刑警寧澤柑潦,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布享言,位于F島的核電站,受9級特大地震影響渗鬼,放射性物質(zhì)發(fā)生泄漏览露。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一譬胎、第九天 我趴在偏房一處隱蔽的房頂上張望肛循。 院中可真熱鬧,春花似錦银择、人聲如沸多糠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽夹孔。三九已至,卻和暖如春析孽,著一層夾襖步出監(jiān)牢的瞬間搭伤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工袜瞬, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留怜俐,地道東北人。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓邓尤,卻偏偏與公主長得像拍鲤,于是被迫代替她去往敵國和親贴谎。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 【Android 控件 RecyclerView】 概述 RecyclerView是什么 從Android 5.0...
    Rtia閱讀 307,509評論 27 439
  • 簡介: 提供一個讓有限的窗口變成一個大數(shù)據(jù)集的靈活視圖季稳。 術(shù)語表: Adapter:RecyclerView的子類...
    酷泡泡閱讀 5,165評論 0 16
  • 簡介 RecyclerView在24.2.0版本中新增了SnapHelper這個輔助類擅这,用于輔助RecyclerV...
    辰之貓閱讀 154,433評論 65 617
  • 馬楠熄了車,從盒子里拿出一只小玩偶景鼠,靠在車上看著仲翎。憋了四十分鐘的幸福此時滿滿地漾了出來。不用操心開車铛漓,一心只用來看...
    凱凱的拖油瓶閱讀 306評論 1 1
  • 兩個噴嚏溯香,驚醒一屋考生。抬望眼浓恶,醉迷離玫坛,何來春蟲唧唧? 還伏桌椅问顷,卻逢頭兒巡紀(jì)昂秃。哪起筆,怎算計(jì)杜窄,熬得落櫻凄凄肠骆!
    碧水浩浩閱讀 217評論 0 0