Skip to content

Instantly share code, notes, and snippets.

@pflammertsma
Last active August 29, 2015 14:06
Show Gist options
  • Select an option

  • Save pflammertsma/754d55a11e4329baee77 to your computer and use it in GitHub Desktop.

Select an option

Save pflammertsma/754d55a11e4329baee77 to your computer and use it in GitHub Desktop.
public class MultiViewPager extends ViewPager {
/**
* Maximum size.
*/
private int mMaxWidth = -1;
/**
* Maximum size.
*/
private int mMaxHeight = -1;
/**
* Child view inside a page to match the page size against.
*/
private int mMatchWidthChildResId;
/**
* Internal state to schedule a new measurement pass.
*/
private boolean mNeedsMeasurePage;
private static void constrainTo(Point size, Point maxSize) {
if (maxSize.x >= 0) {
if (size.x > maxSize.x) {
size.x = maxSize.x;
}
}
if (maxSize.y >= 0) {
if (size.y > maxSize.y) {
size.y = maxSize.y;
}
}
}
public MultiViewPager(Context context) {
super(context);
}
public MultiViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
setClipChildren(false);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MultiViewPager);
setMaxWidth(ta.getDimensionPixelSize(R.styleable.MultiViewPager_android_maxWidth, -1));
setMaxHeight(ta.getDimensionPixelSize(R.styleable.MultiViewPager_android_maxHeight, -1));
setMatchChildWidth(ta.getResourceId(R.styleable.MultiViewPager_matchChildWidth, 0));
ta.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Point size = new Point(
MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.getSize(heightMeasureSpec));
if (mMaxWidth >= 0 || mMaxHeight >= 0) {
Point maxSize = new Point(mMaxWidth, mMaxHeight);
constrainTo(size, maxSize);
widthMeasureSpec = MeasureSpec.makeMeasureSpec(
size.x,
MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(
size.y,
MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
onMeasurePage(widthMeasureSpec, heightMeasureSpec);
}
protected void onMeasurePage(int widthMeasureSpec, int heightMeasureSpec) {
// Only measure if a measurement pass was scheduled
if (!mNeedsMeasurePage) {
return;
}
if (mMatchWidthChildResId == 0) {
mNeedsMeasurePage = false;
} else if (getChildCount() > 0) {
View child = getChildAt(0);
child.measure(widthMeasureSpec, heightMeasureSpec);
int pageWidth = child.getMeasuredWidth();
View match = child.findViewById(mMatchWidthChildResId);
if (match == null) {
throw new NullPointerException(
"MatchWithChildResId did not find that ID in the first fragment of the ViewPager; "
+ "is that view defined in the child view's layout? Note that MultiViewPager "
+ "only measures the child for index 0.");
}
int childWidth = match.getMeasuredWidth();
// Check that the measurement was successful
if (childWidth > 0) {
mNeedsMeasurePage = false;
int difference = pageWidth - childWidth;
setPageMargin(-difference);
int offscreen = (int) Math.ceil((float) pageWidth / (float) childWidth) + 1;
setOffscreenPageLimit(offscreen);
requestLayout();
}
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// Schedule a new measurement pass as the dimensions have changed
mNeedsMeasurePage = true;
}
/**
* Sets the child view inside a page to match the page size against.
*
* @param matchChildWidthResId
*/
public void setMatchChildWidth(int matchChildWidthResId) {
if (mMatchWidthChildResId != matchChildWidthResId) {
mMatchWidthChildResId = matchChildWidthResId;
mNeedsMeasurePage = true;
}
}
/**
* Sets the maximum size.
*
* @param width
*/
public void setMaxWidth(int width) {
mMaxWidth = width;
}
/**
* Sets the maximum size.
*
* @param height
*/
public void setMaxHeight(int height) {
mMaxHeight = height;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment