大多数场景下,会单单使用viewPager+Fragment来完成项目需求,但也有一些特殊情况需要用到viewPager的多重嵌套。
一、例如:
我的想法是:
①用viewPager+Fragment来完成"外卖、食堂、云购订单"这整个大的框架,到这里一切顺利。
②接着,用viewPager+Fragment来实现“外卖订单”里的“等配送、待付款、已完成、已取消”这整个小的框架,但这里在就出问题了。
二、“症状”:
①小框架的滑动事件出现了问题,不能流畅的从一个tab没到下一个tab
②每个tab中的内容是不显示的
③当滑动到“已完成”这个tab时,小框架被滑出去了,直接切换到大框架中的“食堂订单”
④到了“云购订单”时反而出现了小框架其中一个tab的内容
三、尝试:
我猜想这是2个viewPager嵌套产生的问题,于是自定义了小框架的viewPager,重写dispatchTouchEvent使父控件不拦截滑动事件,经测试,失败。自定义小框架的viewPager代码如下:
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
/**
* @创建者 CSDN_LQR
* @描述 自定义ViewPager:首尾页面父控件拦截事件
*/
public class CustomViewPager extends ViewPager {
private int startX;
private int startY;
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomViewPager(Context context) {
super(context);
}
/**
* 事件分发,请求父控件及祖宗控件是否拦截事件
* 1、右划,而且是第一个页面,需要父控件拦截
* 2、左划,而且是最后一个页面,需要父控件拦截
* 3、上下滑动,需要父控件拦截
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(true);//不要拦截,这样是为了保证ACTION_MOVE调用
startX = (int) ev.getRawX();
startY = (int) ev.getRawY();
break;
case MotionEvent.ACTION_MOVE:
int endX = (int) ev.getRawX();
int endY = (int) ev.getRawY();
if (Math.abs(endX - startX) > Math.abs(endY - startY)) {//左右滑动
if (endX > startX) {//往右滑动
if (getCurrentItem() == 0) {//第一个页面,需要父控件拦截
getParent().requestDisallowInterceptTouchEvent(false);
}
} else {//左划
if (getCurrentItem() == getAdapter().getCount() - 1) {//最后一个页面,需要拦截
getParent().requestDisallowInterceptTouchEvent(false);
}
}
} else {//上下滑动
getParent().requestDisallowInterceptTouchEvent(false);
}
break;
default:
break;
}
return super.dispatchTouchEvent(ev);
}
}
四、原因:
经过一番折腾,原因还是未知,但是可以确定跟Fragment有关。
五、解决办法:
直接去掉Fragment!!!
1、自定义BasePager类:
①BasePager类代码:
import android.app.Activity;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.TextView;
import com.dfdz.wmpt.R;
/**
* @创建者 CSDN_LQR
* @描述 基本页面(用于替换Fragment)
*/
public abstract class BasePager {
public Activity mActivity;
public View mRootView;//布局对象
public TextView tvTitle;//标题对象
public FrameLayout flContent;//内容
public BasePager(Activity activity) {
mActivity = activity;
init();
}
private void init() {
mRootView = View.inflate(mActivity, R.layout.base_pager, null);
flContent = (FrameLayout) mRootView.findViewById(R.id.fl_content);
flContent.addView(initView());
}
/**
* 初始化布局
*/
public abstract View initView();
/**
* 初始化数据
*/
public void initData() {
}
}
②base_pager.xml代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="@+id/fl_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</FrameLayout>
</LinearLayout>
2、把之前小框架中的Fragment全部不继承Fragment,改继承BasePager(我这里不管大框架还是小框架全部继承BasePager)。
3、设置新的适配器
不使用FragmentPagerAdapter,使用PagerAdapter
/**
* @创建者 CSDN_LQR
* @描述 viewPager的页面适配器
*/
class ContentAdapter extends PagerAdapter {
@Override
public int getCount() {
return mPagerList.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
BasePager pager = mPagerList.get(position);
container.addView(pager.mRootView);
pager.initData();//初始化数据。。。。不要放在此处初始化数据,否则会预加载下一个页面
return pager.mRootView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public CharSequence getPageTitle(int position) {
return mTlTitleArr[position];
}
}
4、布局中使用了上面的自定义ViewPager
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="@+id/tlTop"
android:layout_width="match_parent"
android:layout_height="30dp"
app:tabBackground="@color/white"
app:tabIndicatorColor="@color/main_bg3"
app:tabIndicatorHeight="1dp"
app:tabSelectedTextColor="@color/main_bg3"
app:tabTextAppearance="@style/TabLayoutTextStyle"
app:tabTextColor="@color/text0"/>
<com.dfdz.wmpt.view.CustomViewPager
android:id="@+id/vpContent"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
注:为方便日后理解,这里贴出部分关键(小框架)代码:
/**
* @创建者 CSDN_LQR
* @描述 OrderFragment中的外卖订单pager
*/
public class TakeOutFoodOrderPager extends BasePager {
@InjectView(R.id.tlTop)
TabLayout mTlTop;
@InjectView(R.id.vpContent)
CustomViewPager mVpContent;
private String[] mTlTitleArr;
private List<BasePager> mPagerList;
private ContentAdapter mMyPagerAdapter;
public TakeOutFoodOrderPager(Activity activity) {
super(activity);
}
@Override
public View initView() {
View view = View.inflate(mActivity, R.layout.fragment_takeoutfood_cateen, null);
ButterKnife.inject(this, view);
//设置tabLayout模式
mTlTop.setTabMode(TabLayout.MODE_FIXED);
return view;
}
@Override
public void initData() {
mTlTitleArr = UIUtils.getStringArr(R.array.tablayout_title_takeoutfood);
if (mPagerList == null) {
mPagerList = new ArrayList<BasePager>();
mPagerList.add(new WaitDistributionTakeOutFoodPager(mActivity));
mPagerList.add(new WaitPayTakeOutFoodPager(mActivity));
mPagerList.add(new FinishTakeOutFoodPager(mActivity));
mPagerList.add(new CancelTakeOutFoodPager(mActivity));
}
//添加Tab
for (String title : mTlTitleArr) {
mTlTop.addTab(mTlTop.newTab().setText(title));
}
//设置viewPager页面适配器
mMyPagerAdapter = new ContentAdapter();
mVpContent.setAdapter(mMyPagerAdapter);
//关联tabLayout和viewPager
mTlTop.setupWithViewPager(mVpContent);
}
/**
* @创建者 CSDN_LQR
* @描述 viewPager的页面适配器
*/
class ContentAdapter extends PagerAdapter {
@Override
public int getCount() {
return mPagerList.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
BasePager pager = mPagerList.get(position);
container.addView(pager.mRootView);
pager.initData();//初始化数据。。。。不要放在此处初始化数据,否则会预加载下一个页面
return pager.mRootView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public CharSequence getPageTitle(int position) {
return mTlTitleArr[position];
}
}
}