博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 实现锚点定位
阅读量:6208 次
发布时间:2019-06-21

本文共 5993 字,大约阅读时间需要 19 分钟。

原文链接:

相信做前端的都做过页面锚点定位的功能,通过<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;    }    @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);    }}

布局文件里 tablayoutCustomScrollView,内容暂时使用LinearLayout填充。

数据模拟

数据模拟,动态添加scrollview内的内容,这里自定义了AnchorView当作每一块的填充内容。

private String[] tabTxt = {"客厅", "卧室", "餐厅", "书房", "阳台", "儿童房"};//内容块view的集合private List
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地址:

欢迎关注我的博客:

更多精彩欢迎关注微信号:春风十里不如认识你
image.png

有个「佛系码农圈」,欢迎大家加入畅聊,开心就好!

过期了,可加我微信 tx467220125 拉你入群。

转载地址:http://nrqca.baihongyu.com/

你可能感兴趣的文章
BeanShell自动装箱拆箱
查看>>
**加密解密基础、PKI及SSL、创建私有CA**
查看>>
python 脚本学习(二)
查看>>
CSS设计指南(读书笔记 - 背景)
查看>>
谈谈IP和MAC捆绑的破解之道
查看>>
python 找出监听的端口号对号显示
查看>>
使用 Servlet 读取表单数据
查看>>
phpMyAdmin安装
查看>>
计划备份mysql数据库
查看>>
Tcp_wrapper
查看>>
Unity3D项目开发一点经验
查看>>
Oracle Study之--Oracle等待事件(5)
查看>>
Lync Server 2013无法共享PPT故障排错处理
查看>>
Citrix、Microsoft、VMware虚拟桌面之网页接口登录对比
查看>>
华为产品技术学习笔记之路由原理(一)
查看>>
RedHat5.2下Linux Oracle 10g ASM 安装详细实录-第二篇-ASM安装
查看>>
[转]Android笔记:ScrollView嵌套ViewPager的滚动冲突解决方法
查看>>
乱花渐欲迷人眼-杜绝设计的视噪
查看>>
JAVA 网络编程小记
查看>>
JPDA 架构研究5 - Agent利用环境指针访问VM (内存管理篇)
查看>>