Android 实现锚点定位
相信做前端的都做过页面锚点定位的功能,通过<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;}@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);}}
布局文件里 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.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 实现锚点定位相关推荐
- Android tabLayout+recyclerView实现锚点定位
原文链接:https://mp.weixin.qq.com/s/L3o2i3WTmg1ScXEYDS8YCg 在上一篇文章 [Android 实现锚点定位 ](https://mp.weixin.qq ...
- android实现3种定位的切换,Android 滑动定位+吸附悬停效果实现
在前两篇文章中,分别介绍了tablayout+scrollview 和 tablayout+recyclerview 实现的滑动定位的功能,文章链接: Android 实现锚点定位 Android t ...
- html增加锚点,html增加锚点定位
第一种方法,也是最简单的方法是锚点用标签,在href属性中写入DIV的id.如下: div { height: 800px; width: 400px; border: 2px solid black ...
- scrollIntoView()实现简单的锚点定位
综述 锚点定位是一个再熟悉不过的操作了,通常会用a标签href=#XX去实现,不过这样做,有一个问题,就是页面会有刷新感,而且地址栏会有变化,F5刷新,则#XXX还是显示在地址栏里,这样如果要进一步进 ...
- 微信小程序-锚点定位+内容滑动控制导航选中
之前两篇文章分别介绍了锚点定位和滑动内容影响导航选中,这里我们就结合起来,实现这两个功能! 思路不再多说,直接上干货! WXML <view class="navigateBox&qu ...
- html 标签、图像、链接、注释、锚点定位、特殊字符
常用的 html 标签 <!-- 1.成对出现的标签:--><h1>h1标题</h1> <div>这是一个div标签</div> <p ...
- 如何用html语言定位img,html经常使用标签(图像标签img,连接标签a,锚点定位,及路径)...
1 图像标签img (重点) 单词缩写: image 图像html HTML网页中任何元素的实现都要依靠HTML标签,要想在网页中显示图像就须要使用图像标签,接下来将详细介绍图像标签以及和他相关的属性 ...
- js锚点定位_overflow属性详解,利用CSS实现锚点定位
1.overflow的裁剪界线--border-box overflow属性用于指定块容器元素的内容溢出时的表现方式--滚动,裁剪,自适应."BFC的最佳结界"只是其衍生出来的特性 ...
- html也没锚点,css 锚点定位不了
css 锚点定位不了 css 锚点定位不了只有一个原因,就是书写错误,锚点的正确书写方式有两种,下面为各位介绍一下. 1.使用a标签设置锚点: ①:设置一个锚点链接 html:(注意:href属性的属 ...
最新文章
- ansible提权操作
- iOS之性能优化·优化App界面的渲染与流畅度
- 职高计算机自我鉴定800字,中专生自我鉴定800字与中专生计算机专业自我鉴定汇编...
- 为什么敏捷开发在亚洲实行不了
- 问题:如何将多个文件里内容都提取出来
- mysql ssh .net_c# – 使用SSH.NET库与MySQL建立SSH连接
- Python:闭包(简介、使用方法、nonlocal修改闭包内使用的外部变量)、装饰器(定义、作用、通用装饰器、多个装饰器、带参数的装饰器、类装饰器、装饰器方式添加WEB框架的路由)
- java restrictions_Restrictions----用法
- Linux定义多个标准输入输出,言简意赅解释Linux中的标准输入输出
- CI Weekly #5 | 微服务架构下的持续部署与交付
- 分享五款可以大幅度提升办公效率的实用软件
- catia如何测量毛料尺寸_CATIA建模规定
- 高效学习工作方法PDCA让你变成心中有梦眼里有光的幸运儿
- JavaScript使用手册、范例
- nacos安装和配置
- 计算机硬件网络设备,[计算机硬件及网络]网络设备的选型.ppt
- Java:实现​lz4格式解压缩算法(附完整源码)
- 【优化求解】基于matlab遗传算法求解立体仓库出入库路径优化问题【含Matlab源码 2028期】
- Tomcat launch tomcat using security manager
- dr5 mac汉化版美容修饰ps插件