1. 程式人生 > >Android tabLayout+recyclerView實現錨點定位

Android tabLayout+recyclerView實現錨點定位

ons boolean 根據 https set ret 需要 tco int

原文鏈接:https://mp.weixin.qq.com/s/L3o2i3WTmg1ScXEYDS8YCg

在上一篇文章 Android 實現錨點定位中,我們介紹了tablayout+scrollView實現的錨點定位,今天我們使用tablayout+recyclerView 來實現同樣的效果。
效果圖:

技術分享圖片

實現思路

實現的思路與上一篇文章是一致的:
1、監聽recyclerView滑動到的位置,tablayout切換到對應標簽
2、tablayout各標簽點擊,recyclerView可滑動到對應區域

數據模擬

數據模擬,使用上一文章的AnchorView作為recyclerView的每個字view,同時這裏對recyclerView

的最後一個子view的高度進行修改,讓其充滿屏幕。

private LinearLayoutManager manager;
private String[] tabTxt = {"客廳", "臥室", "餐廳", "書房", "陽臺", "兒童房"};
//判讀是否是recyclerView主動引起的滑動,true- 是,false- 否,由tablayout引起的
private boolean isRecyclerScroll;
//記錄上一次位置,防止在同一內容塊裏滑動 重復定位到tablayout
private int lastPos;
//用於recyclerView滑動到指定的位置
private boolean canScroll;
private int scrollToPosition;

//tablayout設置標簽
for (int i = 0; i < tabTxt.length; i++) {
    tabLayout.addTab(tabLayout.newTab().setText(tabTxt[i]));
}

//計算內容塊所在的高度,全屏高度-狀態欄高度-tablayout的高度(這裏固定高度50dp),用於recyclerView的最後一個item view填充高度
int screenH = getScreenHeight();
int statusBarH = getStatusBarHeight(this);
int tabH = 50 * 3;
int lastH = screenH - statusBarH - tabH;
manager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(manager);
recyclerView.setAdapter(new MyAdapter(this, tabTxt, lastH));


@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
    holder.anchorView.setContentTxt(tabTxt[position]);
    holder.anchorView.setAnchorTxt(tabTxt[position]);
    //判斷最後一個view
    if (position == tabTxt.length - 1) {
        if (holder.anchorView.getHeight() < lastH) {
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            params.height = lastH;
            holder.anchorView.setLayoutParams(params);
        }
    }
}

recyclerView滑動定位

recyclerView滑動引起的,addOnScrollListeneronScrolled的監聽第一個可見view的位置,直接將tablayout定位到相應的位置。

recyclerView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        //當滑動由recyclerView觸發時,isRecyclerScroll 置true
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            isRecyclerScroll = true;
        }
        return false;
    }
});

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        if (isRecyclerScroll) {
            //第一個可見的view的位置,即tablayou需定位的位置
            int position = manager.findFirstVisibleItemPosition();
            if (lastPos != position) {
                tabLayout.setScrollPosition(position, 0, true);
            }
            lastPos = position;
        }
    }
});

tablayout切換定位

點擊tablayout進行切換,recyclerView需要滑動到相應的位置,註意這裏需要根據跳轉位置不同,進行相應的滑動。

tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
    @Override
    public void onTabSelected(TabLayout.Tab tab) {
        //點擊標簽,使recyclerView滑動,isRecyclerScroll置false
        int pos = tab.getPosition();
        isRecyclerScroll = false;
        moveToPosition(manager, recyclerView, pos);
    }

    @Override
    public void onTabUnselected(TabLayout.Tab tab) {

    }

    @Override
    public void onTabReselected(TabLayout.Tab tab) {

    }
});


public void moveToPosition(LinearLayoutManager manager, RecyclerView mRecyclerView, int position) {
    // 第一個可見的view的位置
    int firstItem = manager.findFirstVisibleItemPosition();
    // 最後一個可見的view的位置
    int lastItem = manager.findLastVisibleItemPosition();
    if (position <= firstItem) {
        // 如果跳轉位置firstItem 之前(滑出屏幕的情況),就smoothScrollToPosition可以直接跳轉,
        mRecyclerView.smoothScrollToPosition(position);
    } else if (position <= lastItem) {
        // 跳轉位置在firstItem 之後,lastItem 之間(顯示在當前屏幕),smoothScrollBy來滑動到指定位置
        int top = mRecyclerView.getChildAt(position - firstItem).getTop();
        mRecyclerView.smoothScrollBy(0, top);
    } else {
        // 如果要跳轉的位置在lastItem 之後,則先調用smoothScrollToPosition將要跳轉的位置滾動到可見位置
        // 再通過onScrollStateChanged控制再次調用當前moveToPosition方法,執行上一個判斷中的方法
        mRecyclerView.smoothScrollToPosition(position);
        scrollToPosition = position;
        canScroll = true;
    }
}

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        if (canScroll) {
            canScroll = false;
            moveToPosition(manager, recyclerView, scrollToPosition);
        }
    }
});

至此,兩種實現錨點定位的方法就介紹到這裏,希望能幫助到讀者在實際項目中的使用。
代碼與上一篇文章的在同一個git地址裏。

詳細代碼見
github地址:https://github.com/taixiang/tabScroll

歡迎關註我的博客:https://blog.manjiexiang.cn/
更多精彩歡迎關註微信號:春風十裏不如認識你
技術分享圖片

有個「佛系碼農圈」,歡迎大家加入暢聊,開心就好!
技術分享圖片
過期了,可加我微信 tx467220125 拉你入群。

Android tabLayout+recyclerView實現錨點定位