具有动态高度的Viewpager不起作用(始终使用第一个片段的高度)

问题描述 投票:0回答:3

我已经关注了thisthat的答案,我还找到了this链接。

我使用这些资源进行试验和错误。现在我的自定义

ViewPager
成功测量了其内容,但只显示了第一个。仅供参考,我的
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>

示例案例:

如果第一个片段的高度为 100 像素,则所有其他片段将保持在 100 像素。 因此,如果第二个片段的高度为 130px,它将被剪切为 100px。

当我尝试调试时,当创建

onMeasure
时,我的
CustomViewPager
上的
Activity
总是调用4次,但它们都只读取第一个片段。之后,即使我从一个片段更改(向左/向右滑动)到另一个片段,
onMeasure
永远不会再次被调用。

请帮助我,我花了很多时间来让这个东西工作。 如果您需要更多信息,请询问我,感谢您的宝贵时间。

android android-fragments android-viewpager
3个回答
15
投票
嗨,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等只是用于添加到viewpager的片段,您可以使用自己的片段,要记住的一件事是它们的外部布局应该是相同的,在我的情况下,我使用了衬垫布局全部

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(); } }
    

4
投票
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); }
    

0
投票
我通过这个处理视图 pager2 的动态高度

private fun updateViewPagerHeightForCurrentPage(position: Int) { val viewPager = itemView.findViewById<ViewPager2>(R.id.vp_orders) val recyclerView = viewPager.getChildAt(0) as? RecyclerView ?: return val viewHolder = recyclerView.findViewHolderForAdapterPosition(position) ?: return val itemView = viewHolder.itemView itemView.measure( View.MeasureSpec.makeMeasureSpec(recyclerView.width, View.MeasureSpec.EXACTLY), View.MeasureSpec.UNSPECIFIED ) val newHeight = itemView.measuredHeight val layoutParams = viewPager.layoutParams layoutParams.height = newHeight viewPager.layoutParams = layoutParams }
使用方法:

viewPager.registerOnPageChangeCallback(object : OnPageChangeCallback(){ override fun onPageSelected(position: Int) { super.onPageSelected(position) updateViewPagerHeightForCurrentPage(position) } })
    
© www.soinside.com 2019 - 2024. All rights reserved.