標籤:win xmlns 計算 ongl scroll cat eve -o one
相信做前端的都做過頁面錨點定位的功能,通過<a href="#head">
去設定頁面內錨點定位跳轉。
本篇文章就使用tablayout
、scrollview
來實現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); }}
布局檔案裡 tablayout
和 CustomScrollView
,內容暫時使用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 實現錨點定位