CLDev
CLDev

Reputation: 1074

Can ViewPager have multiple views in per page?

After trying out the Gallery and Horizontal Scroll View, I found that the View Pager does what I need but with one minor thing missing. Can the View Pager have multiple views per page?

I know that View Pager shows only 1 view/page per swipe. I was wondering if I can limit my views width so my 2nd view following it will show?

For example: I have 3 views and I want the screen to show view 1 and part of view 2 so the user knows there is more content so they can swipe to view 2.

|view 1|view 2|view 3|
|screen   |

Upvotes: 46

Views: 60861

Answers (9)

saranya prasad
saranya prasad

Reputation: 1

Main activity xml file add this code

      <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="130dp"
                    android:layout_marginLeft="5dp"
                    android:layout_marginRight="5dp"
                    android:orientation="vertical"
                    android:weightSum="1">
                    <RelativeLayout
                        android:layout_width="match_parent"
                        android:layout_height="130dp">
                        <com.wonderla.wonderla.muthootpathanamthitta.activity_muthootpathanm.PagerContainer
                            android:id="@+id/pager_container"
                            android:layout_width="match_parent"
                            android:layout_height="fill_parent">
                            <android.support.v4.view.ViewPager
                                android:id="@+id/viewpager"
                                android:layout_width="100dip"
                                android:layout_height="100dip"/>
                      </com.wonderla.wonderla.muthootpathanamthitta.activity_muthootpathanm.PagerContainer>
                    </RelativeLayout>
                </LinearLayout>

Main Activity code

public class MainActivity extends Activity{
 final Integer[] XMEN2= {R.mipmap.bookticket,R.mipmap.safty,R.mipmap.privacy};
 private ArrayList<Integer> XMENArray2 = new ArrayList<Integer>();
 PagerContainer mContainer;
 int currentPage2 = 0;
 private static int NUM_PAGES2 = 0;
 ViewPager mPager2;

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
        initData2();}
 private void initViews() {
  mPager2 = (ViewPager)findViewById(R.id.viewpager);
  mContainer = (PagerContainer)findViewById(R.id.pager_container);
  mPager2.setOffscreenPageLimit(5);
  mPager2.setPageMargin(15);
  mPager2.setClipChildren(false);
 }

   private void initData2() {

        for(int i=0;i<XMEN2.length;i++)
            XMENArray2.add(XMEN2[i]);
        mPager2.setAdapter(new Sliding_Adaptertwo(getActivity(),XMENArray2));
        NUM_PAGES2 =XMEN2.length;
        final Handler handler = new Handler();
        final Runnable Update = new Runnable() {
            public void run() {
                if (currentPage2 == NUM_PAGES2) {
                    currentPage2= 0;
                }mPager2.setCurrentItem(currentPage2++, true);
            }
        };
        Timer swipeTimer = new Timer();
        swipeTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                handler.post(Update);
            }
        }, 3000, 3000);

    }



}

Pager View pagercontainer class


import android.content.Context;

import android.graphics.Point;

import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import android.widget.FrameLayout;


public class PagerContainer extends FrameLayout implements ViewPager.OnPageChangeListener {

    private ViewPager mPager;
    boolean mNeedsRedraw = false;

    public PagerContainer(Context context) {
        super(context);
        init();
    }

    public PagerContainer(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

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

    private void init() {
        //Disable clipping of children so non-selected pages are visible
        setClipChildren(false);

        //Child clipping doesn't work with hardware acceleration in Android 3.x/4.x
        //You need to set this value here if using hardware acceleration in an
        // application targeted at these releases.
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        try {
            mPager = (ViewPager) getChildAt(0);
            mPager.setOnPageChangeListener(this);
        } catch (Exception e) {
            throw new IllegalStateException("The root child of PagerContainer must be a ViewPager");
        }
    }

    public ViewPager getViewPager() {
        return mPager;
    }

    private Point mCenter = new Point();
    private Point mInitialTouch = new Point();

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        mCenter.x = w / 2;
        mCenter.y = h / 2;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        //We capture any touches not already handled by the ViewPager
        // to implement scrolling from a touch outside the pager bounds.
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mInitialTouch.x = (int)ev.getX();
                mInitialTouch.y = (int)ev.getY();
            default:
                ev.offsetLocation(mCenter.x - mInitialTouch.x, mCenter.y - mInitialTouch.y);
                break;
        }

        return mPager.dispatchTouchEvent(ev);
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        //Force the container to redraw on scrolling.
        //Without this the outer pages render initially and then stay static
        if (mNeedsRedraw) invalidate();
    }

    @Override
    public void onPageSelected(int position) { }

    @Override
    public void onPageScrollStateChanged(int state) {
        mNeedsRedraw = (state != ViewPager.SCROLL_STATE_IDLE);
    }
}

and its Adapter

public class Sliding_Adaptertwo extends PagerAdapter {


    private ArrayList<Integer> IMAGES;
    private LayoutInflater inflater;
    private Context context;


    public Sliding_Adaptertwo(Context context, ArrayList<Integer> IMAGES) {
        this.context = context;
        this.IMAGES=IMAGES;
        inflater = LayoutInflater.from(context);
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
    }

    @Override
    public int getCount() {
        return IMAGES.size();
    }

    @Override
    public Object instantiateItem(ViewGroup view, int position) {
        View imageLayout = inflater.inflate(R.layout.sliding_layout, view, false);

        assert imageLayout != null;
        final ImageView imageView = (ImageView) imageLayout
                .findViewById(R.id.image);


        imageView.setImageResource(IMAGES.get(position));

        view.addView(imageLayout, 0);

        return imageLayout;
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view.equals(object);
    }

    @Override
    public void restoreState(Parcelable state, ClassLoader loader) {
    }

    @Override
    public Parcelable saveState() {
        return null;
    }


}

xml file of adapter class

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="fill_parent"
    >

    <ImageView
        android:id="@+id/image"
        android:layout_width="90dp"
        android:layout_height="90dp"
        android:adjustViewBounds="true"
        android:layout_gravity="center"
        android:scaleType="fitXY"
        android:src="@drawable/ad1"
       />
</FrameLayout>

it works fine

Upvotes: 0

saranya prasad
saranya prasad

Reputation: 1

In xml file using this code(Main Activity)

                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="130dp"
                    android:layout_marginLeft="5dp"
                    android:layout_marginRight="5dp"
                    android:orientation="vertical"
                    android:weightSum="1">
                    <RelativeLayout
                        android:layout_width="match_parent"
                        android:layout_height="130dp">
                        <com.wonderla.wonderla.muthootpathanamthitta.activity_muthootpathanm.PagerContainer
                            android:id="@+id/pager_container"
                            android:layout_width="match_parent"
                            android:layout_height="fill_parent">
                            <android.support.v4.view.ViewPager
                                android:id="@+id/viewpager"
                                android:layout_width="100dip"
                                android:layout_height="100dip"/>
                      </com.wonderla.wonderla.muthootpathanamthitta.activity_muthootpathanm.PagerContainer>
                    </RelativeLayout>
                </LinearLayout>

Upvotes: 0

Urvi Jasani
Urvi Jasani

Reputation: 11

LayoutParams lp = new LayoutParams(width,height);
viewpager.setLayoutParams(lp);

Upvotes: 0

howerknea
howerknea

Reputation: 375

This is how I got it:

<android.support.v4.view.ViewPager
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_gravity="center"
    android:layout_marginBottom="8dp"
    android:clipToPadding="false"
    android:gravity="center"
    android:paddingLeft="36dp"
    android:paddingRight="36dp"/>

and in activity,i use this :

markPager.setPageMargin(64);

hope it helps!

Upvotes: 17

Raktim Bhattacharya
Raktim Bhattacharya

Reputation: 59

viewPager.setPageMargin(-18);// adjust accordingly ,-means less gap

in imageadapter

private class ImagePagerAdapter2 extends PagerAdapter {
    private int[] mImages = new int[] {

            R.drawable.add1,
            R.drawable.add3,
            R.drawable.add4,
            R.drawable.add2,
    };
    @Override
    public float getPageWidth(int position) {
        return .3f;
    }

adjust return value...lesser means more image......0.3 means atleast 3 images at a time.

Upvotes: 1

Paul Lammertsma
Paul Lammertsma

Reputation: 38252

Mark Murphy has an interesting blog post addressing precisely this problem. Although I ended up using my own solution in this thread, it's worthwhile looking at Dave Smith's code, which Mark references in the blog post:

https://gist.github.com/8cbe094bb7a783e37ad1/

Warning! Before you take this approach, beware of some very serious issues with this approach, mentioned both at the end of this post and in the comments below.

You'll end up with this:

Screenshot of Dave Smith's PagerContainer

It effectively works by wrapping a ViewPager into a subclass of FrameLayout, setting it to a specific size, and calling setClipChildren(false). This inhibits Android from clipping the views that exceed beyond the boundaries of the ViewPager, and visually accomplishes what you want.

In XML, it's very simple:

<com.example.pagercontainer.PagerContainer
    android:id="@+id/pager_container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#CCC">
    <android.support.v4.view.ViewPager
        android:layout_width="150dp"
        android:layout_height="100dp"
        android:layout_gravity="center_horizontal" />
</com.example.pagercontainer.PagerContainer>

Add in a little code for handling touch events from outside of the ViewPager and invalidating the display when scrolling, and you're done.

That being said, and while this works great in general, I did notice that there is an edge-case that isn't solved with this fairly simple construction: when calling setCurrentPage() on the ViewPager. The only way I could find to resolve this was by subclassing ViewPager itself and having its invalidate() function also invalidate the PagerContainer.

Upvotes: 32

Paul Lammertsma
Paul Lammertsma

Reputation: 38252

I discovered that a perhaps even simpler solution through specifying a negative margin for the ViewPager. I've created the MultiViewPager project on GitHub, which you may want to take a look at:

https://github.com/Pixplicity/MultiViewPager

Although MultiViewPager expects a child view for specifying the dimension, the principle revolves around setting the page margin:

ViewPager.setPageMargin(
    getResources().getDimensionPixelOffset(R.dimen.viewpager_margin));

I then specified this dimension in my dimens.xml:

<dimen name="viewpager_margin">-64dp</dimen>

To compensate for overlapping pages, each page's content view has the opposite margin:

android:layout_marginLeft="@dimen/viewpager_margin_fix"
android:layout_marginRight="@dimen/viewpager_margin_fix"

Again in dimens.xml:

<dimen name="viewpager_margin_fix">32dp</dimen>

(Note that the viewpager_margin_fix dimension is half that of the absolute viewpager_margin dimension.)

We implemented this in the Dutch newspaper app De Telegraaf Krant:

Phone example in De Telegraaf KrantTablet example

Upvotes: 61

goldengil
goldengil

Reputation: 1037

I had the same problem with the only difference that i needed to show 3 pages at once (previous, current and next pages). After a really long research for the best solution i think i found it. The solution is a mix of few of the answers here:

As @Paul Lammertsma's answer pointed out - Dave Smith's code in Mark Murphy's blog is the basis for the solution. The only problem for me was that the ViewPager was only on the top part of the screen due to the size they give it in the xml file:

 android:layout_width="150dp"
 android:layout_height="100dp"

Which wasn't good for my purpose since i was looking for something that will spread all over the screen. So i changed it to wrap the content as you can see here:

  <com.example.nutrino_assignment.PagerContainer
    android:id="@+id/pager_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#CCC">
    <android.support.v4.view.ViewPager
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center" />
  </com.example.nutrino_assignment.PagerContainer>

Now I lost all the effect of what the tutorial was trying to do. Using @andro's answer i was able to show more then 1 page at a time: exactly 2! The current and the next. Did so by overriding as follow:

        @Override 
    public float getPageWidth(int position) {
        return(0.9f); 
    }

That was almost what i needed... (even though i think its enough for what you were asking), but for others who might need something like what i was needed: For the last part of the solution i used the idea in this answer, again by @Paul Lammertsma. In Dave Smith's code you will find in the onCreate method this line:

   //A little space between pages
    pager.setPageMargin(15);

which i replaced with:

   //A little space between pages
    pager.setPageMargin(-64);

now on the first page looks:

|view 1|view 2|view 3|
|screen   |

while on the 2nd it looks like:

|view 1|view 2|view 3|
     |screen    |

Hope it will help someone! I wasted like 2 days on it... Good luck.

Upvotes: 9

andro
andro

Reputation: 977

It is possible to show more than one page on the same screen. One of the ways is by overriding the getPageWidth() method in the PAgerAdapter. getPageWidth() returns a float number between 0 and 1 indicating how much width of the Viewpager should the page occupy. By default it is set to 1. So, you can change this to the width you wish. You can read more about this here & github project.

Upvotes: 18

Related Questions