package net.osmand.plus.views.controls;
import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
public class WrapContentHeightViewPager extends ViewPager {
private boolean swipeable = true;
private int height = 0;
private int decorHeight = 0;
private int widthMeasuredSpec;
private boolean animateHeight;
private int rightHeight;
private int leftHeight;
private int scrollingPosition = -1;
public interface ViewAtPositionInterface {
public View getViewAtPosition(int position);
}
public WrapContentHeightViewPager(Context context) {
super(context);
init();
}
public WrapContentHeightViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
addOnPageChangeListener(new OnPageChangeListener() {
int state;
@Override
public void onPageScrolled(int position, float offset, int positionOffsetPixels) {}
@Override
public void onPageSelected(int position) {
if (state == SCROLL_STATE_IDLE) {
height = 0;
}
}
@Override
public void onPageScrollStateChanged(int state) {
this.state = state;
}
});
}
@Override
public void setAdapter(PagerAdapter adapter) {
if (!(adapter instanceof ViewAtPositionInterface)) {
throw new IllegalArgumentException("WrapContentHeightViewPager requires that PagerAdapter will implement ViewAtPositionInterface");
}
height = 0;
super.setAdapter(adapter);
}
/**
* Allows to redraw the view size to wrap the content of the bigger child.
*
* @param widthMeasureSpec with measured
* @param heightMeasureSpec height measured
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
widthMeasuredSpec = widthMeasureSpec;
int mode = MeasureSpec.getMode(heightMeasureSpec);
if (mode == MeasureSpec.UNSPECIFIED || mode == MeasureSpec.AT_MOST) {
if (height == 0) {
// measure vertical decor (i.e. PagerTitleStrip) based on ViewPager implementation
decorHeight = 0;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp != null && lp.isDecor) {
int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM;
if (consumeVertical) {
decorHeight += child.getMeasuredHeight() ;
}
}
}
// make sure that we have an height (not sure if this is necessary because it seems that onPageScrolled is called right after
int position = getCurrentItem();
View child = getViewAtPosition(position);
if (child != null) {
height = measureViewHeight(child);
}
}
int totalHeight = height + decorHeight + getPaddingBottom() + getPaddingTop();
heightMeasureSpec = MeasureSpec.makeMeasureSpec(totalHeight, MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
public void onPageScrolled(int position, float offset, int positionOffsetPixels) {
super.onPageScrolled(position, offset, positionOffsetPixels);
// cache scrolled view heights
if (scrollingPosition != position) {
scrollingPosition = position;
// scrolled position is always the left scrolled page
View leftView = getViewAtPosition(position);
View rightView = getViewAtPosition(position + 1);
if (leftView != null && rightView != null) {
leftHeight = measureViewHeight(leftView);
rightHeight = measureViewHeight(rightView);
animateHeight = true;
} else {
animateHeight = false;
}
}
if (animateHeight) {
int newHeight = (int) (leftHeight * (1 - offset) + rightHeight * (offset));
if (height != newHeight) {
height = newHeight;
requestLayout();
invalidate();
}
}
}
private int measureViewHeight(View view) {
view.measure(getChildMeasureSpec(widthMeasuredSpec, getPaddingLeft() + getPaddingRight(), view.getLayoutParams().width), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
return view.getMeasuredHeight();
}
protected View getViewAtPosition(int position) {
if (getAdapter() != null) {
Object objectAtPosition = ((ViewAtPositionInterface) getAdapter()).getViewAtPosition(position);
if (objectAtPosition != null) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child != null && getAdapter().isViewFromObject(child, objectAtPosition)) {
return child;
}
}
}
}
return null;
}
public boolean isSwipeable() {
return swipeable;
}
public void setSwipeable(boolean swipeable) {
this.swipeable = swipeable;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return swipeable && super.onInterceptTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return swipeable && super.onTouchEvent(event);
}
}