Android 實(shí)現(xiàn)錨點(diǎn)定位思路詳解
相信做前端的都做過頁面錨點(diǎn)定位的功能,通過<a href="#head" rel="external nofollow" >
去設(shè)置頁面內(nèi)錨點(diǎn)定位跳轉(zhuǎn)。
本篇文章就使用tablayout、scrollview來實(shí)現(xiàn)android錨點(diǎn)定位的功能。
效果圖:
實(shí)現(xiàn)思路
1、監(jiān)聽scrollview滑動(dòng)到的位置,tablayout切換到對(duì)應(yīng)標(biāo)簽
2、tablayout各標(biāo)簽點(diǎn)擊,scrollview可滑動(dòng)到對(duì)應(yīng)區(qū)域
自定義scrollview
因?yàn)槲覀冃枰O(jiān)聽到滑動(dòng)過程中scrollview的滑動(dòng)距離,自定義scrollview通過接口暴露滑動(dòng)的距離。
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); } } //定義接口用于回調(diào) public interface Callbacks { void onScrollChanged(int x, int y, int oldx, int oldy); } }
布局文件里 tablayout 和 CustomScrollView,內(nèi)容暫時(shí)使用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>
數(shù)據(jù)模擬
數(shù)據(jù)模擬,動(dòng)態(tài)添加scrollview內(nèi)的內(nèi)容,這里自定義了AnchorView當(dāng)作每一塊的填充內(nèi)容。
private String[] tabTxt = {"客廳", "臥室", "餐廳", "書房", "陽臺(tái)", "兒童房"}; //內(nèi)容塊view的集合 private List<AnchorView> anchorList = new ArrayList<>(); //判讀是否是scrollview主動(dòng)引起的滑動(dòng),true-是,false-否,由tablayout引起的 private boolean isScroll; //記錄上一次位置,防止在同一內(nèi)容塊里滑動(dòng) 重復(fù)定位到tablayout private int lastPos; //模擬數(shù)據(jù),填充scrollview for (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設(shè)置標(biāo)簽 for (int i = 0; i < tabTxt.length; i++) { tabLayout.addTab(tabLayout.newTab().setText(tabTxt[i])); }
定義變量標(biāo)志isScroll,用于判斷scrollview的滑動(dòng)由誰引起的,避免通過點(diǎn)擊tabLayout引起的scrollview滑動(dòng)問題。
定義變量標(biāo)志lastPos,當(dāng)scrollview 在同一模塊中滑動(dòng)時(shí),則不再去調(diào)用tabLayout.setScrollPosition刷新標(biāo)簽。
自定義的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); } }
實(shí)現(xiàn)
scrollview的滑動(dòng)監(jiān)聽:
scrollView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { //當(dāng)由scrollview觸發(fā)時(shí),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--) { //根據(jù)滑動(dòng)距離,對(duì)比各模塊距離父布局頂部的高度判斷 if (y > anchorList.get(i).getTop() - 10) { setScrollPos(i); break; } } } } }); //tablayout對(duì)應(yīng)標(biāo)簽的切換 private void setScrollPos(int newPos) { if (lastPos != newPos) { //該方法不會(huì)觸發(fā)tablayout 的onTabSelected 監(jiān)聽 tabLayout.setScrollPosition(newPos, 0, true); } lastPos = newPos; } tabLayout的點(diǎn)擊切換: tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { @Override public void onTabSelected(TabLayout.Tab tab) { //點(diǎn)擊標(biāo)簽,使scrollview滑動(dòng),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) { } });
至此效果出來了,但是
問題來了 可以看到當(dāng)點(diǎn)擊最后一項(xiàng)時(shí),scrollView滑動(dòng)到底部時(shí)并沒有呈現(xiàn)出我們想要的效果,希望滑到最后一個(gè)時(shí),全屏只有最后一塊內(nèi)容顯示。
所以這里需要處理下最后一個(gè)view的高度,當(dāng)不滿全屏?xí)r,重新設(shè)置他的高度,通過計(jì)算讓其撐滿屏幕。
//監(jiān)聽判斷最后一個(gè)模塊的高度,不滿一屏?xí)r讓最后一個(gè)模塊撐滿屏幕 private ViewTreeObserver.OnGlobalLayoutListener listener; listener = new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { int screenH = getScreenHeight(); int statusBarH = getStatusBarHeight(MainActivity.this); int tabH = tabLayout.getHeight(); //計(jì)算內(nèi)容塊所在的高度,全屏高度-狀態(tài)欄高度-tablayout的高度-內(nèi)容container的padding 16dp int lastH = screenH - statusBarH - tabH - 16 * 3; AnchorView lastView = anchorList.get(anchorList.size() - 1); //當(dāng)最后一個(gè)view 高度小于內(nèi)容塊高度時(shí),設(shè)置其高度撐滿 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);
這樣就達(dá)到了預(yù)期的效果了。
寫到這里,tablayout + scrollview的錨點(diǎn)定位成型了,在實(shí)際項(xiàng)目中,我們還可以使用tablayout + recyclerview 來完成同樣的效果,后續(xù)的話會(huì)帶來這樣的文章。
這段時(shí)間自己在做一個(gè)小程序,包括數(shù)據(jù)爬取 + 后臺(tái) + 小程序的,可能要過段時(shí)間才能出來,主要是數(shù)據(jù)爬蟲那邊比較麻煩的...期待下!
詳細(xì)代碼見
github地址:https://github.com/taixiang/tabScroll
總結(jié)
以上所述是小編給大家介紹的Android 實(shí)現(xiàn)錨點(diǎn)定位思路詳解,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
Android進(jìn)度條控件progressbar使用方法詳解
這篇文章主要為大家詳細(xì)介紹了Android進(jìn)度條控件progressbar的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08Android實(shí)現(xiàn)定制返回按鈕動(dòng)畫效果的方法
這篇文章主要介紹了Android實(shí)現(xiàn)定制返回按鈕動(dòng)畫效果的方法,涉及Android控件及動(dòng)畫的相關(guān)操作技巧,需要的朋友可以參考下2016-02-02Android利用MPAndroidChart繪制曲線圖表的基礎(chǔ)教程
最近在項(xiàng)目中要用到曲線圖,于是在網(wǎng)上找了很多很多,有AChartengine,MPAndroidChart,helloChart等等,我還用過基于html5的jsChart來做過,不過最終還是選擇了MPAndroidChart來做本文介紹了Android利用MPAndroidChart繪制曲線圖表的基礎(chǔ)教程,需要的朋友可以參考下。2018-03-03android仿微信表情雨下落效果的實(shí)現(xiàn)方法
這篇文章主要給大家介紹了關(guān)于android仿微信表情雨下落效果的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09Android開發(fā)實(shí)現(xiàn)各種圖形繪制功能示例
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)各種圖形繪制功能,結(jié)合實(shí)例形式分析了Android圖形繪制常用的組件、函數(shù)使用方法及相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-09-09Android開發(fā)雙向滑動(dòng)選擇器范圍SeekBar實(shí)現(xiàn)
這篇文章主要為大家介紹了Android開發(fā)雙向滑動(dòng)范圍選擇器SeekBar實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06使用Win10+Android+夜神安卓模擬器,搭建ReactNative開發(fā)環(huán)境
今天小編就為大家分享一篇關(guān)于使用Win10+Android+夜神安卓模擬器,搭建ReactNative開發(fā)環(huán)境,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-10-10