正常情况下我们写页面联动的话都使用Tablayout与ViewPager及Fragment进行联动,但是碍于TabLayout的样式的问题有一些情况是不能满足我们的UI需求的,所以就又尝试用RecycleView与ViewPager及Fragmentz进行联动,然后就取得了不错的效果,接下来跟大家分享
首先是布局文件:
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_food"
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="@color/grey29"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/cl_discount">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_type"
android:layout_width="0dp"
android:layout_height="@dimen/dp128"
android:layout_marginLeft="@dimen/dp21"
android:layout_marginTop="@dimen/dp_w_31"
android:layout_marginRight="@dimen/dp21"
android:visibility="visible"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.ikonke.hotel.ui.weight.WrapContentHeightViewPager
android:id="@+id/vp_food"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp21"
android:layout_marginTop="@dimen/dp29"
android:layout_marginRight="@dimen/dp21"
android:layout_marginBottom="@dimen/dp29"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/rv_type" />
</androidx.constraintlayout.widget.ConstraintLayout>
因为我们的Fragment里面是一个列表,所以用原生的ViewPager给自适应高度的话在约束布局里面会出现划不到列表的最底下的现象,所以这里就采用了自定义自适应高度的ViewPager
public class WrapContentHeightViewPager extends ViewPager {
public WrapContentHeightViewPager(Context context) {
super(context);
}
public WrapContentHeightViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int height = 0;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = child.getMeasuredHeight();
if (h > height) height = h;
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
用自定义的ViewPager的话,在约束布局里面就可以给自适应的高度了,而且也不会有异常,布局文件都写完了接下来就是联动了
首先我们需要先给ViewPager写好适配器
public class FoodViewPagerAdapter extends FragmentPagerAdapter {
ArrayList<Fragment> mlist;
public FoodViewPagerAdapter(@NonNull FragmentManager fm, ArrayList<Fragment> list) {
super(fm);
this.mlist = list;
}
@NonNull
@Override
public Fragment getItem(int position) {
return mlist.get(position);//显示第几个页面
}
@Override
public int getCount() {
return mlist.size();//有几个页面
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return null;
}
}
然后设置适配器
FoodViewPagerAdapter foodViewPagerAdapter = new FoodViewPagerAdapter(getFragmentManager(), fragList);
vpFood.setAdapter(foodViewPagerAdapter);
这里面只传了两个参数,主要说第二个参数,是Fragment的数量,Fragment的数量要跟标题的数量对应我们的标题是请求下来的可能不固定所以我就循环的添加到了Fragment的集合里,如果你们的Fragment数量固定写死也可
然后我们需要给标题列表(替代Tablayout的列表)一个条目点击事件,然后传的值的话需要有条目的下标,然后用ViewPager的方法来进行滑动切换
mTopAdapter.setOnItemClickListener((position, bean) -> {
//定义一个值让标题列表选中条目的下标跟ViewPager选中页面的下标进行共享,并实时更新
mPosition = position;
//切换ViewPager页面
vpFood.setCurrentItem(position, true);
menuId = bean.getRecipeId();
//切换选中条目
for (RecipeInfoBean bean1 : foodTypeList) {
bean1.setSel(false);
}
bean.setSel(true);
mTypeAdapter.notifyDataSetChanged();
mTopAdapter.notifyDataSetChanged();
});
切换ViewPager的方法传了俩参数,第一个参数是让ViewPager切换到下标跟标题列表选中条目下标一致的页面,然后第二个参数控制的是要不要滑动效果
现在实现了由标题列表联动ViewPager切换页面的效果,接下来要实现的是滑动ViewPager页面来切换标题列表的条目的选中效果
vpFood.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
//判断共享下标跟当前页面下标是否一致,不一致的话就把共享下标更新并且切换标题列表的条目选中效果
if (mPosition != position) {
mPosition = position;
//设置所有条目都为不选中
for (RecipeInfoBean bean1 : foodTypeList) {
bean1.setSel(false);
}
//设置当前下标的条目为选中
foodTypeList.get(position).setSel(true);
//刷新适配器展示效果
mTypeAdapter.notifyDataSetChanged();
mTopAdapter.notifyDataSetChanged();
}
//请求数据
mPresenter.getFoods(foodTypeList.get(position).getRecipeId(), foodTypeList.get(position).getId());
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
然后我们Fragment里的列表最好给设置以下属性:布局管理器要设置不可滑动
mGridLayoutManager.setScrollEnabled(false);
这个属性我去掉也没有出现异常,不过最好加上避免意外
自此联动就算结束,最后讲一句,由于我们用的是MVP架构,是在ViewPager的选中监听里面请求的数据,然后在V层的展示请求结果的方法里面调用Fragment里面的Set方法来更新Fragment里面RecycleView要展示的数据,如果用的是MVC的话可以直接在ViewPager的选中监听里面请求,然后传递请求结果
以上便是笔者的总结,希望能够帮助诸位读者,如文中有错,还望及时指出以免误导读者,感谢