Android开发|ViewPager自适应高度问题

【Android开发|ViewPager自适应高度问题】最近在开发中有在一个界面做多组左右滑动的需求,当然平时最常见的就是利用ViewPager和Fragment结合,但是平时常见的只是在一个界面上存在一组左右滑动,且Fragment占满真个界面的情况。对于这个需求,一开始就遇到ViewPager的高度超出而没有自动适配高度的问题。不过网上很多大神已经解决了并分享了。参照:点击打开链接


记录一下,当做积累遇到的问题吧。
首先,定义一个CustomViewPager继承自ViewPager, 可以不用序列化实现Serializable,这里为了方面后面的Fragment传递参数才加的。

public class CustomViewPager extends ViewPager implements Serializable{private int height = 0; private int currPosition; private HashMap 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 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 fragmentList; public MyFragmentPagerAdapter(FragmentManager fm) { super(fm); }public MyFragmentPagerAdapter(FragmentManager fm, List 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的发送和订阅 事件进行传递。







    推荐阅读