How to wrap the height of a ViewPager to the height of its current Fragment?

前端 未结 6 1513
轻奢々
轻奢々 2020-11-27 14:04

I made a ScrollView containing a ViewPager, but the ViewPager does not grow in height. When the content inside the ViewPager is too big, it get \'pucht\'(?) inside, the tabl

相关标签:
6条回答
  • 2020-11-27 14:21

    in my case, i created imageslider with viewpager. initial value of child is null also at the end of index, value of child is null. so, i made some upgrades for repitch answer, because it didn't handle (child==null)

    ViewPager now looks like:

    public class WrapContentViewPager extends ViewPager {
    
        public WrapContentViewPager(Context context) {
            super(context);
            initPageChangeListener();
        }
    
        public WrapContentViewPager(Context context, AttributeSet attrs) {
            super(context, attrs);
            initPageChangeListener();
        }
    
        private void initPageChangeListener() {
            addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
                @Override
                public void onPageSelected(int position) {
                    requestLayout();
                }
            });
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            View child = getChildAt(getCurrentItem());
            if (child != null) {
                child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
                int h = child.getMeasuredHeight();
                heightMeasureSpec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
            } else {for(int i = 0; i < getChildCount(); i++) {
                    View child2 = getChildAt(i);
                    child2.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
                    int h = child2.getMeasuredHeight();
                    heightMeasureSpec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
            }}
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
    }
    

    also, you can add amount of height whatever you want, if the last item of viewpager stick to circlepageindicator, like this : int h = child2.getMeasuredHeight()+50;

    0 讨论(0)
  • 2020-11-27 14:31

    You can customize the ViewPager to resize the ViewPager to it's current page size on page swipe.

    You can use the below code.

    public class WrapContentViewPager extends ViewPager {
    
        private int mCurrentPagePosition = 0;
    
        public WrapContentViewPager(Context context) {
            super(context);
        }
    
        public WrapContentViewPager(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            try {
                boolean wrapHeight = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST;
                if (wrapHeight) {
                    View child = getChildAt(mCurrentPagePosition);
                    if (child != null) {
                    child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
                    int h = child.getMeasuredHeight();
    
                    heightMeasureSpec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
        public void reMeasureCurrentPage(int position) {
            mCurrentPagePosition = position;
            requestLayout();
        }
    }
    

    Declare it in xml:

        <your.package.name.WrapContentViewPager
                android:id="@+id/view_pager"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
        </your.package.name.WrapContentViewPager>
    

    After that call reMeasureCurrentpage function on page swipe.

    final WrapContentViewPager wrapContentViewPager = (WrapContentViewPager) findViewById(R.id.view_pager);
    
    wrapContentViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    
        }
    
        @Override
        public void onPageSelected(int position) {
            wrapContentViewPager.reMeasureCurrentPage(wrapContentViewPager.getCurrentItem());
        }
    
        @Override
        public void onPageScrollStateChanged(int state) {
    
        }
    });
    
    0 讨论(0)
  • 2020-11-27 14:33

    I really liked @abhishek-v answer, but made some upgrades:

    • addPageChangeListener(...) called inside our ViewPager (don't need to call reMeasureCurrentPage(...) manually outside on page swipe)
    • don't need to store mCurrentPagePosition, because we can use getCurrentItem()
    • removed waste try/catch block

    ViewPager now looks like:

    public class WrapContentViewPager extends ViewPager {
    
        public WrapContentViewPager(Context context) {
            super(context);
            initPageChangeListener();
        }
    
        public WrapContentViewPager(Context context, AttributeSet attrs) {
            super(context, attrs);
            initPageChangeListener();
        }
    
        private void initPageChangeListener() {
            addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
                @Override
                public void onPageSelected(int position) {
                    requestLayout();
                }
            });
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            View child = getChildAt(getCurrentItem());
            if (child != null) {
                child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
                int h = child.getMeasuredHeight();
                heightMeasureSpec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
            }
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
    }
    
    0 讨论(0)
  • 2020-11-27 14:33

    If these answer still can't fix the problem, I can provide another choice. At the PagerAdapter java file, you can measure the page height manually and set the container's LayoutParams.height in instantiateItem method. Like this:

    @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
        View view = generateView(mContext, position);
        view.measure(View.MeasureSpec.makeMeasureSpec(DensityUtil.getScreenWidth(mContext), View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
        container.getLayoutParams().height = view.getMeasuredHeight();
        container.addView(view);
        return view;
    }
    
    0 讨论(0)
  • 2020-11-27 14:35

    Finally found a better solution for WrapContentViewPager!

    The other solution contain some bug that hard to be solved, but I think this solution can be simply applied in our code

    I found it on this site https://github.com/akhahaha/burn-android/blob/master/app/src/main/java/com/ucla/burn/android/WrapContentViewPager.java

    Here is the code

    public class WrapContentViewPager extends ViewPager {
            public WrapContentViewPager(Context context) {
                super(context);
            }
    
            public WrapContentViewPager(Context context, AttributeSet attrs) {
                super(context, attrs);
            }
    
            @Override
            protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    
                int height = 0;
                for (int i = 0; i < getChildCount(); i++) {
                    View child = getChildAt(i);
                    child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
                    int h = child.getMeasuredHeight();
                    if (h > height) height = h;
                }
    
                heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
    
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            }
        }
    
    0 讨论(0)
  • 2020-11-27 14:36

    On Android 8.0, you have to invoke another requestLayout to make it work:

    ....@Abhishek's answer
    
    sharePager.post(new Runnable() {
                @Override
                public void run() {
                    sharePager.requestLayout();
                }
            });
    
    0 讨论(0)
提交回复
热议问题