Viewpager с динамической высотой не работает (всегда используйте высоту первого фрагмента)

Я последовал за этим и этим ответам, я также нашел эту ссылку.

Я использую эти ресурсы для проб и ошибок. Теперь мой пользовательский ViewPager успешно ViewPager его содержимое, но отображается только первый . FYI, мой ViewPager содержит несколько сложных представлений, таких как ExpendableListView – вот почему ни один из кода в этих ресурсах не работает отлично, мне нужно изменить код самостоятельно.

У меня есть 4 фрагмента (содержание), поэтому я использую pager.setOffscreenPageLimit(3);

Это мой пользовательский ViewPager :

 public class CustomViewPager extends ViewPager{ public CustomViewPager (Context context) { super(context); } public CustomViewPager (Context context, AttributeSet attrs) { super(context, attrs); } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); boolean wrapHeight = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST; final View tab = getChildAt(0); int width = getMeasuredWidth(); int tabHeight = tab.getMeasuredHeight(); if (wrapHeight) { // Keep the current measured width. widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY); } int fragmentHeight = measureFragment(((Fragment) getAdapter().instantiateItem(this, getCurrentItem())).getView()); heightMeasureSpec = MeasureSpec.makeMeasureSpec(tabHeight + fragmentHeight + (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, getResources().getDisplayMetrics()), MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } public int measureFragment(View view) { if (view == null) return 0; view.measure(0, 0); return view.getMeasuredHeight(); } } 

Это мой CustomPagerTabStrip :

 int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); android.view.ViewGroup.LayoutParams params = getLayoutParams(); params.height = getMeasuredHeight(); 

И это мой XML:

  <RelativeLayout android:id="@+id/relativePager" android:layout_width="match_parent" android:layout_height="wrap_content" > <com.xxx.yyy.util.CustomViewPager android:id="@+id/detailPager" android:layout_width="match_parent" android:layout_height="wrap_content" > <com.xxx.yyy.util.CustomPagerTabStrip android:id="@+id/detailTab" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#161C28" android:textColor="#FFFFFF" /> </com.xxx.yyy.util.CustomViewPager> </RelativeLayout> 

Пример:

Если высота первого фрагмента равна 100px, тогда все остальные фрагменты останутся на 100px. Поэтому, если высота второго фрагмента составляет 130 пикселей, он будет сокращен до 100 пикселей.

Когда я пытался отлаживать , onMeasure на моем CustomViewPager всегда вызывал 4 раза при создании Activity , но все они только считывали первый фрагмент. После этого onMeasure никогда не будет вызываться снова, даже когда я изменяю (слайд слева / справа) от одного фрагмента к другому.

Пожалуйста, помогите мне, я потратил много часов, чтобы заставить эту работу работать. Просто спросите меня, нужна ли вам дополнительная информация, спасибо за ваше время.

Solutions Collecting From Web of "Viewpager с динамической высотой не работает (всегда используйте высоту первого фрагмента)"

Привет, Blaze нашел, что какая-то вещь используется полностью, после меня работает решение.

Он включает пользовательский просмотр прокрутки и пользовательский пейджер. Пейджер настраиваемого представления – это вычисление высоты динамически в соответствии с высотой их дочерних элементов, его высота устанавливается для первоначального обертывания содержимого, а цель просмотра прокрутки обрабатывает событие касания, если пользователи прокручивают экран по вертикали, он не пройдет сенсорный Даже для прокрутки и, таким образом, пользователь может прокручивать страницу.

Пользовательский просмотр прокрутки

 public class CustomScrollView extends ScrollView { private GestureDetector mGestureDetector; public CustomScrollView(Context context, AttributeSet attrs) { super(context, attrs); mGestureDetector = new GestureDetector(context, new YScrollDetector()); setFadingEdgeLength(0); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return super.onInterceptTouchEvent(ev) && mGestureDetector.onTouchEvent(ev); } // Return false if we're scrolling in the x direction class YScrollDetector extends SimpleOnGestureListener { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return (Math.abs(distanceY) > Math.abs(distanceX)); } } } 

Пользовательский просмотр пейджера

 public class CustomPager extends ViewPager{ public CustomPager (Context context) { super(context); } public CustomPager (Context context, AttributeSet attrs) { super(context, attrs); } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); boolean wrapHeight = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST; final View tab = getChildAt(0); int width = getMeasuredWidth(); int tabHeight = tab.getMeasuredHeight(); if (wrapHeight) { // Keep the current measured width. widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY); } int fragmentHeight = measureFragment(((Fragment) getAdapter().instantiateItem(this, getCurrentItem())).getView()); heightMeasureSpec = MeasureSpec.makeMeasureSpec(tabHeight + fragmentHeight + (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, getResources().getDisplayMetrics()), MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } public int measureFragment(View view) { if (view == null) return 0; view.measure(0, 0); return view.getMeasuredHeight(); } } 

Файл макета

 <com.example.demo2.activity.widget.CustomScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <TextView style="@style/text" android:text="Text 1" /> <View style="@style/text_divider" /> <TextView style="@style/text" android:text="Text 2" /> <com.example.demo2.activity.widget.CustomPager android:id="@+id/myViewPager" android:layout_width="match_parent" android:layout_height="wrap_content" /> <View style="@style/text_divider" /> <TextView style="@style/text" android:text="Text 4" /> <View style="@style/text_divider" /> <TextView style="@style/text" android:text="Text 5" /> <View style="@style/text_divider" /> <TextView style="@style/text" android:text="Text 6" /> <View style="@style/text_divider" /> <TextView style="@style/text" android:text="Text 7" /> <View style="@style/text_divider" /> <TextView style="@style/text" android:text="Text 8" /> <View style="@style/text_divider" /> <TextView style="@style/text" android:text="Text 9" /> <View style="@style/text_divider" /> <TextView style="@style/text" android:text="Text 10" /> </LinearLayout> 

Мероприятия

 public class MainActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MyPagerAdapter pageAdapter = new MyPagerAdapter(getSupportFragmentManager()); ViewPager pager = (ViewPager)findViewById(R.id.myViewPager); pager.setAdapter(pageAdapter); } } 

Адаптер фрагмента

Фрагменты с разной высотой добавляются в viewpager, FragmentBlue, Green и т. Д. – это всего лишь фрагменты, используемые для добавления в просмотрщик, который вы можете использовать своими собственными фрагментами. Одна вещь, которую нужно запомнить, – это их внешний макет, должен быть таким же, в моем случае я использовал макет лайнера для всех

 public class MyPagerAdapter extends FragmentPagerAdapter { private List<Fragment> fragments; public MyPagerAdapter(FragmentManager fm) { super(fm); this.fragments = new ArrayList<Fragment>(); fragments.add(new FragmentBlue()); fragments.add(new FragmentGreen()); fragments.add(new FragmentPink()); fragments.add(new FragmentRed()); } @Override public Fragment getItem(int position) { return fragments.get(position); } @Override public int getCount() { return fragments.size(); } } 
 public CustomPager (Context context) { super(context); } public CustomPager (Context context, AttributeSet attrs) { super(context, attrs); } int getMeasureExactly(View child, int widthMeasureSpec) { child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); int height = child.getMeasuredHeight(); return MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); boolean wrapHeight = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST; final View tab = getChildAt(0); if (tab == null) { return; } int width = getMeasuredWidth(); if (wrapHeight) { // Keep the current measured width. widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY); } Fragment fragment = ((Fragment) getAdapter().instantiateItem(this, getCurrentItem())); heightMeasureSpec = getMeasureExactly(fragment.getView(), widthMeasureSpec); //Log.i(Constants.TAG, "item :" + getCurrentItem() + "|height" + heightMeasureSpec); // super has to be called again so the new specs are treated as // exact measurements. super.onMeasure(widthMeasureSpec, heightMeasureSpec); }