I have followed this and that answers, i also found this link.
I use those resources to do trial & errors. Now my custom ViewPager
successfully measure its content, but only the first one displayed. FYI, my ViewPager
holds some complex views, like ExpendableListView
- thats why none of the code in those resources working perfectly, i need to modify the code by myself.
I have 4 fragments (content), so i use pager.setOffscreenPageLimit(3);
This is my custom ViewPager
:
public class CustomViewPager extends ViewPager{
public CustomViewPager (Context context) {
super(context);
}
public CustomViewPager (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();
}
}
This is my CustomPagerTabStrip
:
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
android.view.ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
And this is my XML :
<RelativeLayout
android:id="@+id/relativePager"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<com.xxx.yyy.util.CustomViewPager
android:id="@+id/detailPager"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<com.xxx.yyy.util.CustomPagerTabStrip
android:id="@+id/detailTab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#161C28"
android:textColor="#FFFFFF" />
</com.xxx.yyy.util.CustomViewPager>
</RelativeLayout>
The example case :
If the first fragment's height is 100px, then all of other fragments will stay on 100px. So if the second fragment's height is 130px, it will be cut to 100px.
When i tried to debug, the onMeasure
on my CustomViewPager
always called 4 times when the Activity
is created, but all of them only read the first fragment. The onMeasure
never getting called again after that, even when i change (slide left/right) from one fragment to other.
Please help me out, i have spended lot of hours to get this thing working. Just ask me if you need more information, Thanks for your time.
Hi Blaze found some thing use full, following solution is working for me.
Its include a custom scroll view and custom view pager. The purpose custom view pager is its calculate the height dynamically according to its children's height, its hieght is set to wrap content initially and the purpose of scroll view is handling the touch event , if the users scrolls the screen vertically it will not pass the touch even to scroll and thus user is able to scroll the page.
Custom scroll view
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 SimpleOnGestureListener {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
return (Math.abs(distanceY) > Math.abs(distanceX));
}
}
}
Custom view pager
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();
}
}
Layout file
<com.example.demo2.activity.widget.CustomScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
style="@style/text"
android:text="Text 1" />
<View style="@style/text_divider" />
<TextView
style="@style/text"
android:text="Text 2" />
<com.example.demo2.activity.widget.CustomPager
android:id="@+id/myViewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<View style="@style/text_divider" />
<TextView
style="@style/text"
android:text="Text 4" />
<View style="@style/text_divider" />
<TextView
style="@style/text"
android:text="Text 5" />
<View style="@style/text_divider" />
<TextView
style="@style/text"
android:text="Text 6" />
<View style="@style/text_divider" />
<TextView
style="@style/text"
android:text="Text 7" />
<View style="@style/text_divider" />
<TextView
style="@style/text"
android:text="Text 8" />
<View style="@style/text_divider" />
<TextView
style="@style/text"
android:text="Text 9" />
<View style="@style/text_divider" />
<TextView
style="@style/text"
android:text="Text 10" />
</LinearLayout>
Activity
public class MainActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyPagerAdapter pageAdapter = new MyPagerAdapter(getSupportFragmentManager());
ViewPager pager = (ViewPager)findViewById(R.id.myViewPager);
pager.setAdapter(pageAdapter);
}
}
Fragment adapter
fragments with different heights are added to the viewpager, FragmentBlue,Green etc are just fragments used to add to the viewpager you can use your own fragments, one thing to remember is their outer layout should be same in my case I used liner layout for all
public class MyPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
public MyPagerAdapter(FragmentManager fm) {
super(fm);
this.fragments = new ArrayList<Fragment>();
fragments.add(new FragmentBlue());
fragments.add(new FragmentGreen());
fragments.add(new FragmentPink());
fragments.add(new FragmentRed());
}
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
}
public CustomPager (Context context) {
super(context);
}
public CustomPager (Context context, AttributeSet attrs) {
super(context, attrs);
}
int getMeasureExactly(View child, int widthMeasureSpec) {
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int height = child.getMeasuredHeight();
return MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
}
@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);
if (tab == null) {
return;
}
int width = getMeasuredWidth();
if (wrapHeight) {
// Keep the current measured width.
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
}
Fragment fragment = ((Fragment) getAdapter().instantiateItem(this, getCurrentItem()));
heightMeasureSpec = getMeasureExactly(fragment.getView(), widthMeasureSpec);
//Log.i(Constants.TAG, "item :" + getCurrentItem() + "|height" + heightMeasureSpec);
// super has to be called again so the new specs are treated as
// exact measurements.
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With