How to implement stack transformation in VerticalViewPager,Here is my code which i have implemented VerticalViewPager with stack transformation but the issue is it is fading out, I want to remove fading out while swipe up the page.
public class VerticalViewPager extends Activity {
private static final float MIN_SCALE = 0.75f;
PagerAdapter adapter;
private static final float MIN_ALPHA = 0.75f;
private boolean a;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.verticalviewpager);
final fr.castorflex.android.verticalviewpager.VerticalViewPager verticalViewPager = (fr.castorflex.android.verticalviewpager.VerticalViewPager) findViewById(R.id.verticalviewpager);
adapter = new MyCustomAdapter(VerticalViewPager.this, SplashScreen.newsidArray, SplashScreen.newsdescArray, SplashScreen.newstitleArray,
SplashScreen.newsimageArray, SplashScreen.newsdateArray, SplashScreen.newsauthorArray, SplashScreen.newsurlArray);
verticalViewPager.setOffscreenPageLimit(1);
verticalViewPager.setAdapter(adapter);
verticalViewPager.setPageTransformer(false, new PageTransformer() {
#Override
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
int pageHeight = view.getHeight();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 0) { // [-1,0]
view.setAlpha(1);
} else if (position <= 1) { // (0,1]
// Fade the page out.
view.setAlpha(1F-position);
view.setTranslationY((int) ((float) (pageHeight) * -position));
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
});
verticalViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
public void onPageScrollStateChanged(int state) {
}
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
int page = verticalViewPager.getCurrentItem();
Log.e("page",String.valueOf(page));
if((page+1)== MyCustomAdapter.nodata){
// Toast.makeText(VerticalViewPager.this,"No News Available To Swipeup",500).show();
final Toast toast = Toast.makeText(getApplicationContext(), "No News Available To Swipeup", Toast.LENGTH_SHORT);
toast.show();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
toast.cancel();
}
}, 500);
}
}
public void onPageSelected(int position) {
SplashScreen.myCustomPosition = position;
}
});
}
}
Related
I have made an app in which I have added functionality of vertical swipe using ViewPager class. Now I need help to show Admob Interstitial ad after 5 swipes. I have seen several other SO question but could not get clarity.
Can anyone help me how can I do this? Here is my code:
MainActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mains);
mData = dbHelper.getAll(Data.class);
DATA_CARDS = mData.size();
ScreenSlidePagerAdapter screenSlidePagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
VerticalViewPager verticalViewPager = (VerticalViewPager) findViewById(R.id.pager);
verticalViewPager.setAdapter(screenSlidePagerAdapter);
}
ScreenSlidePagerAdapter
public class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
private static final int NUM_PAGES = MainActivity.DATA_CARDS;
public ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
SlidingFragment slidingFragment = new SlidingFragment();
Bundle bundle = new Bundle();
bundle.putInt("position", position);
slidingFragment.setArguments(bundle);
return slidingFragment;
}
#Override
public int getCount() {
return NUM_PAGES;
}
}
VerticalViewPager
public class VerticalViewPager extends ViewPager {
public VerticalViewPager(Context context) {
super(context);
init();
}
public VerticalViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
setPageTransformer(true, new VerticalPageTransformer());]
setOverScrollMode(OVER_SCROLL_NEVER);
}
private class VerticalPageTransformer implements ViewPager.PageTransformer {
#Override
public void transformPage(View view, float position) {
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 1) { // [-1,1]
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
//set Y position to swipe in from top
float yPosition = position * view.getHeight();
view.setTranslationY(yPosition);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
/**
* Swaps the X and Y coordinates of your touch event.
*/
private MotionEvent swapXY(MotionEvent ev) {
float width = getWidth();
float height = getHeight();
float newX = (ev.getY() / height) * width;
float newY = (ev.getX() / width) * height;
ev.setLocation(newX, newY);
return ev;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev){
boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
swapXY(ev); // return touch coordinates to original reference frame for any child views
return intercepted;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(swapXY(ev));
}
}
You can add the PageChangeListener to your view pager and call the onPageSelected() calls, for this you need to have class field called e.g. int mAdCounter = 0:
verticalViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
mAdCount++;
if (mAdCount % 5 == 0) {
//Display your add
//It's better if you load the ad before you need to display it, you can hide the adview and load it
} else {
//Hide the adView
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
Above is my issue screenshot. I just want to remove the opacity while I swipe up and down. When I swipe down, the current page turns transparent. I need to remove that transparency. Instead of extending the ViewPager, I have extended the activity. Can anyone give me solution for this issue?
public class VerticalViewPager extends Activity {
private static final float MIN_SCALE = 0.75f;
PagerAdapter adapter;
private static final float MIN_ALPHA = 0.75f;
private boolean a;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.verticalviewpager);
fr.castorflex.android.verticalviewpager.VerticalViewPager verticalViewPager = (fr.castorflex.android.verticalviewpager.VerticalViewPager) findViewById(R.id.verticalviewpager);
adapter = new MyCustomAdapter(VerticalViewPager.this, SplashScreen.newsidArray, SplashScreen.newsdescArray, SplashScreen.newstitleArray,
SplashScreen.newsimageArray, SplashScreen.newsdateArray, SplashScreen.newsauthorArray, SplashScreen.newsurlArray);
verticalViewPager.setOffscreenPageLimit(1);
verticalViewPager.setAdapter(adapter);
verticalViewPager.setPageTransformer(false, new PageTransformer() {
#Override
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
int pageHeight = view.getHeight();
if (position <= -1.0F) {
view.setAlpha(1);
Log.e("1", "test1");
} else if (position < 0F) {
view.setAlpha(1);
Log.e("2", "test2");
} else if (position >= 0F) {
view.setAlpha(0.9F - position);
view.setTranslationY((int) ((float) (pageHeight) * -position));
Log.e("3", "test3" + position);
} else if (position > 1.0F) {
view.setAlpha(1);
// view.setTranslationX(position < 0 ? 0f : -pageHeight * position);
Log.e("4", "test4");
}
}
});
}
}
Please try this.
And you have to confirm not using setAlpha() anywhere for page layout.(e.g. layout xml)
verticalViewPager.setPageTransformer(false, new ViewPager.PageTransformer() {
#Override
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
int pageHeight = view.getHeight();
if (position >= 0) {
view.setTranslationY(position < 0 ? 0f : -pageHeight * position);
}
}
});
I got the answer, you need to set the background for the view you are animating. By default it is transparent
android:background="#FFFFFF"
I'm trying to create interface like
.
Central element is ViewPager with full-size image, top element is RecyclerView with preview images. But I couldn't find the way to magnet elements to center. Is there way to override behavior of RecyclerView?
I found the solution exactly what you need. I created a small example on github.com: AndroidPreviewSlider
The thing is that top view is ViewPager and center view is ViewPager too.
Detailed code is below:
Adapter for top preview
public class PhotoPreviewAdapter extends FragmentPagerAdapter {
private static final int DEFAULT_SIDE_PREVIEW_COUNT = 3;
private final int sidePreviewCount;
private final List<PhotoInfo> photoInfos;
public PhotoPreviewAdapter(FragmentManager fm, List<PhotoInfo> photoInfos) {
this(fm, DEFAULT_SIDE_PREVIEW_COUNT, photoInfos);
}
public PhotoPreviewAdapter(FragmentManager fm, int sidePreviewCount, List<PhotoInfo> photoInfos) {
super(fm);
this.sidePreviewCount = sidePreviewCount;
this.photoInfos = photoInfos;
}
public int getSidePreviewCount() {
return sidePreviewCount;
}
#Override
public Fragment getItem(int position) {
if (isDummy(position)) {
return DummyPreviewFragment.newInstance();
} else {
return PhotoPreviewFragment.newInstance(photoInfos.get(getRealPosition(position)));
}
}
private boolean isDummy(int position) {
return position < sidePreviewCount || position > photoInfos.size() - 1 + sidePreviewCount;
}
private int getRealPosition(int position) {
return position - sidePreviewCount;
}
#Override
public int getCount() {
return photoInfos.size() + (sidePreviewCount * 2);
}
#Override
public float getPageWidth(int position) {
return 1.0f / getElementsPerPage();
}
private int getElementsPerPage() {
return (sidePreviewCount * 2) + 1;
}
}
Adapter for central view is simple
public class PhotoViewAdapter extends FragmentPagerAdapter {
private final List<PhotoInfo> photoInfos;
public PhotoViewAdapter(FragmentManager fm, List<PhotoInfo> photoInfos) {
super(fm);
this.photoInfos = photoInfos;
}
#Override
public Fragment getItem(int position) {
return PhotoViewFragment.newInstance(photoInfos.get(position));
}
#Override
public int getCount() {
return photoInfos.size();
}
}
And one of the main is sync listener
public class OnSyncPageChangeListener implements ViewPager.OnPageChangeListener {
private int scrollState = ViewPager.SCROLL_STATE_IDLE;
private final ViewPager syncToViewPager;
private final ViewPager syncWithViewPager;
public OnSyncPageChangeListener(ViewPager syncToViewPager, ViewPager syncWithViewPager) {
this.syncToViewPager = syncToViewPager;
this.syncWithViewPager = syncWithViewPager;
}
#Override
public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
if (scrollState != ViewPager.SCROLL_STATE_IDLE) {
final float ratio = calculateRatioForPosition(position);
final float scrollX = syncWithViewPager.getScrollX();
final float scrollY = syncWithViewPager.getScrollY();
syncToViewPager.scrollTo((int) (scrollX * ratio), (int) scrollY);
}
}
private float calculateRatioForPosition(int position) {
final float syncToViewPagerWidth = syncToViewPager.getWidth();
final float syncWithViewPagerWidth = syncWithViewPager.getWidth();
final float syncToViewPagerElementWeight = syncToViewPager.getAdapter().getPageWidth(position);
final float syncWithViewPagerElementWeight = syncWithViewPager.getAdapter().getPageWidth(position);
final float syncToViewPagerElementsCount = (1.0f / syncToViewPagerElementWeight);
final float syncWithViewPagerElementsCount = (1.0f / syncWithViewPagerElementWeight);
final float syncToViewPagerElementWidth = syncToViewPagerWidth / syncToViewPagerElementsCount;
final float syncWithViewPagerElementWidth = syncWithViewPagerWidth / syncWithViewPagerElementsCount;
return syncToViewPagerElementWidth / syncWithViewPagerElementWidth;
}
#Override
public void onPageSelected(final int position) {
}
#Override
public void onPageScrollStateChanged(final int state) {
scrollState = state;
if (state == ViewPager.SCROLL_STATE_IDLE) {
syncToViewPager.setCurrentItem(syncWithViewPager.getCurrentItem(), false);
}
}
}
And finally init ViewPager's
#Bind(R.id.photoPreviewPager)
ViewPager photoPreviewPager;
#Bind(R.id.photoViewPager)
ViewPager photoViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
final List<PhotoInfo> photoInfos = PhotoInfosProvider.generate();
final PhotoPreviewAdapter photoPreviewAdapter = new PhotoPreviewAdapter(getSupportFragmentManager(), photoInfos);
final PhotoViewAdapter photoViewAdapter = new PhotoViewAdapter(getSupportFragmentManager(), photoInfos);
photoPreviewPager.setAdapter(photoPreviewAdapter);
photoPreviewPager.addOnPageChangeListener(new OnSyncPageChangeListener(photoViewPager, photoPreviewPager));
photoViewPager.setAdapter(photoViewAdapter);
photoViewPager.setOffscreenPageLimit(photoPreviewAdapter.getSidePreviewCount() * 2 + 1);
photoViewPager.addOnPageChangeListener(new OnSyncPageChangeListener(photoPreviewPager, photoViewPager));
}
More detailed code is in repo
The LinearLayoutManager have a scrollToPositionWithOffset method that takes both the position and also the offset of the start of the item from the start of the RecyclerView, which seems like it would accomplish what you need.
You can use this image slider(https://github.com/jjhesk/LoyalNativeSlider) instead of the ViewPager .
First of all, you can use this google official example to create visual effect of pulling this view to center. You'll have ImageView over ViewPager for displaying animated appearing. When animation will be finished, make make your ImageView Gone and show requested image in ViewPager.
I am using ViewPager (support library). I want to know every time the ViewPager change the visible page, it is scrolling left or right.
Please give me a solution. Any recommend is welcome also.
Thanks
set setOnPageChangeListener to your ViewPager
keep a variable global as
private int lastPosition = 0;
and in
#Override
public void onPageSelected(int arg0) {
if (lastPosition > position) {
System.out.println("Left");
}else if (lastPosition < position) {
System.out.println("Right");
}
lastPosition = position;
}
It's not a perfect solution but here's a way to check the swipe direction when you start swiping:
new ViewPager.OnPageChangeListener() {
private static final float thresholdOffset = 0.5f;
private boolean scrollStarted, checkDirection;
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (checkDirection) {
if (thresholdOffset > positionOffset) {
Log.i(C.TAG, "going left");
} else {
Log.i(C.TAG, "going right");
}
checkDirection = false;
}
}
#Override
public void onPageSelected(int position) {}
#Override
public void onPageScrollStateChanged(int state) {
if (!scrollStarted && state == ViewPager.SCROLL_STATE_DRAGGING) {
scrollStarted = true;
checkDirection = true;
} else {
scrollStarted = false;
}
}
});
EDIT: there's a more elegant approach that involves using a ViewPager.PageTransformer and checking it's position intervals:
...
myViewPager.setPageTransformer(true, new PageTransformer());
...
public class PageTransformer implements ViewPager.PageTransformer {
public void transformPage(View view, float position) {
if (position < -1) {
// [-00,-1): the page is way off-screen to the left.
} else if (position <= 1) {
// [-1,1]: the page is "centered"
} else {
// (1,+00]: the page is way off-screen to the right.
}
}
}
You can learn more from: Using ViewPager for Screen Slides
This is my simple solution in the onPageScrolled() method of ViewPager.OnPageChangeListener:
Same solution as GuilhE with a minor fix to avoid getting false positives when paging left (swiping right) on the first page(no more pages to the left) in the ViewPager.
It simply does an additional check to see if the swipe has actually moved at all.
new ViewPager.OnPageChangeListener() {
private static final float thresholdOffset = 0.5f;
private static final int thresholdOffsetPixels = 1;
private boolean scrollStarted, checkDirection;
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (checkDirection) {
if (thresholdOffset > positionOffset && positionOffsetPixels > thresholdOffsetPixels) {
Log.i(C.TAG, "going left");
} else {
Log.i(C.TAG, "going right");
}
checkDirection = false;
}
}
#Override
public void onPageSelected(int position) {}
#Override
public void onPageScrollStateChanged(int state) {
if (!scrollStarted && state == ViewPager.SCROLL_STATE_DRAGGING) {
scrollStarted = true;
checkDirection = true;
} else {
scrollStarted = false;
}
}
});
You can keep class member variable to save last visited page
private int mLastVisitedPageIndex = 0;
Then use following function to check direction
#Override
public void onPageSelected(int i) {
boolean isMovingForward = mLastVisitedPageIndex < i?true:false;
//Use isMovingForward variable anywhere now
mLastVisitedPageIndex = i;
}
use that
#Override
public void onPageSelected( int position )
{
mCurrentFragmentPosition = position;
}
#Override
public void onPageScrolled( int position, float positionOffset, int positionOffsetPixels )
{
boolean isGoingToRightPage = position == mCurrentFragmentPosition;
if(isGoingToRightPage)
{
// user is going to the right page
}
else
{
// user is going to the left page
}
}
Use the ViewPager.OnPageChangeListener interface. You can use the position argument passed to onPageSelected and compare it to the previous value to figure out which way the ViewPager was scrolled.
private float sumPositionAndPositionOffset;
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
boolean isSwipeToLeft = position + positionOffset > sumPositionAndPositionOffset;
sumPositionAndPositionOffset = position + positionOffset;
}
I solved the issue with this implementation. Hope it helps.
public static final float EPSILON= 0.001f;
#Override
public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
// initial position (positionOffset == 0)
if (positionOffset < EPSILON) {
mIsRight = positionOffset < 0.5;
return;
}
// code here
if (mIsRight) {
} else {
}
}
We can also do this using a Custom Viewpager, which can contain swipeLeft() and swipeRight() methods and its onTouchEvent(MotionEvent event) method can contain ACTION_MOVE and ACTION_CANCEL case.
// This can be the code if helpful.
public class SwiperViewPager extends ViewPager {
SwiperListener mSwiperListener;
private float downX;
private float downY;
private boolean isTouchCaptured;
private float upX1;
private float upY1;
private float upX2;
private float upY2;
public SwiperViewPager(Context context) {
super(context);
}
public SwiperViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
private float x1, x2;
static final int min_distance = 20;
boolean eventSent = false;
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE: {
downX = event.getX();
downY = event.getY();
if (!isTouchCaptured) {
upX1 = event.getX();
upY1 = event.getY();
isTouchCaptured = true;
} else {
upX2 = event.getX();
upY2 = event.getY();
float deltaX = upX1 - upX2;
float deltaY = upY1 - upY2;
//HORIZONTAL SCROLL
if (Math.abs(deltaX) > Math.abs(deltaY)) {
if (Math.abs(deltaX) > min_distance) {
// left or right
if (deltaX < 0) {
if(!eventSent && mSwiperListener!=null){
mSwiperListener.onLeftSwipe();
eventSent = true;
}
}
if (deltaX > 0) {
if(!eventSent && mSwiperListener!=null){
if(mSwiperListener.onRightSwipe()){
eventSent = true;
return false;
}
}
}
} else {
//not long enough swipe...
}
}
//VERTICAL SCROLL
else {
if (Math.abs(deltaY) > min_distance) {
// top or down
if (deltaY < 0) {
}
if (deltaY > 0) {
}
} else {
//not long enough swipe...
}
}
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:{
isTouchCaptured = false;
eventSent = false;
}
}
return super.onTouchEvent(event);
}
public void setmSwiperListener(SwiperListener mSwiperListener) {
this.mSwiperListener = mSwiperListener;
}
public static interface SwiperListener {
public boolean onLeftSwipe();
public boolean onRightSwipe();
}
}
Apologies - had to edit the answer as I found a bug.
Here is improved solution:
The solution compares current page index with one previously selected (previousPageIndex)
newPageIndex represents the page which is about to be scrolled to.
Condition (positionOffset == 0) compares if the scroll finished
private int previousPageIndex = 0;
private int newPageIndex = -1;
private final int MOVE_DIRECTION_NONE = 0;
private final int MOVE_DIRECTION_LEFT = 1;
private final int MOVE_DIRECTION_RIGHT = 2;
private int moveDirection = MOVE_DIRECTION_NONE;
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels);
if (moveDirection == MOVE_DIRECTION_NONE) {
if (previousPageIndex == position){
moveDirection = MOVE_DIRECTION_LEFT;
if (newPageIndex == -1) newPageIndex = previousPageIndex + 1;
} else {
moveDirection = MOVE_DIRECTION_RIGHT;
if (newPageIndex == -1) newPageIndex = previousPageIndex - 1;
}
}
if (positionOffset == 0) {
System.out.println("Reseting");
previousPageIndex = position;
moveDirection = MOVE_DIRECTION_NONE;
newPageIndex = -1;
}
switch (moveDirection) {
case MOVE_DIRECTION_LEFT:
if (onPageChangingHandler != null) onPageChangingHandler.pageChanging(previousPageIndex, newPageIndex, positionOffset);
System.out.println("Sliding Left | Previous index: " + previousPageIndex + " | New Index: " + newPageIndex + " | offset: " + positionOffset + " | Position: " + position);
break;
case MOVE_DIRECTION_RIGHT:
if (onPageChangingHandler != null) onPageChangingHandler.pageChanging(newPageIndex, previousPageIndex, positionOffset);
System.out.println("Sliding Right | Previous index: " + previousPageIndex + " | New Index: " + newPageIndex + " | offset: " + positionOffset + " | Position: " + position);
break;
case MOVE_DIRECTION_NONE:
System.out.println("Moving NONE");
break;
}
}
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
private int mCurrentSelectedScreen;
private int mNextSelectedScreen;
private static final float thresholdOffset = 0.5f;
private boolean scrollStarted=true, checkDirection=false;
ArrayList<Integer> comp_ary=new ArrayList<Integer>();
#Override
public void onPageSelected(int arg0) {
}
#Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
//Log.e("positionOffsetPixels : "+positionOffsetPixels, "positionOffset : "+positionOffset);
comp_ary.add(positionOffsetPixels);
if (checkDirection) {
if (comp_ary.get(2) < comp_ary.get(comp_ary.size()-1)) {
Log.e("going left", "going left");
} else
if (comp_ary.get(2) > comp_ary.get(comp_ary.size()-1))
{
Log.e("going right", "going right");
}
checkDirection = false;
comp_ary=new ArrayList<Integer>();
}
}
#Override
public void onPageScrollStateChanged(int arg0) {
if (!scrollStarted && arg0 == ViewPager.SCROLL_STATE_SETTLING) {
scrollStarted = true;
checkDirection = true;
} else {
scrollStarted = false;
}
}
});
dab on this if your worried about position offset suddenly changing to 0 after taking a value > 0.9F
private boolean LEFT_DAB; //left swipe
private float offset; //current position offset
private float take_off; //previous position offset
private static final float quavo = 0.5F; //position offset threshold
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels);
offset = take_off > 0.9F ? take_off : positionOffset;
take_off = positionOffset;
if (offset > quavo) {
LEFT_DAB = false;//RIGHT_SWIPE
} else {
LEFT_DAB = true;//LEFT_SWIPE
}
}
Here's a way you can know the scroll direction while it's happening. All you have to do is set an OnPageChangeCallback() on the ViewPager. You save the current page of the ViewPager in OnPageSelected() and compare it to the position parameter of OnPageScrolled(). If the current page is less than or equal to the position, you are scrolling to the right, if not, you are scrolling to the left.
var currentPage = 0
viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
currentPage = position
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels)
if (currentPage <= position) {
// We are scrolling right
} else {
// We are scrolling left
}
}
})
pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if(position == pager.getCurrentItem()){
// Move Right
}
else{
// Move Left
}
}
I am using PagerAdapter for horizontal swiping for showing newspaper pages in my app.
Currently I want to implement the circular scrolling in this app.Right now what I have done is whenever I am getting on last page I try to set the currentItem to first pagei.e that functionality working for last page to first page,but the problem is that how can I go to last page from first page.
Here I am pasting my code related to pagerAdapter & onPageChangeListener:-
awesomeAdapter = new AwesomePagerAdapter(awesomePager);
awesomePager.setAdapter(awesomeAdapter);
awesomePager.setPageMargin(10);
awesomePager.setOnPageChangeListener(new OnPageChangeListener() {
int lastPosition;
float posOffset = 0;
#Override
public void onPageSelected(int position) {
viewerPage = position;
CommonLogic.logMessage("Viewer Page:- "+ viewerPage, TAG, Log.VERBOSE);
posOffset = 0;
}
#Override
public void onPageScrolled(int position,float positionOffset,int positionOffsetPixels) {
if (positionOffset == 0 && positionOffsetPixels == 0 && position != 0) {
lastPosition = position;
}
posOffset -= positionOffset;
CommonLogic.logMessage(" Position:- "
+ position + " Position Offset:- " + positionOffset
+ " Position Offset Variable:- "
+ posOffset
+ " Position Offset Pixels:- "
+ positionOffsetPixels
+ " Last Position " + lastPosition,
TAG, Log.VERBOSE);
CommonLogic.logMessage(" Last Position "
+ lastPosition, TAG, Log.VERBOSE);
}
#Override
public void onPageScrollStateChanged(int state) {
// To Detect the Last Page & This Sets it to first page.This working fine.
if (state == ViewPager.SCROLL_STATE_DRAGGING && viewerPage == (uris.size() - 1)) {
CommonLogic.logMessage("Scroll State Changed ", TAG,Log.VERBOSE);
postDelayed(new Runnable() {
#Override
public void run() {
awesomePager.setCurrentItem(0, true);
}
}, 200);
}
// I have also used this to detect whether the user is on first & try to move on last page,but it is not working well.
else if (state == ViewPager.SCROLL_STATE_DRAGGING && (lastPosition == 0 || lastPosition == (uris.size() - 1)) && viewerPage == 0 && posOffset <= 0) {
CommonLogic.logMessage( "Scroll State Changed ", TAG,Log.VERBOSE);
postDelayed(new Runnable() {
#Override
public void run() {
awesomePager.setCurrentItem((uris.size() - 1), true);
}
}, 200);
}
}
}
});
Also the PagerAdapter i.e AwesomweAdapter in my case,is also as folllows:-
private class AwesomePagerAdapter extends PagerAdapter {
ViewPager pdfContainer;
DocumentNewView documentNewView;
CustomViewPager customViewPager;
public AwesomePagerAdapter(CustomViewPager awesomePager) {
this.customViewPager = awesomePager;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public int getCount() {
return uris.size();
}
public DocumentNewView addViewAt(int position, DocumentNewView mainView) {
CommonLogic.logMessage("Position of View:- " + position, TAG,
Log.VERBOSE);
pdfContainer.addView(mainView);
return mainView;
}
/**
* Create the page for the given position. The adapter is responsible
* for adding the view to the container given here, although it only
* must ensure this is done by the time it returns from
* {#link #finishUpdate()}.
*
* #param container
* The containing View in which the page will be shown.
* #param position
* The page position to be instantiated.
* #return Returns an Object representing the new page. This does not
* need to be a View, but can be some other container of the
* page.
*/
#Override
public Object instantiateItem(View collection, int position) {
CommonLogic
.logMessage("Instantiate Item Called ", TAG, Log.VERBOSE);
documentNewView = new DocumentNewView(cxt, display, customViewPager);
documentNewView.setPdfContext(new PdfContext());
CodecDocument codecDocument = documentNewView.open(uris
.get(position));
documentNewView.renderDocument(codecDocument);
documentNewView.setMaxZoom(4f);
documentNewView.setVerticalScrollBarEnabled(true);
codecDocument = null;
this.pdfContainer = (ViewPager) collection;
return addViewAt(position, documentNewView);
}
/**
* Remove a page for the given position. The adapter is responsible for
* removing the view from its container, although it only must ensure
* this is done by the time it returns from {#link #finishUpdate()}.
*
* #param container
* The containing View from which the page will be removed.
* #param position
* The page position to be removed.
* #param object
* The same object that was returned by
* {#link #instantiateItem(View, int)}.
*/
#Override
public void destroyItem(View collection, int position, Object view) {
pdfContainer.removeView((DocumentNewView) view);
}
/**
* Called when the a change in the shown pages has been completed. At
* this point you must ensure that all of the pages have actually been
* added or removed from the container as appropriate.
*
* #param container
* The containing View which is displaying this adapter's
* page views.
*/
#Override
public void finishUpdate(View arg0) {
CommonLogic.logMessage("Finish Update Called ", TAG, Log.VERBOSE);
}
#Override
public void restoreState(Parcelable arg0, ClassLoader arg1) {
}
#Override
public Parcelable saveState() {
return null;
}
#Override
public void startUpdate(View arg0) {
CommonLogic.logMessage("State Update Called ", TAG, Log.VERBOSE);
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == ((DocumentNewView) object);
}
Please give me any suggestions/changes in my code (if applicable) for it.
Thanks in Advance.
I could achieve this by overriding onPageSelected method of OnPageChangeListener. Consider you have three pages in this order A<->B<->C. To goal is to reach C if we scroll right from A and similarly to reach A if we scroll left from C.
To do this, define your to have 5 pages (3+2), and organize the pages as follows:
C<->A<->B<->C<->A
Now in the onPageSelected method, check and if position if 0, change it to 3 (getCount()-2) and if position is 4 (getCount()-1), change it to 1. Make sure to use the method:
setCurrentItem(item, smoothScroll)
Here is complete code for CircularPagerAdaptor Class :
package zolender.adapters;
import android.content.Context;
import android.os.Parcelable;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.LayoutInflater;
import android.view.View;
public class CircularPagerAdapter extends PagerAdapter{
private int[] pageIDsArray;
private int count;
public CircularPagerAdapter(final ViewPager pager, int... pageIDs) {
super();
int actualNoOfIDs = pageIDs.length;
count = actualNoOfIDs + 2;
pageIDsArray = new int[count];
for (int i = 0; i < actualNoOfIDs; i++) {
pageIDsArray[i + 1] = pageIDs[i];
}
pageIDsArray[0] = pageIDs[actualNoOfIDs - 1];
pageIDsArray[count - 1] = pageIDs[0];
pager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
int pageCount = getCount();
if (position == 0){
pager.setCurrentItem(pageCount-2,false);
} else if (position == pageCount-1){
pager.setCurrentItem(1,false);
}
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// TODO Auto-generated method stub
}
#Override
public void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub
}
});
}
public int getCount() {
return count;
}
public Object instantiateItem(View container, int position) {
LayoutInflater inflater = (LayoutInflater) container.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
int pageId = pageIDsArray[position];
View view = inflater.inflate(pageId, null);
((ViewPager) container).addView(view, 0);
return view;
}
#Override
public void destroyItem(View container, int position, Object object) {
((ViewPager) container).removeView((View) object);
}
#Override
public void finishUpdate(View container) {
// TODO Auto-generated method stub
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == ((View) object);
}
#Override
public void restoreState(Parcelable state, ClassLoader loader) {
// TODO Auto-generated method stub
}
#Override
public Parcelable saveState() {
// TODO Auto-generated method stub
return null;
}
#Override
public void startUpdate(View container) {
// TODO Auto-generated method stub
}
}
And here is how you can use it:
myPager = (ViewPager) findViewById(R.id.myfivepanelpager);
PagerAdapter adapter = new CircularPagerAdapter(myPager, new int[]{R.layout.farleft, R.layout.left, R.layout.middle, R.layout.right, R.layout.farright});
myPager.setAdapter(adapter);
myPager.setCurrentItem(3);
I also needed a circular ViewPager. This is what I've done. I assume you get pageCount value from somewhere.
...
pager = (ViewPager) findViewById(R.id.pager);
//Gesture detection
final GestureDetector gestureDetector = new GestureDetector(new MyGestureDetector());
pager.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
});
//pagelistener is just for getting selected page
pager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
selectedPage = position;
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
and here is the GestureDetector.
Copied from here
class MyGestureDetector extends SimpleOnGestureListener {
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
int SWIPE_MIN_DISTANCE = Utils.ConvertToPixel(mContext, 50);
int SWIPE_MAX_OFF_PATH = Utils.ConvertToPixel(mContext, 250);
int SWIPE_THRESHOLD_VELOCITY = Utils.ConvertToPixel(mContext, 200);
try {
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
return false;
// right to left swipe
if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY
&& selectedPage == (pageCount - 1)) {
pager.setCurrentItem(0);
return true;
} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY
&& selectedPage == 0) {
pager.setCurrentItem(pageCount - 1);
return true;
}
} catch (Exception e) {
// nothing
}
return false;
}
}
Expanding on Z0lenDer's answer, when using a regular ViewPager where you don't need to free the memory for each associated view, it's more efficient to store the created views rather than the layout IDs. This is necessary if wanting to get rid of any delay and flicker when the item is being switched.
There's also an issue with the animation when using onPageSelected, as it doesn't let the slide finish before doing the switch. The only way I found to avoid this is to only perform the switch once the scroll state has changed to SCROLL_STATE_IDLE and just setting the current item in onPageSelected.
private int currentPage = 0;
...
pager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
currentPage = position;
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub
Log.d(TAG, "onPageScrollStateChanged: " + state);
if (state == ViewPager.SCROLL_STATE_IDLE) {
int pageCount = getCount();
if (currentPage == 0){
pager.setCurrentItem(pageCount-2,false);
} else if (currentPage == pageCount-1){
pager.setCurrentItem(1,false);
}
}
}
});
Try this
((ViewPager) container)
.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
Log.i("TAG", "pos::" + position);
}
#Override
public void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub
int currentPage = pager.getCurrentItem();
Log.i("TAG", "currentPage::" + currentPage);
Log.i("TAG", "currentState::" + currentState);
Log.i("TAG", "previousState::" + previousState);
if (currentPage == 4 || currentPage == 0) {
previousState = currentState;
currentState = state;
if (previousState == 1 && currentState == 0) {
pager.setCurrentItem(currentPage == 0 ? 4 : 0);
}
}
}
#Override
public void onPageScrolled(int arg0, float arg1,
int arg2) {
// TODO Auto-generated method stub
}
});
return
This should be placed inside
#Override
public Object instantiateItem(final View container, int position) {}
I used it this way,
fragment layouts in adapter 0>1>2>3>4>5,
0 & 5 are dummy
viewPager.setAdapter(adapter);
viewPager.setCurrentItem(1, false); //going to page 1;
final int[] pagePosition = new int[1];
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
pagePosition[0] = position;
}
#Override
public void onPageScrollStateChanged(int state) { //state changes from 2 to 0 during a swipe
if (state == 0 && pagePosition[0] == 0){
viewPager.setCurrentItem(4, false);
} else if (state == 0 && pagePosition[0] == 5){
viewPager.setCurrentItem(1, false);
}
}
});
Well this helped
private class CircularViewPagerHandler implements ViewPager.OnPageChangeListener {
private ViewPager mViewPager;
private int mCurrentPosition;
private int mScrollState;
private int mPreviousPosition;
public CircularViewPagerHandler(final ViewPager viewPager) {
mViewPager = viewPager;
}
#Override
public void onPageSelected(final int position) {
mCurrentPosition = position;
mPreviousPosition = position-1;
}
#Override
public void onPageScrollStateChanged(final int state) {
if (state == ViewPager.SCROLL_STATE_IDLE) {
setNextItemIfNeeded();
}
mScrollState = state;
}
private void setNextItemIfNeeded() {
if (!isScrollStateSettling()) {
handleSetNextItem();
}
}
private boolean isScrollStateSettling() {
return mScrollState == ViewPager.SCROLL_STATE_SETTLING; //indicated page is settling to it's final position
}
private void handleSetNextItem() {
final int lastPosition = mViewPager.getAdapter().getCount() - 1;
if (mCurrentPosition == 0) {
mViewPager.setCurrentItem(lastPosition,false);
} else if (mCurrentPosition == lastPosition) {
mViewPager.setCurrentItem(0, false);
}
}
#Override
public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
}
}
It was #tobi_b's answer