ViewPager в ScrollView с динамической высотой страницы - PullRequest
0 голосов
/ 29 июня 2018

Я прочитал много других SO-ответов, но, кажется, ничего не то, что я хочу. То, что я хочу, - это ViewPager внутри ScrollView, где высота каждой страницы соответствует содержимому. Кажется, что некоторые из наиболее приемлемых ответов на SO должны принимать максимальную высоту дочерних элементов в ViewPager, но это приводит к пустому пространству.

WrapContentViewPager

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;
    View view = null;
    for(int i = 0; i < getChildCount(); i++) {
        view = getChildAt(i);
        view.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
        int h = view.getMeasuredHeight();
        if(h > height) height = h;
    }

    if (height != 0) {
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
    }

    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    setMeasuredDimension(getMeasuredWidth(), measureHeight(heightMeasureSpec, view));
}


/**
 * Determines the height of this view
 *
 * @param measureSpec A measureSpec packed into an int
 * @param view the base view with already measured height
 *
 * @return The height of the view, honoring constraints from measureSpec
 */
private int measureHeight(int measureSpec, View view) {
    int result = 0;
    int specMode = MeasureSpec.getMode(measureSpec);
    int specSize = MeasureSpec.getSize(measureSpec);

    if (specMode == MeasureSpec.EXACTLY) {
        result = specSize;
    } else {
        // set the height from the base view if available
        if (view != null) {
            result = view.getMeasuredHeight();
        }
        if (specMode == MeasureSpec.AT_MOST) {
            result = Math.min(result, specSize);
        }
    }
    return result;
}

}

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

Я пробовал библиотеку WCViewPager на GitHub на https://github.com/rnevet/WCViewPager, и она также не работает для меня.

Может ли кто-нибудь направить меня к правильному решению? Я использую ViewPager только с PagerAdapter, а не FragmentPagerAdapter, кстати.

UPDATE

Я нашел лучший способ ее решить.

`открытый класс 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 mode = MeasureSpec.getMode(heightMeasureSpec);
    // Unspecified means that the ViewPager is in a ScrollView WRAP_CONTENT.
    // At Most means that the ViewPager is not in a ScrollView WRAP_CONTENT.
    if (mode == MeasureSpec.UNSPECIFIED || mode == MeasureSpec.AT_MOST) {
        // super has to be called in the beginning so the child views can be initialized.
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int position = getCurrentItem();
        View child = this.findViewWithTag("view"+position);
        child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
        int height = child.getMeasuredHeight();
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
    }
    // super has to be called again so the new specs are treated as exact measurements
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

} `

и в моем PagerAdapter я сменил метод instantiateItem

 @Override
public @NonNull Object instantiateItem(@NonNull ViewGroup view, int position) {
    View layout = inflater.inflate(R.layout.layout, view, false);
    layout.setTag("view" + position);
}

Это решение запоминает высоту текущей страницы при каждом ее перемещении. getChildAt(getCurrentItem()) дает разные результаты, поэтому это не надежно.

...