动态高度浏览器

问题描述 投票:28回答:6

我正在尝试在自定义滚动视图中创建一个自定义viewpager,以动态包装当前孩子的身高。

package com.example.vihaan.dynamicviewpager;

import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.widget.ScrollView;

    /**
     * Created by vihaan on 1/9/15.
     */
    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 GestureDetector.SimpleOnGestureListener {
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2,
                                    float distanceX, float distanceY) {
                return (Math.abs(distanceY) > Math.abs(distanceX));
            }
        }
    }

CustomPager

/**
 * Created by vihaan on 1/9/15.
 */
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();
    }
}

MyPagerAdapter

public class MyPagerAdapter extends FragmentPagerAdapter {

    private List<Fragment> fragments;

    public MyPagerAdapter(FragmentManager fm) {
        super(fm);
        this.fragments = new ArrayList<Fragment>();
        fragments.add(new FirstFragment());
        fragments.add(new SecondFragment());
        fragments.add(new ThirdFragment());
        fragments.add(new FourthFragment());
    }

    @Override
    public Fragment getItem(int position) {
        return fragments.get(position);
    }

    @Override
    public int getCount() {
        return fragments.size();
    }
}

我希望这可以围绕当前片段的高度,但是只考虑第一个孩子的身高。

示例github项目:https://github.com/VihaanVerma89/DynamicViewPager

android android-viewpager android-custom-view android-scrollview
6个回答
67
投票

对代码进行了一些调整,现在可以正常工作。

1] onMeasure功能不正确。使用以下逻辑

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    if (mCurrentView == null) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        return;
    }
    int height = 0;
    mCurrentView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
    int h = mCurrentView.getMeasuredHeight();
    if (h > height) height = h;
    heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);

    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

2]每次更改页面时都需要重新测量ViewPager。这样做的好地方是setPrimaryItemPagerAdapter功能>

@Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        super.setPrimaryItem(container, position, object);
        if (position != mCurrentPosition) {
            Fragment fragment = (Fragment) object;
            CustomPager pager = (CustomPager) container;
            if (fragment != null && fragment.getView() != null) {
                mCurrentPosition = position;
                pager.measureCurrentView(fragment.getView());
            }
        }
    }

这里是通过以下调整指向GitHub项目的链接:https://github.com/vabhishek/WrapContentViewPagerDemo


23
投票

@@ abhishek的ans会执行所需的操作,但以下代码也会在高度变化时添加动画


15
投票

以防万一有人找到我这样的帖子。工作版本没有最初高度为零的错误:


3
投票

添加到@vihaan的解决方案中,如果您有PagerTitleStrip或PagetTabStrip,则可以添加此


0
投票
public class WrapContentViewPager extends ViewPager {
private Boolean mAnimStarted = false;

public WrapContentViewPager(Context context) {
    super(context);
}

public WrapContentViewPager(Context context, AttributeSet attrs) {
    super(context, attrs);
}

@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    if (!mAnimStarted && null != getAdapter()) {
        int height = 0;
        View child = ((CommonViewPagerAdapter) getAdapter()).getItem(getCurrentItem()).getView();
        if (child != null) {
            child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
            height = child.getMeasuredHeight();
            if (height < getMinimumHeight()) {
                height = getMinimumHeight();
            }
        }

        // Not the best place to put this animation, but it works pretty good.
        int newHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
        if (getLayoutParams().height != 0 && heightMeasureSpec != newHeight) {
            final int targetHeight = height;
            final int currentHeight = getLayoutParams().height;
            final int heightChange = targetHeight - currentHeight;

            Animation a = new Animation() {
                @Override
                protected void applyTransformation(float interpolatedTime, Transformation t) {
                    if (interpolatedTime >= 1) {
                        getLayoutParams().height = targetHeight;
                    } else {
                        int stepHeight = (int) (heightChange * interpolatedTime);
                        getLayoutParams().height = currentHeight + stepHeight;
                    }
                    requestLayout();
                }

                @Override
                public boolean willChangeBounds() {
                    return true;
                }
            };

            a.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                    mAnimStarted = true;
                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    mAnimStarted = false;
                }

                @Override
                public void onAnimationRepeat(Animation animation) {
                }
            });

            a.setDuration(100);
            startAnimation(a);
            mAnimStarted = true;
        } else {
            heightMeasureSpec = newHeight;
        }
    }

    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}

0
投票

这几行代码将解决问题。

为viewpager类创建一个自定义小部件。并在xml中将其用于viewpager。

© www.soinside.com 2019 - 2024. All rights reserved.