最近在开发中有在一个界面做多组左右滑动的需求,当然平时最常见的就是利用ViewPager和Fragment结合,但是平时常见的只是在一个界面上存在一组左右滑动,且Fragment占满真个界面的情况。对于这个需求,一开始就遇到ViewPager的高度超出而没有自动适配高度的问题。不过网上很多大神已经解决了并分享了。参照:点击打开链接
记录一下,当做积累遇到的问题吧。
首先,定义一个CustomViewPager继承自ViewPager, 可以不用序列化实现Serializable,这里为了方面后面的Fragment传递参数才加的。
public class CustomViewPager extends ViewPager implements Serializable{
private int height = 0;
private int currPosition;
private HashMap<Integer, View> mChildViews = new LinkedHashMap<>();
public CustomViewPager(Context context) {
super(context);
}
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mChildViews.size() > currPosition){
View child = mChildViews.get(currPosition);
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
height = child.getMeasuredHeight();
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
/** 通过设置LayoutParams来控制子View的高度 即重置当前位置下标(fragment)的高度*/
public void resetHeight(int position){
this.currPosition = position;
if (mChildViews.size() > currPosition){
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
if (layoutParams == null){
layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, height);
}
layoutParams.height = height;
setLayoutParams(layoutParams);
}
}
public void setObjectForView(View view, int position){
mChildViews.put(position, view);
}
}
自定义的CustomViewPager主要是测量 ViewPager 当前下标的高度,然后通过resetHeight()方法重置其高度。setObjectForView(View, int)是在实例Fragment的时候调用,目的是与ViewPager进行绑定,然后可以重新测量高度进行自适应。
下面就是一个简单的例子,在ScrollView里面嵌套ViewPager,并且让ViewPager能够自适应高度。
public class FirstFragment extends Fragment {
public FirstFragment() {
// Required empty public constructor
}
public static FirstFragment newInstance(CustomViewPager vp){
FirstFragment fragment = new FirstFragment();
Bundle bundle = new Bundle();
bundle.putSerializable("vp", vp);
fragment.setArguments(bundle);
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_first, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (getArguments() != null){
CustomViewPager vp = (CustomViewPager) getArguments().getSerializable("vp");
vp.setObjectForView(view, 0);
}
}
}
public class SecondFragment extends Fragment {
public SecondFragment() {
// Required empty public constructor
}
public static SecondFragment newInstance(CustomViewPager vp){
SecondFragment fragment = new SecondFragment();
Bundle bundle = new Bundle();
bundle.putSerializable("vp", vp);
fragment.setArguments(bundle);
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_second, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (getArguments() != null){
CustomViewPager vp = (CustomViewPager) getArguments().getSerializable("vp");
vp.setObjectForView(view, 1);
}
}
}
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private CustomViewPager mVp;
private TextView mTitle1, mTitle2;
private List<Fragment> mFragmentList = new ArrayList<>();
private Context mContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
mVp = (CustomViewPager) findViewById(R.id.vp);
mTitle1 = (TextView) findViewById(R.id.title1);
mTitle2 = (TextView) findViewById(R.id.title2);
mTitle1.setOnClickListener(this);
mTitle2.setOnClickListener(this);
mVp.setOffscreenPageLimit(2);
mFragmentList.add(FirstFragment.newInstance(mVp));
mFragmentList.add(SecondFragment.newInstance(mVp));
mVp.setAdapter(new MyFragmentPagerAdapter(getSupportFragmentManager(), mFragmentList));
mVp.resetHeight(0);
updateTitleWithViewPager(0);
mVp.addOnPageChangeListener(new PagerChangeListener(mVp));
}
private void updateTitleWithViewPager(int index){
switch (index){
case 0:
mTitle1.setTextColor(ContextCompat.getColor(mContext, R.color.colorAccent));
mTitle2.setTextColor(ContextCompat.getColor(mContext, R.color.text_666));
mVp.setCurrentItem(0);
break;
case 1:
mTitle1.setTextColor(ContextCompat.getColor(mContext, R.color.text_666));
mTitle2.setTextColor(ContextCompat.getColor(mContext, R.color.colorAccent));
mVp.setCurrentItem(1);
break;
}
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.title1:
updateTitleWithViewPager(0);
break;
case R.id.title2:
updateTitleWithViewPager(1);
break;
}
}
static class MyFragmentPagerAdapter extends FragmentPagerAdapter{
private List<Fragment> fragmentList;
public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
public MyFragmentPagerAdapter(FragmentManager fm, List<Fragment> fragmentList) {
super(fm);
this.fragmentList = fragmentList;
}
@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
@Override
public int getCount() {
return fragmentList.size();
}
}
private class PagerChangeListener implements ViewPager.OnPageChangeListener {
private CustomViewPager customViewPager;
public PagerChangeListener(CustomViewPager viewPager){
this.customViewPager = viewPager;
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
customViewPager.resetHeight(position);
updateTitleWithViewPager(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
}
}
当然,上面提到Fragment和ViewPager通过setObjectForView进行绑定,上面用到了Fragment的传递参数方式进行绑定,从而在自定义CustomViewPager时实现了序列化接口Serializable,除了这种方式,还可以使用接口回调的方法,亦或最简单的直接使用Butterknife的发送和订阅 事件进行传递。