相信做前端的都做过页面锚点定位的功能,通过<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;}@Overrideprotected 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.TabLayoutandroid: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.CustomScrollViewandroid:id="@+id/scrollView"android:layout_width="match_parent"android:layout_height="match_parent"android:fillViewport="true"android:fitsSystemWindows="true"><LinearLayoutandroid: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;
//记录上一次位置,防止在同一内容块里滑动 重复定位到tablayout
private int lastPos;//模拟数据,填充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设置标签
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() {@Overridepublic boolean onTouch(View v, MotionEvent event) {//当由scrollview触发时,isScroll 置trueif (event.getAction() == MotionEvent.ACTION_DOWN) {isScroll = true;}return false;}
});scrollView.setCallbacks(new CustomScrollView.Callbacks() {@Overridepublic 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() {@Overridepublic void onTabSelected(TabLayout.Tab tab) {//点击标签,使scrollview滑动,isScroll置falseisScroll = false;int pos = tab.getPosition();int top = anchorList.get(pos).getTop();scrollView.smoothScrollTo(0, top);}@Overridepublic void onTabUnselected(TabLayout.Tab tab) {}@Overridepublic void onTabReselected(TabLayout.Tab tab) {}
});

至此效果出来了,但是
问题来了 可以看到当点击最后一项时,scrollView滑动到底部时并没有呈现出我们想要的效果,希望滑到最后一个时,全屏只有最后一块内容显示。
所以这里需要处理下最后一个view的高度,当不满全屏时,重新设置他的高度,通过计算让其撑满屏幕。

//监听判断最后一个模块的高度,不满一屏时让最后一个模块撑满屏幕
private ViewTreeObserver.OnGlobalLayoutListener listener;listener = new ViewTreeObserver.OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {int screenH = getScreenHeight();int statusBarH = getStatusBarHeight(MainActivity.this);int tabH = tabLayout.getHeight();//计算内容块所在的高度,全屏高度-状态栏高度-tablayout的高度-内容container的padding 16dpint 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 实现锚点定位相关推荐

  1. Android tabLayout+recyclerView实现锚点定位

    原文链接:https://mp.weixin.qq.com/s/L3o2i3WTmg1ScXEYDS8YCg 在上一篇文章 [Android 实现锚点定位 ](https://mp.weixin.qq ...

  2. android实现3种定位的切换,Android 滑动定位+吸附悬停效果实现

    在前两篇文章中,分别介绍了tablayout+scrollview 和 tablayout+recyclerview 实现的滑动定位的功能,文章链接: Android 实现锚点定位 Android t ...

  3. html增加锚点,html增加锚点定位

    第一种方法,也是最简单的方法是锚点用标签,在href属性中写入DIV的id.如下: div { height: 800px; width: 400px; border: 2px solid black ...

  4. scrollIntoView()实现简单的锚点定位

    综述 锚点定位是一个再熟悉不过的操作了,通常会用a标签href=#XX去实现,不过这样做,有一个问题,就是页面会有刷新感,而且地址栏会有变化,F5刷新,则#XXX还是显示在地址栏里,这样如果要进一步进 ...

  5. 微信小程序-锚点定位+内容滑动控制导航选中

    之前两篇文章分别介绍了锚点定位和滑动内容影响导航选中,这里我们就结合起来,实现这两个功能! 思路不再多说,直接上干货! WXML <view class="navigateBox&qu ...

  6. html 标签、图像、链接、注释、锚点定位、特殊字符

    常用的 html 标签 <!-- 1.成对出现的标签:--><h1>h1标题</h1> <div>这是一个div标签</div> <p ...

  7. 如何用html语言定位img,html经常使用标签(图像标签img,连接标签a,锚点定位,及路径)...

    1 图像标签img (重点) 单词缩写: image 图像html HTML网页中任何元素的实现都要依靠HTML标签,要想在网页中显示图像就须要使用图像标签,接下来将详细介绍图像标签以及和他相关的属性 ...

  8. js锚点定位_overflow属性详解,利用CSS实现锚点定位

    1.overflow的裁剪界线--border-box overflow属性用于指定块容器元素的内容溢出时的表现方式--滚动,裁剪,自适应."BFC的最佳结界"只是其衍生出来的特性 ...

  9. html也没锚点,css 锚点定位不了

    css 锚点定位不了 css 锚点定位不了只有一个原因,就是书写错误,锚点的正确书写方式有两种,下面为各位介绍一下. 1.使用a标签设置锚点: ①:设置一个锚点链接 html:(注意:href属性的属 ...

最新文章

  1. ansible提权操作
  2. iOS之性能优化·优化App界面的渲染与流畅度
  3. 职高计算机自我鉴定800字,中专生自我鉴定800字与中专生计算机专业自我鉴定汇编...
  4. 为什么敏捷开发在亚洲实行不了
  5. 问题:如何将多个文件里内容都提取出来
  6. mysql ssh .net_c# – 使用SSH.NET库与MySQL建立SSH连接
  7. Python:闭包(简介、使用方法、nonlocal修改闭包内使用的外部变量)、装饰器(定义、作用、通用装饰器、多个装饰器、带参数的装饰器、类装饰器、装饰器方式添加WEB框架的路由)
  8. java restrictions_Restrictions----用法
  9. Linux定义多个标准输入输出,言简意赅解释Linux中的标准输入输出
  10. CI Weekly #5 | 微服务架构下的持续部署与交付
  11. 分享五款可以大幅度提升办公效率的实用软件
  12. catia如何测量毛料尺寸_CATIA建模规定
  13. 高效学习工作方法PDCA让你变成心中有梦眼里有光的幸运儿
  14. JavaScript使用手册、范例
  15. nacos安装和配置
  16. 计算机硬件网络设备,[计算机硬件及网络]网络设备的选型.ppt
  17. Java:实现​lz4格式解压缩算法(附完整源码)
  18. 【优化求解】基于matlab遗传算法求解立体仓库出入库路径优化问题【含Matlab源码 2028期】
  19. Tomcat launch tomcat using security manager
  20. dr5 mac汉化版美容修饰ps插件

热门文章

  1. CodeIgniter 合作paypal
  2. matplotlib常用函数(更新中)
  3. Oracle Hint(提示)与常用方法
  4. RabbitMQ实现生产者发送消息异步confirm
  5. 华为机试——句子逆序
  6. 生产者消费者模型 java
  7. 更新显示当前歌曲的名称 winform 0130
  8. 实体与标识符的理解 0125
  9. linux-vim-文本编辑
  10. python-操作数据库的练习