android view pager swipe animation - android

I am trying to do some animation in the page swipe in view pager by overriding the transformPage() method, such that when I swipe from right to left the new page (page coming from the right side) should appear below the previous page as soon as the animation starts and then the previous page should slide to the left side over the new page.
When I swipe from left to right the new page should directly slide over the previous page and covers it completely. But I am not able to achieve it.
I have tried the following:-
if(position > 0 && position < 1)
{
int pageWidth = page.getWidth();
float translateValue = (-position * pageWidth);
if(translateValue < pageWidth)
{
translationX = translateValue;
}
else
{
translationX = 0;
}
}
else
{
alpha = 1;
scale = 1;
translationX = 0;
}
Please provide some suggestions. Thanks

This should work like you want, you just have to put it in your PagerTransformer class:
private static final float MIN_SCALE_DEPTH = 0.75f;
#Override
public void transformPage(View page, float position) {
final float alpha;
final float scale;
final float translationX;
if (position > 0 && position < 1) {
alpha = (1 - position);
scale = MIN_SCALE_DEPTH + (1 - MIN_SCALE_DEPTH) * (1 - Math.abs(position));
translationX = (page.getWidth() * -position);
} else {
alpha = 1;
scale = 1;
translationX = 0;
}
page.setAlpha(alpha);
page.setTranslationX(translationX);
page.setScaleX(scale);
page.setScaleY(scale);

Related

Android All directional view pager swipe issue

I am trying to build a component where cards can be swiped in all the direction and can be brought back. Which translates to following:
Left to right: bring back the previous card
Right to left: bring new card underneath
Top to bottom: bring back the previous card
Bottom to top: bring new card underneath
I decided that the best way to move forward will be if I extend Viewpager and combine both vertical and horizontal Viewpager implementation. It will solve all the animation related issues as well as fragment management work.
Eventually, I was able to create what I wanted but it is now stuck at last problem. When the Viewpager is swiped vertically it has the marked zone which behaves fluidly but the dark zone does not swipe correctly(image below). For vertical swipe implementation, I have used the touch coordinate swapping approach and mapped the coordinates. I have tried to look at the mapping for swapping and can't see where am I going wrong.
It will be a great help if someone can point me in the right direction:
Here are the code pieces:
AllDirectionViewPager.java
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
public class AllDirectionViewPager extends ViewPager {
public static String TAG = "AllDirectionViewPager";
private float startX, startY, mHeight, mWidth;
int DIRECTION_LOCKING_THRESHOLD_X=5, DIRECTION_LOCKING_THRESHOLD_Y=5, mDirection=-1;
boolean directionLocked=false;
VDepthPageTransformer mVerticalTransformer;
HDepthPageTransformer mHorizontalTransformer;
public AllDirectionViewPager(Context context) {
super(context);
init();
}
public AllDirectionViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
setOverScrollMode(OVER_SCROLL_NEVER);
mVerticalTransformer = new VDepthPageTransformer();
mHorizontalTransformer = new HDepthPageTransformer();
}
/**
* Swaps the X and Y coordinates of 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;
Log.i(TAG, "swap xy called. init: "+ev.getX()+","+ev.getY()+" final: "+newX+","+newY+" with height: "+height);
ev.setLocation(newX, newY);
return ev;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev){
boolean intercepted = false;
int direction;
direction = getDirection(ev);
Log.i(TAG, "viewpager intercepted: "+mDirection);
if(mDirection==0) {
intercepted = super.onInterceptTouchEvent(swapXY(ev));
swapXY(ev); // return touch coordinates to original reference frame for any child views
} else if (mDirection==1) {
intercepted = super.onInterceptTouchEvent(ev);
}
return intercepted;
}
//1: Left-Right; 0: UP-DOWN; -1: continuing
int getDirection(MotionEvent ev) {
float dirX=0, dirY=0;
boolean continuing = false;
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = ev.getX();
startY = ev.getY();
mDirection = -1;
directionLocked = false;
Log.d(TAG, "swipe start");
break;
case MotionEvent.ACTION_MOVE:
float endX = ev.getX();
float endY = ev.getY();
Log.d(TAG, "direction locked: "+directionLocked+" diffY: "+(endY - startY)+ " diffX: "+(endX - startX));
if (!directionLocked && ((Math.abs(endX - startX)>DIRECTION_LOCKING_THRESHOLD_X)||(Math.abs(endY - startY) > DIRECTION_LOCKING_THRESHOLD_Y))) {
dirX = (endX - startX) / getHeight();
dirY = (endY - startY) / getWidth();
directionLocked = true;
if (Math.abs(dirX) < Math.abs(dirY)) {
mDirection = 0;
this.setPageTransformer(true, mVerticalTransformer);
Log.d(TAG, "Vertical set");
}
else if (Math.abs(dirX) > Math.abs(dirY)) {
mDirection = 1;
this.setPageTransformer(true, mHorizontalTransformer);
Log.d(TAG, "Horizontal set");
}
else {
mDirection = -1;
directionLocked = false;
Log.d(TAG, "nothing found");
}
}
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "swipe done");
directionLocked = false;
break;
default:
continuing = true;
}
if(continuing)
return -1;
return -1;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
int direction = getDirection(ev);
Log.i(TAG, "viewpager touch: "+mDirection);
Log.i(TAG, "Touch coords: "+ev.getX()+","+ev.getY());
if(mDirection==0) {
return super.onTouchEvent(swapXY(ev));
}else/* if(mDirection==1) */{
return super.onTouchEvent(ev);
}
// return false;
}
}
HDepthPageTransformer.java
import android.support.v4.view.ViewPager;
import android.view.View;
public class HDepthPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.85f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 0) { // [-1,0]
// Use the default slide transition when moving to the left page
view.setAlpha(1);
view.setTranslationX(0);
view.setScaleX(1);
view.setScaleY(1);
} else if (position <= 1) { // (0,1]
// Fade the page out.
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(pageWidth * -position);
// Scale the page down (between MIN_SCALE and 1)
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
VDepthPageTransformer.java
import android.support.v4.view.ViewPager;
import android.view.View;
public class VDepthPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.85f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 0) { // [-1,0]
// Use the default slide transition when moving to the top page
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);
view.setScaleX(1);
view.setScaleY(1);
} else if (position <= 1) { // (0,1]
// Fade the page out.
view.setAlpha(1 - position);
// Counteract the default slide transition
view.setTranslationX(pageWidth * -position);
// Scale the page down (between MIN_SCALE and 1)
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
Image not to scale to show problem area (Sorry for bad artwork):
The depth page transformers are sourced from the android developers website.
Used some part from here for vertical scrolling: Android: Vertical ViewPager
As no one was answering this, I dived into the android source code of viewpager and realized that although the observation is bizarre, the reason is incorrect initialization.
Because onInterceptTouchEvent is fired before any drag actually occurs(ie before onTouchEvent). It was important to initialize the process correctly before lending control to onTouchEvent. That is all one needs to do in the above code. Hopefully, soon I'll post a library for the same over here :) but if someone needs it before that, just leave a comment.

ViewPager became show incorrect pages after update of the support libraries

I updated the Google support libraries to rev. 23.2.0. And ViewPager became show wrong page views.
ViewPager uses a custom page transformer:
private class ZoomOutPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.85f;
private float mCenterOffset;
private boolean mIsFixedCenterOffset = false;
public void transformPage(View view, float position) {
final int pageWidth = view.getWidth();
final int pageHeight = view.getHeight();
if(!mIsFixedCenterOffset) {
mCenterOffset = position;
mIsFixedCenterOffset = true;
}
position -= mCenterOffset;
if (position <= 1) {
final float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
final float vertMargin = pageHeight * (1 - scaleFactor) / 2;
final float horzMargin = pageWidth * (1 - scaleFactor) / 2;
if (position < 0) {
view.setTranslationX(horzMargin - vertMargin / 2);
} else {
view.setTranslationX(-horzMargin + vertMargin / 2);
}
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
}
}
}
And has page margin:
ViewPager viewPager = (ViewPager) v.findViewById(R.id.vpDaySlider);
mAdapter = new DayPagerAdapter(getActivity(), fm, mWeekNumber);
viewPager.setAdapter(mAdapter);
viewPager.addOnPageChangeListener(this);
viewPager.setPageTransformer(false, new ZoomOutPageTransformer());
Point display = SettingsManager.getDisplaySize(getContext());
final int padding = (int)(display.x * 0.1);
viewPager.setPageMargin(padding);
Now, it looks like below:
I even don't know where bug is... How to fix it? I need to page fills parent space and scales down only on scrolling.
Warning in LogCat:
W/FragmentManager: moveToState: Fragment state for DayFragment{24ec179 #2 id=0x7f0c00b4} not updated inline; expected state 3 found 2
ADDED
I realized what a bug. ZoomOutPageTransformer fixes the first position of page. And it must be 0 or nearly at zero but after update the first value of position > 1 (for example 1.1 on my phone) but the next (second) value is real page position (for my phone: 0).
Because of what is happening? I think it's a wrong behaviour of ViewPager.
I fixed this bug so:
private static class ZoomOutPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.85f;
private ViewPager mViewPager;
private float mPositionFixer;
private boolean isSetFixer = false;
public ZoomOutPageTransformer(ViewPager viewPager) {
mViewPager = viewPager;
}
public void transformPage(View view, float position) {
final int pageWidth = view.getWidth();
final int pageHeight = view.getHeight();
if(!isSetFixer) {
final int mClientWidth = mViewPager.getMeasuredWidth() -
mViewPager.getPaddingLeft() - mViewPager.getPaddingRight();
mPositionFixer = ((float)mViewPager.getPaddingStart()) / mClientWidth;
isSetFixer = true;
}
position -= mPositionFixer;
if (position <= 1) {
final float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
final float vertMargin = pageHeight * (1 - scaleFactor) / 2;
final float horzMargin = pageWidth * (1 - scaleFactor) / 2;
if (position < 0) {
view.setTranslationX(horzMargin - vertMargin / 2);
} else {
view.setTranslationX(-horzMargin + vertMargin / 2);
}
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
}
}
}
Although I cannot understand this bug in Support libraries rev. 23.2.0.

DepthPageTransformer from both side same effect?

The code for dept page transformation animation appears when slide to left, to achieve the similar effect when sliding to right I did work around but have no success.
Depth Page Tranfomer
I want the same effect when I back to previous image that is the coming image must zoom out and current image slide to right. Any solution or fix for this?
This code solves the problem, but is written in C#,i use Xamarin.Android, but it should be easy to translate to java, because it is translated from Java.
It is a class derived from RecyclerView.ViewHolder because in my code I use a RecyclerView to display multiple ViewPager.
I implement the interfaces
ViewPager.IPageTransformer
ViewPager.IOnPageChangeListener
In Java are
ViewPager.PageTransformer
ViewPager.OnPageChangeListener
In the same class to know if this dragging to the right or to the left.
And the transformation change in the direction
public class PhotoPaisViewHolder : RecyclerView.ViewHolder,
ViewPager.IPageTransformer,
ViewPager.IOnPageChangeListener
{
private static AtomicInteger sNextGeneratedId = new AtomicInteger(1);
/**
* Generate a value suitable for use in {#link #setId(int)}.
* This value will not collide with ID values generated at build time by aapt for R.id.
*
* #return a generated ID value
*/
public static int GenerateViewId()
{
for (;;)
{
int result = sNextGeneratedId.Get();
// aapt-generated IDs have the high byte nonzero; clamp to the range under that.
int newValue = result + 1;
if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
if (sNextGeneratedId.CompareAndSet(result, newValue))
{
return result;
}
}
}
public ViewPager Pager { get; private set; }
// Get references to the views defined in the CardView layout.
public PhotoPaisViewHolder(View itemView)
: base(itemView)
{
// This for support multiple pagers in the same RecyclerView
Pager = itemView.FindViewById<ViewPager>(Resource.Id.pager);
if (Build.VERSION.SdkInt < BuildVersionCodes.JellyBeanMr1)
{
Pager.Id = PhotoPaisViewHolder.GenerateViewId();
}
else
{
Pager.Id = View.GenerateViewId();
}
Pager.AddOnPageChangeListener(this);
Pager.SetPageTransformer(reverse, this);
}
//For control the transformation
private static float MIN_SCALE = 0.75f;
private int currentPos;
private bool reverse;
private bool dragging;
public void TransformPage(View view, float position)
{
// Console.WriteLine(position);
int pageWidth = view.Width;
if (position < -1)
{ // [-Infinity,-1)
// This page is way off-screen to the left.
view.Alpha = 0;
}
else if (position <= 0)
{ // [-1,0]
// Use the default slide transition when moving to the left page
if (reverse)
{
TransformUpView(view);
}
else
{
TransformDownView(view, position, pageWidth);
}
}
else if (position <= 1)
{ // (0,1]
// Fade the page out.
if (reverse)
{
TransformDownView(view, position, pageWidth);
}
else
{
TransformUpView(view);
}
}
else
{ // (1,+Infinity]
// This page is way off-screen to the right.
view.Alpha = 0;
}
}
private static void TransformDownView(View view, float position, int pageWidth)
{
view.Alpha = 1 - Math.Abs(position);
// Counteract the default slide transition
view.TranslationX = pageWidth * -position;
// Scale the page down (between MIN_SCALE and 1)
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.Abs(position));
view.ScaleX = scaleFactor;
view.ScaleY = scaleFactor;
}
private static void TransformUpView(View view)
{
view.Alpha = 1;
view.TranslationX = 0;
view.ScaleX = 1;
view.ScaleY = 1;
}
public void OnPageScrollStateChanged(int state)
{
dragging = state == ViewPager.ScrollStateDragging;
}
public void OnPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{
if (dragging)
{
if (position < currentPos)
{
if (reverse)
{
reverse = !reverse;
Pager.SetPageTransformer(reverse, this);
}
}
else
{
if (!reverse)
{
reverse = !reverse;
Pager.SetPageTransformer(reverse, this);
}
}
}
}
public void OnPageSelected(int position)
{
currentPos = position;
}
}

How to remove fading animation in vertical ViewPager in Android

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"

How to set the point, after which the ViewPager swipes to another View?

If more than 50% of the follower of View B is visible,
on release the ViewPager will animate to the View B instead of goind back to View A.
How can I change this point of switching from 50% to x%?
You can do this by overriding the onScrollChanged() function, here's an example:
#Override
public void onScrollChanged(ViewPager vp, int x, int y, int oldx, int oldy) {
// We take the last son in the ViewPager
View view = (View) vp.getChildAt(vp.getChildCount() - 1);
if (diff < view.getBottom()/2) {
// do the animation
}
}
Let me know if that worked or not (in order for me to know if I should remove the Answer from here).
Thanks
You can build your own customized ViewPager and override the proper method with your own float-value. something like :
public CustomViewpager extends ViewPager {
#Override
private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) {
int targetPage;
if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) {
targetPage = velocity > 0 ? currentPage : currentPage + 1;
} else {
//change your values here for whatever you need for your purposes
final float truncator = currentPage >= mCurItem ? 0.4f : 0.6f;
targetPage = (int) (currentPage + pageOffset + truncator);
}
if (mItems.size() > 0) {
final ItemInfo firstItem = mItems.get(0);
final ItemInfo lastItem = mItems.get(mItems.size() - 1);
// Only let the user target pages we have items for
targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position));
}
return targetPage;
}
}

Categories

Resources