今天写的是ScrollView和TabLayout联合使用实现滑动定位效果,话不多说,请看效果图:
图中主要实现了两个功能。第一:点击上方的TabLayout标签,页面可以快速滑到对应的位置。第二:当滑动下方的view时,TabLayout会跟随下方显示对应的view,话不多说,请看下面代码:
1.首先看布局文件的代码:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activity.scrolltab.ScrollViewTabActivity">
<android.support.design.widget.TabLayout
android:id="@+id/tab_name"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="#00574B"
android:overScrollMode="never"
android:paddingLeft="16dp"
android:paddingRight="16dp"
app:tabGravity="fill"
app:tabMode="scrollable"
app:tabSelectedTextColor="#D81B60"
app:tabTextColor="#FFFFFF" />
<TextView
android:id="@+id/tv_name"
android:layout_width="match_parent"
android:layout_height="40dp"
android:text="1111"
android:visibility="gone" />
<ScrollView
android:id="@+id/sc_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_item1"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="#FFFFFF"
android:gravity="center"
android:text="张三"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_item2"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="#FFC8B4"
android:gravity="center"
android:text="李四"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_item3"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="#FFFFFF"
android:gravity="center"
android:text="王五"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_item4"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="#FFC8B4"
android:gravity="center"
android:text="赵六"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_item5"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="#FFFFFF"
android:gravity="center"
android:text="刘七"
android:textSize="20sp" />
</LinearLayout>
</ScrollView>
</LinearLayout>
上面的布局文件名称是activity_scroll_view_tab,里面的内容很常规,就是上面一个TabLayout,下面是ScrollView。
2.TabLayout和ScrollView在Activity的配合实现
public class ScrollViewTabActivity extends AppCompatActivity {
@BindView(R.id.tv_item1)
TextView tvItem1;
@BindView(R.id.tv_item2)
TextView tvItem2;
@BindView(R.id.tv_item3)
TextView tvItem3;
@BindView(R.id.tv_item4)
TextView tvItem4;
@BindView(R.id.tv_item5)
TextView tvItem5;
@BindView(R.id.sc_view)
ScrollView scView;
@BindView(R.id.tv_name)
TextView tvName;
@BindView(R.id.tab_name)
TabLayout tabName;
private int height1;
private int height2;
private int height3;
private int height4;
private int height5;
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scroll_view_tab);
ButterKnife.bind(this);
addTab();//添加标签
initView();
}
private void addTab() {
tabName.addTab(tabName.newTab().setText("张三"));
tabName.addTab(tabName.newTab().setText("李四"));
tabName.addTab(tabName.newTab().setText("王五"));
tabName.addTab(tabName.newTab().setText("赵六"));
tabName.addTab(tabName.newTab().setText("刘七"));
}
private boolean IsSlide = false;//默认不是滑动操作
@RequiresApi(api = Build.VERSION_CODES.M)
private void initView() {
tabName.setSelectedTabIndicatorHeight(0);//去掉标签隐藏的下划线
//ScrollView的滑动监听
scView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
//第二个参数:目前的x轴坐标
//第三个参数:目前的y轴坐标
//第四个参数:上一个x轴坐标
//第五个参数:上一个y轴坐标
IsSlide = true;//表明此时正在滑动
if (scrollY < height1) {//表明此时在Item1范围内,所以第一个Item应该被选择
Objects.requireNonNull(tabName.getTabAt(0)).select();
} else if (scrollY >= height1 && scrollY < height2) {//表明此时在Item2范围内,所以第二个Item应该被选择
Objects.requireNonNull(tabName.getTabAt(1)).select();
} else if (scrollY >= height2 && scrollY < height3) {//表明此时在Item3范围内,所以第三个Item应该被选择
Objects.requireNonNull(tabName.getTabAt(2)).select();
} else if (scrollY >= height3 && scrollY < height4) {//表明此时在Item4范围内,所以第四个Item应该被选择
Objects.requireNonNull(tabName.getTabAt(3)).select();//表明此时在Item5范围内,所以第五个Item应该被选择
} else {
Objects.requireNonNull(tabName.getTabAt(4)).select();表明此时在Item6范围内,所以第六个Item应该被选择
}
IsSlide = false;//表明滑动结束
}
});
//这个方法的作用是标签被选择调用的方法
tabName.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
//当标签处于选中的状态 此时有两种情况 1.直接点击tabLayout标签会走 2.当ScrollView滑动时,因为我们在滑动里面设置了选择标签,所以此时这个方法也会走
//现在有个问题,当滑动的时候,tabLayout标签也会被选择,这个方法也会走,所以此时会产生冲突,我们要排除滑动的操作
if (IsSlide) {//表示此时正在滑动 不走这个方法
return;
}
int position = tab.getPosition();//表明哪个标签被选择
if (position == 0) {
scView.smoothScrollTo(0, 0);//滑到对应的View顶部
Toast.makeText(ScrollViewTabActivity.this, "张三", Toast.LENGTH_SHORT).show();
} else if (position == 1) {
scView.smoothScrollTo(0, height1);//滑到对应的View顶部
Toast.makeText(ScrollViewTabActivity.this, "李四", Toast.LENGTH_SHORT).show();
} else if (position == 2) {
scView.smoothScrollTo(0, height2);//滑到对应的View顶部
Toast.makeText(ScrollViewTabActivity.this, "王五", Toast.LENGTH_SHORT).show();
} else if (position == 3) {
scView.smoothScrollTo(0, height3);//滑到对应的View顶部
Toast.makeText(ScrollViewTabActivity.this, "赵六", Toast.LENGTH_SHORT).show();
} else {
scView.smoothScrollTo(0, height4);//滑到对应的View顶部
Toast.makeText(ScrollViewTabActivity.this, "刘七", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
height1 = tvItem1.getMeasuredHeight();//表示第一个item的高度,这是高度
height2 = tvItem1.getMeasuredHeight() + tvItem2.getMeasuredHeight();//这个是第一个item加第二个item的高度 下面同理
height3 = tvItem1.getMeasuredHeight() + tvItem2.getMeasuredHeight() + tvItem3.getMeasuredHeight();
height4 = tvItem1.getMeasuredHeight() + tvItem2.getMeasuredHeight() + tvItem3.getMeasuredHeight() + tvItem4.getMeasuredHeight();
height5 = tvItem1.getMeasuredHeight() + tvItem2.getMeasuredHeight() + tvItem3.getMeasuredHeight() + tvItem4.getMeasuredHeight() + tvItem5.getMeasuredHeight();
}
}
上面的代码就是处理TabLayout和ScrollView的逻辑关系代码,在上面的代码中我也注释了很多,希望可以帮助大家理解,在这里我在强调上面代码中的两点:
第一:我使用了**onWindowFocusChanged()**方法去获得对应View的高度,这个方法表示的是在页面获得焦点的时候,获得相应View的高度,因为你在onStart(),onResume()是拿不到的,你可以写个demo证实一下,当然你也可以将获得高度写在滑动事件里,这样也可以拿到。
第二:addOnTabSelectedListener()这个方法当标签被选择时会被调用,我们在这里使用它时,主要目的是点击(也是被选择)某个标签时,快速定位到某个View,可是在我们的代码里,当ScrollView滑动时,标签也会被选择,如果不做处理,addOnTabSelectedListener()方法也会被调用,所以这种方法应该被排除掉,具体请看上面代码逻辑。
由于这仅仅是一个demo,只是为了给大家提供一个思路,具体问题还要具体分析,有什么不同或者不对的地方,还希望大家及时指出。