Android ViewPager - Show preview of page on left and right
AndroidAndroid ViewpagerAndroid Problem Overview
I'm using Android's ViewPager
. What I want to do is to show a preview of the page on both the left and the right. I've seen where I can use a negative pageMargin
to show a preview of the right side.
setPageMargin(-100);
Is there anyway that I can show a preview of the left side aswell? Its basically something similar to the gallery widget that I am looking for.
Android Solutions
Solution 1 - Android
To show preview of left and right pages set the following two values
viewpager.setClipToPadding(false);
viewpager.setPadding(left,0,right,0);
If you need space between two pages in the viewpager then add
viewpager.setPageMargin(int);
Solution 2 - Android
Solution with the new ViewPager2
Nowadays you should consider using ViewPager2 which "replaces ViewPager, addressing most of its predecessor’s pain-points":
> * Based on RecyclerView
> * RTL (right-to-left) layout support
> * Vertical orientation support
> * Reliable Fragment support (including handling changes to the underlying Fragment collection)
> * Dataset change animations (including DiffUtil
support)
The result
The code
In your Activity/Fragment, setup the ViewPager2:
// MyRecyclerViewAdapter is an standard RecyclerView.Adapter :)
viewPager2.adapter = MyRecyclerViewAdapter()
// You need to retain one page on each side so that the next and previous items are visible
viewPager2.offscreenPageLimit = 1
// Add a PageTransformer that translates the next and previous items horizontally
// towards the center of the screen, which makes them visible
val nextItemVisiblePx = resources.getDimension(R.dimen.viewpager_next_item_visible)
val currentItemHorizontalMarginPx = resources.getDimension(R.dimen.viewpager_current_item_horizontal_margin)
val pageTranslationX = nextItemVisiblePx + currentItemHorizontalMarginPx
val pageTransformer = ViewPager2.PageTransformer { page: View, position: Float ->
page.translationX = -pageTranslationX * position
// Next line scales the item's height. You can remove it if you don't want this effect
page.scaleY = 1 - (0.25f * abs(position))
// If you want a fading effect uncomment the next line:
// page.alpha = 0.25f + (1 - abs(position))
}
viewPager2.setPageTransformer(pageTransformer)
// The ItemDecoration gives the current (centered) item horizontal margin so that
// it doesn't occupy the whole screen width. Without it the items overlap
val itemDecoration = HorizontalMarginItemDecoration(
context,
R.dimen.viewpager_current_item_horizontal_margin
)
viewPager2.addItemDecoration(itemDecoration)
Add the HorizontalMarginItemDecoration
, which is a trivial ItemDecoration
:
/**
* Adds margin to the left and right sides of the RecyclerView item.
* Adapted from https://stackoverflow.com/a/27664023/4034572
* @param horizontalMarginInDp the margin resource, in dp.
*/
class HorizontalMarginItemDecoration(context: Context, @DimenRes horizontalMarginInDp: Int) :
RecyclerView.ItemDecoration() {
private val horizontalMarginInPx: Int =
context.resources.getDimension(horizontalMarginInDp).toInt()
override fun getItemOffsets(
outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State
) {
outRect.right = horizontalMarginInPx
outRect.left = horizontalMarginInPx
}
}
Add the dimensions that control how much of the previous/next item is visible, and current item horizontal margin:
<dimen name="viewpager_next_item_visible">26dp</dimen>
<dimen name="viewpager_current_item_horizontal_margin">42dp</dimen>
Finally add the ViewPager2
to your layout:
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
One important thing: a ViewPager2
item must have layout_height="match_parent"
(otherwise it throws an IllegalStateException), so you should do something like:
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" <-- this!
app:cardCornerRadius="8dp"
app:cardUseCompatPadding="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="280dp">
<!-- ... -->
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
PageTransformer examples
Google has added a guide on ViewPager2 that has 2 PageTransformer
implementations that you can use as an inspiration: https://developer.android.com/training/animation/screen-slide-2
About the new ViewPager2
Solution 3 - Android
The answer by @JijuInduchoodan is perfect and working. However, since I am relatively new to Android, it took me a while to understand & set it properly. So, I am posting this answer for future reference and help anyone else who is in same shoes as me.
if (viewPager == null)
{
// Initializing view pager
viewPager = (ViewPager) findViewById(R.id.vpLookBook);
// Disable clip to padding
viewPager.setClipToPadding(false);
// set padding manually, the more you set the padding the more you see of prev & next page
viewPager.setPadding(40, 0, 40, 0);
// sets a margin b/w individual pages to ensure that there is a gap b/w them
viewPager.setPageMargin(20);
}
There's no need to set any width to the ViewPager's
page in the adapter. There no additional code required to see previous & next page in ViewPager
. However, if you want to add blank space at the top & bottom of the each page, you can set the following code to ViewPager's
child page`s parent layout.
android:paddingTop="20dp"
android:paddingBottom="20dp"
This will be the final look of the ViewPager.
Solution 4 - Android
In 2017 such behaviour additionally can be easily achieved by using RecyclerView
with PagerSnapHelper (added in version 25.1.0 of v7 support library):

Sometime ago I needed such viewpager-like feature and prepared a tiny library:
MetalRecyclerPagerView - you can find all the code along with examples there.
Mainly it consists of a single class file: MetalRecyclerViewPager.java (and two xmls: attrs.xml and ids.xml).
Hope it helps somebody and will save some hours :)
Solution 5 - Android
You can do this in xml file, just use below code:
android:clipToPadding="false"
android:paddingLeft="XX"
android:paddingRight="XX"
> For example:
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingLeft="30dp"
android:paddingRight="30dp" />
> Note: If you need space between pages, set padding/margin to child fragments
Solution 6 - Android
if someone still looking for solution, I had customized the ViewPage to achieve it without using negative margin, find a sample project here https://github.com/44kksharma/Android-ViewPager-Carousel-UI
it should work in most cases but you can still define page margin with
mPager.setPageMargin(margin in pixel);
https://imgflip.com/gif/2557e5"><img src="https://i.imgflip.com/2557e5.gif" title="made at imgflip.com"/>
Solution 7 - Android
Kotlin + ViewPager2
I am late to the party but the above answers didn't work for me. So I am here to help others who are still looking for the answer.
-
Your XML:
<androidx.viewpager2.widget.ViewPager2 android:id="@+id/newsHomeViewPager" android:layout_width="match_parent" android:layout_height="wrap_content" />
-
Your item Layout root view should be like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingStart="@dimen/dp_10" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" />
-
Your Activity/Fragment:
add this before setting your viewpager adapter
newsHomeViewPager.apply {
clipToPadding = false // allow full width shown with padding
clipChildren = false // allow left/right item is not clipped
offscreenPageLimit = 2 // make sure left/right item is rendered
}
//increase this offset to show more of left/right
val offsetPx =
resources.getDimension(R.dimen.dp_30).toInt().dpToPx(resources.displayMetrics)
newsHomeViewPager.setPadding(0, 0, offsetPx, 0)
//increase this offset to increase distance between 2 items
val pageMarginPx =
resources.getDimension(R.dimen.dp_5).toInt().dpToPx(resources.displayMetrics)
val marginTransformer = MarginPageTransformer(pageMarginPx)
newsHomeViewPager.setPageTransformer(marginTransformer)
4. dp to pixel function:
fun Int.dpToPx(displayMetrics: DisplayMetrics): Int = (this * displayMetrics.density).toInt()
General Notes:
-
I've to show the next page only, so in
setPadding
method, I've kept 0 for left andoffsetPx
for right. So addoffsetPx
to the right side also in thesetPadding
method if you wanted to show the right-side item too. -
I've used dp from the dimension file, you can use your own.
Thank you, happy coding.
Solution 8 - Android
For those struggling to have this on different screens,
mPager.setClipToPadding(false);
DisplayMetrics displayMetrics = new DisplayMetrics();
self.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int width = displayMetrics.widthPixels;
int paddingToSet = width/4; //set this ratio according to how much of the next and previos screen you want to show.
mPager.setPadding(paddingToSet,0,paddingToSet,0);
Solution 9 - Android
Thanks to the author of this article. It's the best solution I found.
Just create a function eg. in your Helpers
class like:
fun ViewPager2.showHorizontalPreview(offsetDpLeft : Int, offsetDpRight : Int, marginBtwItems : Int){
this.apply {
clipToPadding = false // allow full width shown with padding
clipChildren = false // allow left/right item is not clipped
offscreenPageLimit = 2 // make sure left/right item is rendered
}
// increase this offset to show more of left/right
val offsetPxLeft = offsetDpLeft.toPx()
val offsetPxRight = offsetDpRight.toPx()
this.setPadding(offsetPxLeft, 0, offsetPxRight, 0)
// increase this offset to increase distance between 2 items
val pageMarginPx = marginBtwItems.toPx()
val marginTransformer = MarginPageTransformer(pageMarginPx)
this.setPageTransformer(marginTransformer)
}
and call it like:
mViewPager.showHorizontalPreview(40,40,5)
in your Activity/Fragment
Solution 10 - Android
Note that when setting none zero paddings to a viewpager, the viewpager's edgeeffect placement is messed up, this is a bug of the viewpager, see here:viewpager edgeeffect bug
You can either disable the edge effect by setting android:overScrollMode="never"
to the viewpager, or you can fix the bug with a slightly modified version of the EdgeEffect class:ViewPagerEdgeEffect fix
Solution 11 - Android
override fun getPageWidth(position: Int): Float {
return 0.7f
}
Add this in adapter class file, This worked for me
Solution 12 - Android
Based on Jiju's answer, if you want to set margin between pages for VIEWPAGER 2, please use the code like this:
viewpager.setPageTransformer(new MarginPageTransformer(14));
Solution 13 - Android
In the XML file you should set paddings like so:
in the fragment:
int margin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20*2, getResources().getDisplayMetrics());
and to have it all set, use this
myViewPager.setPageMargin(-margin);
should do the trick :)
Solution 14 - Android
Use this fragment adapter and class to view the viewpager in left and right scroll.add necessary classes to scroll to view next pages.
package com.rmn.viewpager;
import java.util.List;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
/**
* The <code>PagerAdapter</code> serves the fragments when paging.
* @author mwho
*/
public class PagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
/**
* @param fm
* @param fragments
*/
public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
/* (non-Javadoc)
* @see android.support.v4.app.FragmentPagerAdapter#getItem(int)
*/
@Override
public Fragment getItem(int position) {
return this.fragments.get(position);
}
/* (non-Javadoc)
* @see android.support.v4.view.PagerAdapter#getCount()
*/
@Override
public int getCount() {
return this.fragments.size();
}
}
package com.manishkpr.viewpager;
import android.content.Context;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
public class ViewPagerAdapter extends FragmentPagerAdapter {
private Context _context;
public ViewPagerAdapter(Context context, FragmentManager fm) {
super(fm);
_context=context;
}
@Override
public Fragment getItem(int position) {
Fragment f = new Fragment();
switch(position){
case 0:
f=LayoutOne.newInstance(_context);
break;
case 1:
f=LayoutTwo.newInstance(_context);
break;
}
return f;
}
@Override
public int getCount() {
return 2;
}
}