Android 實現錨點定位

來源:互聯網
上載者:User

標籤:win   xmlns   計算   ongl   scroll   cat   eve   -o   one   

相信做前端的都做過頁面錨點定位的功能,通過<a href="#head"> 去設定頁面內錨點定位跳轉。
本篇文章就使用tablayoutscrollview來實現android錨點定位的功能。

實現思路

1、監聽scrollview滑動到的位置,tablayout切換到對應標籤
2、tablayout各標籤點擊,scrollview可滑動到對應地區

自訂scrollview

因為我們需要監聽到滑動過程中scrollview的滑動距離,自訂scrollview通過介面暴露滑動的距離。

public class CustomScrollView extends ScrollView {    public Callbacks mCallbacks;    public CustomScrollView(Context context) {        super(context);    }    public CustomScrollView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public CustomScrollView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    public void setCallbacks(Callbacks callbacks) {        this.mCallbacks = callbacks;    }    @Override    protected void onScrollChanged(int l, int t, int oldl, int oldt) {        super.onScrollChanged(l, t, oldl, oldt);        if (mCallbacks != null) {            mCallbacks.onScrollChanged(l, t, oldl, oldt);        }    }    //定義介面用於回調    public interface Callbacks {        void onScrollChanged(int x, int y, int oldx, int oldy);    }}

布局檔案裡 tablayoutCustomScrollView,內容暫時使用LinearLayout填充。

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <android.support.design.widget.TabLayout        android:id="@+id/tablayout"        android:layout_width="match_parent"        android:layout_height="wrap_content"        app:tabIndicatorColor="@color/colorPrimary"        app:tabMode="scrollable"        app:tabSelectedTextColor="@color/colorPrimary" />    <com.tabscroll.CustomScrollView        android:id="@+id/scrollView"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:fillViewport="true"        android:fitsSystemWindows="true">        <LinearLayout            android:id="@+id/container"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:orientation="vertical"            android:padding="16dp">        </LinearLayout>    </com.tabscroll.CustomScrollView></LinearLayout>
資料類比

資料類比,動態添加scrollview內的內容,這裡自訂了AnchorView當作每一塊的填充內容。

private String[] tabTxt = {"客廳", "臥室", "餐廳", "書房", "陽台", "兒童房"};//內容塊view的集合private List<AnchorView> anchorList = new ArrayList<>();//判讀是否是scrollview主動引起的滑動,true-是,false-否,由tablayout引起的private boolean isScroll;//記錄上一次位置,防止在同一內容塊裡滑動 重複定位到tablayoutprivate int lastPos;//類比資料,填充scrollviewfor (int i = 0; i < tabTxt.length; i++) {    AnchorView anchorView = new AnchorView(this);    anchorView.setAnchorTxt(tabTxt[i]);    anchorView.setContentTxt(tabTxt[i]);    anchorList.add(anchorView);    container.addView(anchorView);}//tablayout設定標籤for (int i = 0; i < tabTxt.length; i++) {    tabLayout.addTab(tabLayout.newTab().setText(tabTxt[i]));}

定義變數標誌isScroll,用於判斷scrollview的滑動由誰引起的,避免通過點擊tabLayout引起的scrollview滑動問題。
定義變數標誌lastPos,當scrollview 在同一模組中滑動時,則不再去調用tabLayout.setScrollPosition重新整理標籤。

自訂的AnchorView

public class AnchorView extends LinearLayout {    private TextView tvAnchor;    private TextView tvContent;    public AnchorView(Context context) {        this(context, null);    }    public AnchorView(Context context, @Nullable AttributeSet attrs) {        this(context, attrs, 0);    }    public AnchorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init(context);    }    private void init(Context context) {        View view = LayoutInflater.from(context).inflate(R.layout.view_anchor, this, true);        tvAnchor = view.findViewById(R.id.tv_anchor);        tvContent = view.findViewById(R.id.tv_content);        Random random = new Random();        int r = random.nextInt(256);        int g = random.nextInt(256);        int b = random.nextInt(256);        tvContent.setBackgroundColor(Color.rgb(r, g, b));    }    public void setAnchorTxt(String txt) {        tvAnchor.setText(txt);    }    public void setContentTxt(String txt) {        tvContent.setText(txt);    }}
實現

scrollview的滑動監聽:

scrollView.setOnTouchListener(new View.OnTouchListener() {    @Override    public boolean onTouch(View v, MotionEvent event) {        //當由scrollview觸發時,isScroll 置true        if (event.getAction() == MotionEvent.ACTION_DOWN) {            isScroll = true;        }        return false;    }});scrollView.setCallbacks(new CustomScrollView.Callbacks() {    @Override    public void onScrollChanged(int x, int y, int oldx, int oldy) {        if (isScroll) {            for (int i = tabTxt.length - 1; i >= 0; i--) {                //根據滑動距離,對比各模組距離父布局頂部的高度判斷                if (y > anchorList.get(i).getTop() - 10) {                    setScrollPos(i);                    break;                }            }        }    }});//tablayout對應標籤的切換private void setScrollPos(int newPos) {    if (lastPos != newPos) {        //該方法不會觸發tablayout 的onTabSelected 監聽        tabLayout.setScrollPosition(newPos, 0, true);    }    lastPos = newPos;}

tabLayout的點擊切換:

tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {    @Override    public void onTabSelected(TabLayout.Tab tab) {        //點擊標籤,使scrollview滑動,isScroll置false        isScroll = false;        int pos = tab.getPosition();        int top = anchorList.get(pos).getTop();        scrollView.smoothScrollTo(0, top);    }    @Override    public void onTabUnselected(TabLayout.Tab tab) {    }    @Override    public void onTabReselected(TabLayout.Tab tab) {    }});

至此效果出來了,但是
問題來了 可以看到當點擊最後一項時,scrollView滑動到底部時並沒有呈現出我們想要的效果,希望滑到最後一個時,全屏只有最後一塊內容顯示。
所以這裡需要處理下最後一個view的高度,當不滿全屏時,重新設定他的高度,通過計算讓其撐滿螢幕。

//監聽判斷最後一個模組的高度,不滿一屏時讓最後一個模組撐滿螢幕private ViewTreeObserver.OnGlobalLayoutListener listener;listener = new ViewTreeObserver.OnGlobalLayoutListener() {    @Override    public void onGlobalLayout() {        int screenH = getScreenHeight();        int statusBarH = getStatusBarHeight(MainActivity.this);        int tabH = tabLayout.getHeight();        //計算內容塊所在的高度,全屏高度-狀態列高度-tablayout的高度-內容container的padding 16dp        int lastH = screenH - statusBarH - tabH - 16 * 3;        AnchorView lastView = anchorList.get(anchorList.size() - 1);        //當最後一個view 高度小於內容塊高度時,設定其高度撐滿        if (lastView.getHeight() < lastH) {            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);            params.height = lastH;            lastView.setLayoutParams(params);        }        container.getViewTreeObserver().removeOnGlobalLayoutListener(listener);    }};container.getViewTreeObserver().addOnGlobalLayoutListener(listener);

這樣就達到了預期的效果了。

寫到這裡,tablayout + scrollview的錨點定位成型了,在實際項目中,我們還可以使用tablayout + recyclerview 來完成同樣的效果,後續的話會帶來這樣的文章。

這段時間自己在做一個小程式,包括資料爬取 + 後台 + 小程式的,可能要過段時間才能出來,主要是資料爬蟲那邊比較麻煩的...期待下!

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

歡迎關注我的部落格:https://blog.manjiexiang.cn/
更多精彩歡迎關注號:春風十裡不如認識你

有個「佛系碼農圈」,歡迎大家加入暢聊,開心就好!

到期了,可加我 tx467220125 拉你入群。

Android 實現錨點定位

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.