资讯专栏INFORMATION COLUMN

Android 实现锚点定位

dendoink / 609人阅读

摘要:原文链接相信做前端的都做过页面锚点定位的功能,通过去设置页面内锚点定位跳转。本篇文章就使用来实现锚点定位的功能。写到这里,的锚点定位成型了,在实际项目中,我们还可以使用来完成同样的效果,后续的话会带来这样的文章。

</>复制代码

  1. 原文链接:https://mp.weixin.qq.com/s/EYyTBtM9qCdmB9nlDEF-3w

相信做前端的都做过页面锚点定位的功能,通过 去设置页面内锚点定位跳转。
本篇文章就使用tablayoutscrollview来实现android锚点定位的功能。
效果图:

实现思路

1、监听scrollview滑动到的位置,tablayout切换到对应标签
2、tablayout各标签点击,scrollview可滑动到对应区域

自定义scrollview

因为我们需要监听到滑动过程中scrollview的滑动距离,自定义scrollview通过接口暴露滑动的距离。

</>复制代码

  1. public class CustomScrollView extends ScrollView {
  2. public Callbacks mCallbacks;
  3. public CustomScrollView(Context context) {
  4. super(context);
  5. }
  6. public CustomScrollView(Context context, AttributeSet attrs) {
  7. super(context, attrs);
  8. }
  9. public CustomScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
  10. super(context, attrs, defStyleAttr);
  11. }
  12. public void setCallbacks(Callbacks callbacks) {
  13. this.mCallbacks = callbacks;
  14. }
  15. @Override
  16. protected void onScrollChanged(int l, int t, int oldl, int oldt) {
  17. super.onScrollChanged(l, t, oldl, oldt);
  18. if (mCallbacks != null) {
  19. mCallbacks.onScrollChanged(l, t, oldl, oldt);
  20. }
  21. }
  22. //定义接口用于回调
  23. public interface Callbacks {
  24. void onScrollChanged(int x, int y, int oldx, int oldy);
  25. }
  26. }

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

</>复制代码

数据模拟

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

</>复制代码

  1. private String[] tabTxt = {"客厅", "卧室", "餐厅", "书房", "阳台", "儿童房"};
  2. //内容块view的集合
  3. private List anchorList = new ArrayList<>();
  4. //判读是否是scrollview主动引起的滑动,true-是,false-否,由tablayout引起的
  5. private boolean isScroll;
  6. //记录上一次位置,防止在同一内容块里滑动 重复定位到tablayout
  7. private int lastPos;
  8. //模拟数据,填充scrollview
  9. for (int i = 0; i < tabTxt.length; i++) {
  10. AnchorView anchorView = new AnchorView(this);
  11. anchorView.setAnchorTxt(tabTxt[i]);
  12. anchorView.setContentTxt(tabTxt[i]);
  13. anchorList.add(anchorView);
  14. container.addView(anchorView);
  15. }
  16. //tablayout设置标签
  17. for (int i = 0; i < tabTxt.length; i++) {
  18. tabLayout.addTab(tabLayout.newTab().setText(tabTxt[i]));
  19. }

定义变量标志isScroll,用于判断scrollview的滑动由谁引起的,避免通过点击tabLayout引起的scrollview滑动问题。
定义变量标志lastPos,当scrollview 在同一模块中滑动时,则不再去调用tabLayout.setScrollPosition刷新标签。

自定义的AnchorView

</>复制代码

  1. public class AnchorView extends LinearLayout {
  2. private TextView tvAnchor;
  3. private TextView tvContent;
  4. public AnchorView(Context context) {
  5. this(context, null);
  6. }
  7. public AnchorView(Context context, @Nullable AttributeSet attrs) {
  8. this(context, attrs, 0);
  9. }
  10. public AnchorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
  11. super(context, attrs, defStyleAttr);
  12. init(context);
  13. }
  14. private void init(Context context) {
  15. View view = LayoutInflater.from(context).inflate(R.layout.view_anchor, this, true);
  16. tvAnchor = view.findViewById(R.id.tv_anchor);
  17. tvContent = view.findViewById(R.id.tv_content);
  18. Random random = new Random();
  19. int r = random.nextInt(256);
  20. int g = random.nextInt(256);
  21. int b = random.nextInt(256);
  22. tvContent.setBackgroundColor(Color.rgb(r, g, b));
  23. }
  24. public void setAnchorTxt(String txt) {
  25. tvAnchor.setText(txt);
  26. }
  27. public void setContentTxt(String txt) {
  28. tvContent.setText(txt);
  29. }
  30. }
实现

scrollview的滑动监听:

</>复制代码

  1. scrollView.setOnTouchListener(new View.OnTouchListener() {
  2. @Override
  3. public boolean onTouch(View v, MotionEvent event) {
  4. //当由scrollview触发时,isScroll 置true
  5. if (event.getAction() == MotionEvent.ACTION_DOWN) {
  6. isScroll = true;
  7. }
  8. return false;
  9. }
  10. });
  11. scrollView.setCallbacks(new CustomScrollView.Callbacks() {
  12. @Override
  13. public void onScrollChanged(int x, int y, int oldx, int oldy) {
  14. if (isScroll) {
  15. for (int i = tabTxt.length - 1; i >= 0; i--) {
  16. //根据滑动距离,对比各模块距离父布局顶部的高度判断
  17. if (y > anchorList.get(i).getTop() - 10) {
  18. setScrollPos(i);
  19. break;
  20. }
  21. }
  22. }
  23. }
  24. });
  25. //tablayout对应标签的切换
  26. private void setScrollPos(int newPos) {
  27. if (lastPos != newPos) {
  28. //该方法不会触发tablayout 的onTabSelected 监听
  29. tabLayout.setScrollPosition(newPos, 0, true);
  30. }
  31. lastPos = newPos;
  32. }

tabLayout的点击切换:

</>复制代码

  1. tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
  2. @Override
  3. public void onTabSelected(TabLayout.Tab tab) {
  4. //点击标签,使scrollview滑动,isScroll置false
  5. isScroll = false;
  6. int pos = tab.getPosition();
  7. int top = anchorList.get(pos).getTop();
  8. scrollView.smoothScrollTo(0, top);
  9. }
  10. @Override
  11. public void onTabUnselected(TabLayout.Tab tab) {
  12. }
  13. @Override
  14. public void onTabReselected(TabLayout.Tab tab) {
  15. }
  16. });

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

</>复制代码

  1. //监听判断最后一个模块的高度,不满一屏时让最后一个模块撑满屏幕
  2. private ViewTreeObserver.OnGlobalLayoutListener listener;
  3. listener = new ViewTreeObserver.OnGlobalLayoutListener() {
  4. @Override
  5. public void onGlobalLayout() {
  6. int screenH = getScreenHeight();
  7. int statusBarH = getStatusBarHeight(MainActivity.this);
  8. int tabH = tabLayout.getHeight();
  9. //计算内容块所在的高度,全屏高度-状态栏高度-tablayout的高度-内容container的padding 16dp
  10. int lastH = screenH - statusBarH - tabH - 16 * 3;
  11. AnchorView lastView = anchorList.get(anchorList.size() - 1);
  12. //当最后一个view 高度小于内容块高度时,设置其高度撑满
  13. if (lastView.getHeight() < lastH) {
  14. LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
  15. params.height = lastH;
  16. lastView.setLayoutParams(params);
  17. }
  18. container.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
  19. }
  20. };
  21. container.getViewTreeObserver().addOnGlobalLayoutListener(listener);

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

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

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

详细代码见
github地址:https://github.com/taixiang/tabScroll

欢迎关注我的博客:https://blog.manjiexiang.cn/
更多精彩欢迎关注微信号:春风十里不如认识你

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

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/76440.html

相关文章

发表评论

0条评论

dendoink

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<