Viewpager with dynamic height not working (always use the first fragment's height)

前端 未结 2 794
被撕碎了的回忆
被撕碎了的回忆 2021-02-04 16:39

I have followed this and that answers, i also found this link.

I use those resources to do trial & errors. Now my custom ViewPager successfully measure

相关标签:
2条回答
  • 2021-02-04 17:14

    Hi Blaze found some thing use full, following solution is working for me.

    Its include a custom scroll view and custom view pager. The purpose custom view pager is its calculate the height dynamically according to its children's height, its hieght is set to wrap content initially and the purpose of scroll view is handling the touch event , if the users scrolls the screen vertically it will not pass the touch even to scroll and thus user is able to scroll the page.

    Custom scroll view

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

    Custom view pager

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

    Layout file

    <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>
    

    Activity

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

    Fragment adapter

    fragments with different heights are added to the viewpager, FragmentBlue,Green etc are just fragments used to add to the viewpager you can use your own fragments, one thing to remember is their outer layout should be same in my case I used liner layout for all

    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();
    }
    }
    
    0 讨论(0)
  • 2021-02-04 17:18
    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 讨论(0)
提交回复
热议问题