ViewPager with fixed width childs

android, android-viewpager

Solution

It is possible to scale the pages within the ViewPager with `FragmentPagerAdapter.getPageWidth`. You will need a custom FragmentPagerAdapter. If you return a number between 0 and 1, the pages are scaled down, width > 1 scales pages up accordingly. But this is not really good, because you can't scroll the image within the up-scaled page.

If you wrap the ImageView in a `HorizontalScrollView`, things are a bit better, you can scroll the images within pages, but the swipe gesture between pages is caught by the HorizontalScrollView if you are not very fast. See this video.

So the solution is truly to use a custom HorizontalScrollView (see `InterceptingHorizontalScrollView`) which disallows intercepting the onTouch event, but also allows it when the User scrolls to the end (See overidden `onOverScrolled`). See this video or the image below for the difference.

EDIT You don't need to override onInterceptTouchEvent, because HorizontalScrollView intercepts them by default (so scrolling the image has higher priority than paging.)

Finally, here's all the code:

MainActivity.java

public class MainActivity extends Activity {

    private ViewPager mViewPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Set up the ViewPager
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setPageMargin(30);
        mViewPager.setAdapter(new ImagePagerAdapter(getFragmentManager()));
    }

    private class ImagePagerAdapter extends FragmentPagerAdapter {

        public ImagePagerAdapter(FragmentManager fm) {
            super(fm);
        }
        @Override
        public Fragment getItem(int i) {
            switch(i) {
                case 0:
                    return ImageFragment.newInstance(R.drawable.forest1);
                case 1:
                    return ImageFragment.newInstance(R.drawable.forest2);
                case 2:
                    return ImageFragment.newInstance(R.drawable.forest3);
                default:
                    return ImageFragment.newInstance(R.drawable.ic_launcher);
            }
        }
        @Override
        public int getCount() {
            return 3;
        }
        @Override
        public float getPageWidth(int position)
        {
            // Here it is possible to scale page width
            return super.getPageWidth(position);
        }
    }
}

activity_main.xml

<RelativeLayout 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"
    tools:context=".MainActivity">

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</RelativeLayout>

ImageFragment.java

public class ImageFragment extends Fragment {
    private static final String ARG_PARAM1 = "image_resid";
    private int mImageResId;

    public static ImageFragment newInstance(int image_resid) {
        ImageFragment fragment = new ImageFragment();
        Bundle args = new Bundle();
        args.putInt(ARG_PARAM1, image_resid);
        fragment.setArguments(args);
        return fragment;
    }
    public ImageFragment() {
        // Required empty public constructor
    }
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mImageResId = getArguments().getInt(ARG_PARAM1);
        }
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_image, container, false);
        ImageView imageView = (ImageView)v.findViewById(R.id.imageView);
        imageView.setImageResource(mImageResId);
        return v;
    }
}

fragment_image.xml

<com.gyebro.viewpagertest.InterceptingHorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="600dp"
    android:layout_height="match_parent"
    tools:context="com.gyebro.viewpagertest.ImageFragment">
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:adjustViewBounds="true"
            android:id="@+id/imageView"
            android:src="@drawable/forest1" />
</com.gyebro.viewpagertest.InterceptingHorizontalScrollView>

InterceptingHorizontalScrollView.java

public class InterceptingHorizontalScrollView extends HorizontalScrollView {

    public InterceptingHorizontalScrollView(Context context) {
        super(context);
    }
    public InterceptingHorizontalScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public InterceptingHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /*@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (getParent() != null) {
            switch (ev.getAction()) {
                case MotionEvent.ACTION_MOVE:
                    getParent().requestDisallowInterceptTouchEvent(true);
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    getParent().requestDisallowInterceptTouchEvent(false);
                    break;
            }
        }
        return super.onInterceptTouchEvent(ev);
    }*/

    @Override
    protected void onOverScrolled (int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
        super.onOverScrolled(scrollX,scrollY,clampedX,clampedY);
        // if clampedX == true, we've reached the end of the HorizontalScrollView so
        // allow parent to intercept
        if(clampedX) {
            Log.d("InterceptingHorizontalScrollView", "Reached the end, allowing interception");
            getParent().requestDisallowInterceptTouchEvent(false);
        }
    }
}

Problem

I need to design a `ViewPager` which able to pass childs with fixed width (e.g childs with 700dp width), Unfortunately the current version of `ViewPager` will automatically makes all childrens width to `MATCH_PARENT`, is there any way to add this functionality to `ViewPager`? My `ViewPager` layout: ``` <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <android.support.v4.view.ViewPager android:id="@+id/some_id" android:layout_width="match_parent" android:layout_height="300dp" android:overScrollMode="never" /> </LinearLayout> ``` `ViewPager` childs layout: ``` <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/banner_main_layout_container" android:layout_width="700dp" android:layout_height="match_parent" android:background="#fff" android:gravity="center" android:orientation="vertical" > <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:src="some images"/> </LinearLayout> ``` Thanks in Advance...

Original source