Android TabLayout+ScrollView 实现仿html锚点

来源:互联网 发布:mac更新后重启黑屏 编辑:程序博客网 时间:2024/04/30 02:51

概述

在浏览网页的时候,如果网页内容过长,添加网页内部导航会增加用户体验,也就是添加锚点。
这里是用 TabLayout+ScrollView 为页面添加锚点,实现仿html页面导航功能。

TabLayout+ScrollView 实现仿html锚点

先顺一下思路,2点功能:

  1. 点击TabLayout条目的时候,对应区域滑动到当前展示位置
  2. 滑动ScrollView,对应的标签变为选中状态,并且移动到中间位置

这里需要考虑一个问题:如果点击TabLayout条目,内容区域ScrollView发生改变,这种状态下ScrollView滑动是不会导致TabLayout条目发生改变的。


知识点

1、TabLayout的选中监听

 mTabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {            @Override            public void onTabSelected(TabLayout.Tab tab) {                int position = tab.getPosition();                // 根据点击的位置,使ScrollView 滑动到对应区域                  ......            }            @Override            public void onTabUnselected(TabLayout.Tab tab) {            }            @Override            public void onTabReselected(TabLayout.Tab tab) {            }        });

2、ScrollView 的滑动监听

sv_bodyContainer.setScrollViewListener(new ScrollChangedScrollView.ScrollViewListener() {            @Override            public void onScrollChanged(ScrollView scrollView, int x, int y, int oldx, int oldy) {                // 根据滑动到的当前位置,改变TabLayout的选中位置            }            @Override            public void onScrollStop(boolean isStop) {            }        });

3、获得ScrollView滑动距离

   int scrollY = scrollView.getScrollY();

4、TabLayout 滑动到指定位置

  mTabLayout.setScrollPosition(int position, float positionOffset, boolean updateSelectedText);

5、区分好两个操作动作:1. ScrollView 滚动,改变TabLayout ;2. 点击TabLayout 标签,ScrollView 发生滑动。避免当TabLayout 点击条目的时候,因ScrollView 发生滑动,同时又导致TabLayout改变的循环情况。可用一个标记位来标明当前的动作是由TabLayout 点击条目发起还是ScrollView 手动滑动发起。

6、如果ScrollView是在一个内容模块中滑动,要避免重复调用TabLyout的滑动。


代码实现

布局文件 activity_tab_layout.xml

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_tab_layout"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.skx.tomike.activity.TabLayoutActivity">    <android.support.design.widget.TabLayout        android:id="@+id/anchor_tagContainer"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:background="#a930c3a6"        app:tabIndicatorColor="@color/skx_323232"        app:tabMode="scrollable"        app:tabSelectedTextColor="@color/skx_323232"        app:tabTextColor="@color/skx_878787" />    <com.skx.tomike.customview.ScrollChangedScrollView        android:id="@+id/anchor_bodyContainer"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout_below="@id/anchor_tagContainer">        <LinearLayout            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:orientation="vertical">            <ImageView                android:id="@+id/iv_image"                android:layout_width="match_parent"                android:layout_height="240dp"                android:scaleType="fitXY"                android:src="@drawable/image_07" />            <TextView                android:id="@+id/tv_1"                android:layout_width="match_parent"                android:layout_height="486dp"                android:background="@color/skx_33ff4081"                android:gravity="center"                android:textSize="36sp" />            <TextView                android:id="@+id/tv_2"                android:layout_width="match_parent"                android:layout_height="420dp"                android:background="@color/skx_2cb298"                android:gravity="center"                android:textSize="36sp" />            <TextView                android:id="@+id/tv_3"                android:layout_width="match_parent"                android:layout_height="630dp"                android:background="#568463"                android:gravity="center"                android:textSize="36sp" />            <TextView                android:id="@+id/tv_4"                android:layout_width="match_parent"                android:layout_height="120dp"                android:background="@color/skx_2c3e50"                android:gravity="center"                android:textSize="36sp" />            <TextView                android:id="@+id/tv_5"                android:layout_width="match_parent"                android:layout_height="420dp"                android:background="@color/skx_4dbbcf"                android:gravity="center"                android:textSize="36sp" />            <TextView                android:id="@+id/tv_6"                android:layout_width="match_parent"                android:layout_height="320dp"                android:background="@color/skx_007aff"                android:gravity="center"                android:textSize="36sp" />            <TextView                android:id="@+id/tv_7"                android:layout_width="match_parent"                android:layout_height="503dp"                android:background="@color/skx_7f000000"                android:gravity="center"                android:textSize="36sp" />            <TextView                android:id="@+id/tv_8"                android:layout_width="match_parent"                android:layout_height="272dp"                android:background="@color/skx_85f3f3f3"                android:gravity="center"                android:textSize="36sp" />            <TextView                android:id="@+id/tv_9"                android:layout_width="match_parent"                android:layout_height="338dp"                android:background="@color/skx_959ea7"                android:gravity="center"                android:textSize="36sp" />        </LinearLayout>    </com.skx.tomike.customview.ScrollChangedScrollView></RelativeLayout>

Acitivity 代码,注释得也算详细了

public class TabLayoutActivity extends SkxBaseActivity {    private TabLayout tab_tagContainer;    private ScrollChangedScrollView sv_bodyContainer;    private TextView tv_1;    private TextView tv_2;    private TextView tv_3;    private TextView tv_4;    private TextView tv_5;    private TextView tv_6;    private TextView tv_7;    private TextView tv_8;    private TextView tv_9;    // 头部导航标签    private String[] navigationTag = {"图片", "啤酒", "饮料", "矿泉水", "瓜子", "花生", "八宝粥", "泡面", "鸡爪", "火腿肠"};    /**     * 是否是ScrollView主动动作     * false:是ScrollView主动动作     * true:是TabLayout 主动动作     */    private boolean tagFlag = false;    /**     * 用于切换内容模块,相应的改变导航标签,表示当一个所处的位置     */    private int lastTagIndex = 0;    /**     * 用于在同一个内容模块内滑动,锁定导航标签,防止重复刷新标签     * true: 锁定     * false ; 没有锁定     */    private boolean content2NavigateFlagInnerLock = false;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        initializeView();        refreshView();        installListener();    }    @Override    public void initializeView() {        super.initializeView();        setContentView(R.layout.activity_tab_layout);        tab_tagContainer = (TabLayout) findViewById(R.id.anchor_tagContainer);        sv_bodyContainer = (ScrollChangedScrollView) findViewById(R.id.anchor_bodyContainer);        tv_1 = (TextView) findViewById(R.id.tv_1);        tv_2 = (TextView) findViewById(R.id.tv_2);        tv_3 = (TextView) findViewById(R.id.tv_3);        tv_4 = (TextView) findViewById(R.id.tv_4);        tv_5 = (TextView) findViewById(R.id.tv_5);        tv_6 = (TextView) findViewById(R.id.tv_6);        tv_7 = (TextView) findViewById(R.id.tv_7);        tv_8 = (TextView) findViewById(R.id.tv_8);        tv_9 = (TextView) findViewById(R.id.tv_9);    }    @Override    public void refreshView() {        super.refreshView();        tv_1.setText(navigationTag[1]);        tv_2.setText(navigationTag[2]);        tv_3.setText(navigationTag[3]);        tv_4.setText(navigationTag[4]);        tv_5.setText(navigationTag[5]);        tv_6.setText(navigationTag[6]);        tv_7.setText(navigationTag[7]);        tv_8.setText(navigationTag[8]);        tv_9.setText(navigationTag[9]);        // 添加页内导航标签        for (String item : navigationTag) {            tab_tagContainer.addTab(tab_tagContainer.newTab().setText(item));        }    }    @Override    public void installListener() {        super.installListener();        sv_bodyContainer.setOnTouchListener(new View.OnTouchListener() {            @Override            public boolean onTouch(View v, MotionEvent event) {                //表明当前的动作是由 ScrollView 触发和主导                if (event.getAction() == MotionEvent.ACTION_DOWN) {                    tagFlag = true;                }                return false;            }        });        sv_bodyContainer.setScrollViewListener(new ScrollChangedScrollView.ScrollViewListener() {            @Override            public void onScrollChanged(ScrollView scrollView, int x, int y, int oldx, int oldy) {                scrollRefreshNavigationTag(scrollView);            }            @Override            public void onScrollStop(boolean isStop) {            }        });        tab_tagContainer.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {            @Override            public void onTabSelected(TabLayout.Tab tab) {                //表明当前的动作是由 TabLayout 触发和主导                tagFlag = false;                // 根据点击的位置,使ScrollView 滑动到对应区域                int position = tab.getPosition();                // 计算点击的导航标签所对应内容区域的高度                int targetY = 0;                switch (position) {                    case 0:                        break;                    case 1:                        targetY = tv_1.getTop();                        break;                    case 2:                        targetY = tv_2.getTop();                        break;                    case 3:                        targetY = tv_3.getTop();                        break;                    case 4:                        targetY = tv_4.getTop();                        break;                    case 5:                        targetY = tv_5.getTop();                        break;                    case 6:                        targetY = tv_6.getTop();                        break;                    case 7:                        targetY = tv_7.getTop();                        break;                    case 8:                        targetY = tv_8.getTop();                        break;                    case 9:                        targetY = tv_9.getTop();                        break;                    default:                        break;                }                // 移动到对应的内容区域                sv_bodyContainer.smoothScrollTo(0, targetY + 5);            }            @Override            public void onTabUnselected(TabLayout.Tab tab) {            }            @Override            public void onTabReselected(TabLayout.Tab tab) {            }        });    }    /**     * 内容区域滑动刷新导航标签     *     * @param scrollView 内容模块容器     */    private void scrollRefreshNavigationTag(ScrollView scrollView) {        if (scrollView == null) {            return;        }        // 获得ScrollView滑动距离        int scrollY = scrollView.getScrollY();        // 确定ScrollView当前展示的顶部内容属于哪个内容模块        if (scrollY > tv_9.getTop()) {            refreshContent2NavigationFlag(9);        } else if (scrollY > tv_8.getTop()) {            refreshContent2NavigationFlag(8);        } else if (scrollY > tv_7.getTop()) {            refreshContent2NavigationFlag(7);        } else if (scrollY > tv_6.getTop()) {            refreshContent2NavigationFlag(6);        } else if (scrollY > tv_5.getTop()) {            refreshContent2NavigationFlag(5);        } else if (scrollY > tv_4.getTop()) {            refreshContent2NavigationFlag(4);        } else if (scrollY > tv_3.getTop()) {            refreshContent2NavigationFlag(3);        } else if (scrollY > tv_2.getTop()) {            refreshContent2NavigationFlag(2);        } else if (scrollY > tv_1.getTop()) {            refreshContent2NavigationFlag(1);        } else {            refreshContent2NavigationFlag(0);        }    }    /**     * 刷新标签     *     * @param currentTagIndex 当前模块位置     */    private void refreshContent2NavigationFlag(int currentTagIndex) {        // 上一个位置与当前位置不一致是,解锁内部锁,是导航可以发生变化        if (lastTagIndex != currentTagIndex) {            content2NavigateFlagInnerLock = false;        }        if (!content2NavigateFlagInnerLock) {            // 锁定内部锁            content2NavigateFlagInnerLock = true;            // 动作是由ScrollView触发主导的情况下,导航标签才可以滚动选中            if (tagFlag) {                tab_tagContainer.setScrollPosition(currentTagIndex, 0, true);            }        }        lastTagIndex = currentTagIndex;    }}
1 1
原创粉丝点击