首页 > 系统 > Android > 正文

Android 实现锚点定位思路详解

2019-10-21 21:45:52
字体:
来源:转载
供稿:网友

相信做前端的都做过页面锚点定位的功能,通过<a href="#head" rel="external nofollow" > 去设置页面内锚点定位跳转。

本篇文章就使用tablayout、scrollview来实现android锚点定位的功能。

效果图:

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) { }});

至此效果出来了,但是

Android,锚点,定位

问题来了 可以看到当点击最后一项时,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);

这样就达到了预期的效果了。

Android,锚点,定位

写到这里,tablayout + scrollview的锚点定位成型了,在实际项目中,我们还可以使用tablayout + recyclerview 来完成同样的效果,后续的话会带来这样的文章。

这段时间自己在做一个小程序,包括数据爬取 + 后台 + 小程序的,可能要过段时间才能出来,主要是数据爬虫那边比较麻烦的...期待下!

详细代码见

github地址:https://github.com/taixiang/tabScroll

总结

以上所述是小编给大家介绍的Android 实现锚点定位思路详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对VEVB武林网网站的支持!


注:相关教程知识阅读请移步到Android开发频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表