I am very new to Android Development and for a project of mine I want to be able to have multiple animations for a fragment. The ones I want is to be able to swipe left and right and zoom in and out for each fragment. An example would be to have an Image in each fragment, and I could zoom in and out and swipe to the next image. I have seen examples online where this is achieved using a grid view. Is there any example or resources online where I can do this?
In my example I have here is that I used Viewpager 2 for the swipe animation then I attempted to implement a zoom-in feature but when I ran it overwrites the viewpager and I am unable to swipe pages only zoom in and out of that image. Can I somehow add the zoom feature in the PageTransformer class? I know this is probably a very poor way of going about it.
I know probably that in the in the PageTransformer class I need to add the zoom in and out animation how would I do that?
package com.example.viewpager;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import com.github.chrisbanes.photoview.PhotoView;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
viewPager.setPageTransformer(true, new DepthPageTransformer());
viewPager.setAdapter(new MyPagerAdapter(this));
PhotoView photoView = (PhotoView) findViewById(R.id.photo_view);
photoView.setImageResource(R.drawable.a_child_of_the_king);
photoView.setImageResource(R.drawable.a_mighty_fortress);
photoView.setImageResource(R.drawable.a_quiet_place);
photoView.setImageResource(R.drawable.all_the_way);
}
//PageTranformer class
package com.example.viewpager;
import android.support.v4.view.ViewPager;
import android.view.View;
import com.github.chrisbanes.photoview.PhotoView;
//import androidx.viewpager.widget.ViewPager;
public class DepthPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.75f;
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(0f);
} else if (position <= 0) { // [-1,0]
// Use the default slide transition when moving to the left page
view.setAlpha(1f);
view.setTranslationX(0f);
view.setScaleX(1f);
view.setScaleY(1f);
} 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(0f);
}
}
}
Swiping with Viewpager makes sense in a way.
Do you load all the images into the same Layout?
Are you inflating a Fragment and inflate the single Layout onto it and then load the image into the displayed ImageView?
If so, for zooming in and out you might have to modify this approach to register touches correctly:
private ScaleGestureDetector scaleGestureDetector;
private float mScaleFactor = 1.0f;
private ImageView imageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView=findViewById(R.id.imageView);
scaleGestureDetector = new ScaleGestureDetector(this, new ScaleListener());
}
#Override
public boolean onTouchEvent(MotionEvent motionEvent) {
scaleGestureDetector.onTouchEvent(motionEvent);
return true;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
mScaleFactor *= scaleGestureDetector.getScaleFactor();
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));
imageView.setScaleX(mScaleFactor);
imageView.setScaleY(mScaleFactor);
return true;
}
}
Happy Coding :)
Thanks, I am loading the images into the same layout. This is done in a separate class. see code below. Now The code that you provided am I able to just implement that to the Main Activity class? Would I be able to call:
viewPager.setPageTransformer(true, new DepthPageTransformer());
viewPager.setAdapter(new MyPagerAdapter(this)); as well as scaleGestureDetector function?
public class MyPagerAdapter extends PagerAdapter {
private Context mContext;
private int[] images = {
R.drawable.a_child_of_the_king,
R.drawable.a_mighty_fortress,
R.drawable.a_quiet_place,
R.drawable.all_the_way,
R.drawable.because_he_lives,
R.drawable.before_jehovahs_awful_throne,
R.drawable.before_jehovahs_awful_throne2,
R.drawable.beneath_the_cross_of_jesus
};
public MyPagerAdapter(Context context) {
mContext = context;
}
#Override
public Object instantiateItem(ViewGroup collection, int position) {
LayoutInflater inflater = LayoutInflater.from(mContext);
ViewGroup viewGroup = (ViewGroup) inflater.inflate(R.layout.imagelayout,
collection, false);
ImageView imageView = (ImageView)viewGroup.findViewById(R.id.imageView);
imageView.setImageResource(images[position]);
collection.addView(viewGroup);
return viewGroup;
}
#Override
public void destroyItem(ViewGroup collection, int position, Object view) {
((ViewGroup) collection).removeView((View) view);
}
#Override
public int getCount() {
return images.length;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
#Override
public CharSequence getPageTitle(int position) {
ModelObject customPagerEnum = ModelObject.values()[position];
return mContext.getString(customPagerEnum.getTitleResId());
}
Related
in my main activity i have a horizontal viewpager. Inside one of the fragment of the viewpager i have another vertical viewpager. Both works fine. But for the horizontal viewpager, i need to scroll from the edge of the screens. But i want it to be scrolled from anywhere in the screen.
my horizontal viewpager setup:
viewPager = (ViewPager) findViewById(R.id.viewpager);
adapterViewPager = new HorizontalViewPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapterViewPager);
viewPager.setCurrentItem(1);
horizontal viewpager adapter:
public class HorizontalViewPagerAdapter extends FragmentPagerAdapter {
private static int NUM_ITEMS = 3;
public HorizontalViewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return MoreFragment.newInstance("Fragment MoreFragment", "HA HA HA");
case 1:
return NewsFragment.newInstance("Fragment 1", "HA HA HA");
case 2:
return WebViewFragment.newInstance("Fragment Webview", "HA HA HA");
default:
return null;
}
}
#Override
public int getCount() {
return NUM_ITEMS;
}
#Override
public CharSequence getPageTitle(int position) {
return "Tab " + position;
}
}
in my news fragment i have another viewpager.
viewPager = view.findViewById(R.id.shortpager);
adapterViewPager = new VerticalPagerAdapter(getActivity().getSupportFragmentManager(), newsList);
viewPager.setAdapter(adapterViewPager);
My vertical viewpager class:
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() {
// The majority of the magic happens here
setPageTransformer(true, new VerticalPageTransformer());
// The easiest way to get rid of the overscroll drawing that happens on the left and right
setOverScrollMode(OVER_SCROLL_NEVER);
}
/**
* 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));
}
private class VerticalPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.75f;
#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 <= 0) { // [-1,0]
// Use the default slide transition when moving to the left/top page
view.setAlpha(1);
ViewCompat.setElevation(view, 1);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
view.setTranslationY(0);
//set Y position to swipe in from top
float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} else if (position <= 1) { // [0,1]
view.setAlpha(1);
ViewCompat.setElevation(view, 2);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
view.setTranslationY(position * view.getHeight());
// Scale the page down (between MIN_SCALE and 1)
view.setScaleX(1);
view.setScaleY(1);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
}
vertical viewpager adapter:
public class VerticalPagerAdapter extends FragmentPagerAdapter {
private static int NUM_ITEMS = 3;
private final ArrayList<News> newsList;
public VerticalPagerAdapter(FragmentManager fm, ArrayList<News> newsList) {
super(fm);
this.newsList = newsList;
}
#Override
public Fragment getItem(int position) {
return ShortFragment.newInstance("Fragment 1", "HA HA HA", newsList.get(position));
}
#Override
public int getCount() {
return this.newsList.size();
}
#Override
public CharSequence getPageTitle(int position) {
return "Tab " + position;
}
}
Vertical viewpager scrolls smoothly. Currently for horizontal viewpager, i have to scroll from the edge of the screens. But i need to make it scrolled like the vertical one from anywhere in the screen.
Issue with your code is your VerticalViewPager
If you notice the code,
#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;
}
Step-1, Call super with swapped gesture.
Step-2, Perform actions on vertical view pager with current gesture.
And if you specifically see the comment, // return touch coordinates to original reference frame for any child views this clearly tells that gesture is first consumed by child.
So in your vertical view pager since you are swapping the gestures, it is consuming the Horizontal Gesture even before passing it to the parent. Thats why your horizontal view pager do not get the gesture.
If you are using Vertical View Pager with any conflicting gesture implementation like ScrollView, Lists, RecyclerView, ViewPager, etc. use the one as in the link below. It is deprecated but works with all Gesture Conflicting Views.
https://github.com/kaelaela/VerticalViewPager
I had this issue and I resolved it by wrapping the viewpager in a Scrollview
<ScrollView
android:id="#+id/nested_scroll"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/view_pager"
android:nestedScrollingEnabled="false"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</ScrollView>
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) {
}
});
link check this news app, i want to develop like this.
i want swipe up/down side effect..
i tried this code,but not correctly swiping as i want.
in this code when i swipe up/down,only the text is changing not a layout.
public class ArticlesActivity extends Activity implements GestureDetector.OnGestureListener{
ImageView image,imageArticle;
TextView tv1,tv2,tv3;
private GestureDetector gd;
LinearLayout layout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_articles);
//Creating GestureDetector Object
gd = new GestureDetector(this, this);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
//Registering TouchEvent with GestureDetector
return gd.onTouchEvent(event);
}
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
//Destroying Activity
finish();
}
#Override
public boolean onDown(MotionEvent arg0) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// TODO Auto-generated method stub
//Defining Sensitivity
float sensitivity = 50;
//Swipe Up Check
if(e1.getY() - e2.getY() > sensitivity){
//Setting Image Resource to Up_Arrow on Swipe Up
tv1.setText("Some Text");
tv2.setText("Some Text");
tv3.setText("Some Text");
image.setImageResource(R.drawable.logo);
imageArticle.setImageResource(R.drawable.ic_launcher);
return true;
}
//Swipe Down Check
else if(e2.getY() - e1.getY() > sensitivity){
//Setting Image Resource to Down_Arrow on Swipe Down
tv1.setText("Some Text");
tv2.setText("Some Text");
tv3.setText("Some Text");
image.setImageResource(R.drawable.ic_launcher);
imageArticle.setImageResource(R.drawable.logo);
return true;
}
else{
//If some error occurrs, setting again to Default_Image (Actually it will never happen in this case)
image.setImageResource(R.drawable.logo);
return true;
}
}
#Override
public void onLongPress(MotionEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2,
float arg3) {
// TODO Auto-generated method stub
return false;
}
#Override
public void onShowPress(MotionEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public boolean onSingleTapUp(MotionEvent arg0) {
// TODO Auto-generated method stub
return false;
}
}
This will work like inshorts app
main.xml
<com.cardviewanimation.VerticalViewPager
android:id="#+id/verticleViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
content_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.CardView
android:id="#+id/card_view"
android:layout_gravity="center"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
card_view:cardCornerRadius="2dp"
card_view:contentPadding="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="300dp"
android:src="#drawable/background"
android:scaleType="fitXY"/>
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"/>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
VerticleViewPagerActivity.java
public class VerticleViewPagerActivity extends AppCompatActivity {
VerticalViewPager verticalViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
verticalViewPager = (VerticalViewPager) findViewById(R.id.verticleViewPager);
verticalViewPager.setAdapter(new VerticlePagerAdapter(this));
}
}
VerticlePagerAdapter.java
public class VerticlePagerAdapter extends PagerAdapter {
String mResources[] = {"To start off lets understand what exactly Android CardView is? Its a new widget for Android, which can be used to display a card sort of a layout in android. As you may know Android material design is inspired from paper and ink concept. Mostly it displays views on top of each other, with shadows. In simple terms, Android CardView is such a view which has all material design properties, most importantly showing shadows according the elevation. The best part about this view is that it extends FrameLayout and it can be displayed on all the platforms of android since it’s available through the Support v7 library. Lets have a look at some of its properties:","To start off lets understand what exactly Android CardView is? Its a new widget for Android, which can be used to display a card sort of a layout in android. As you may know Android material design is inspired from paper and ink concept. Mostly it displays views on top of each other, with shadows. In simple terms, Android CardView is such a view which has all material design properties, most importantly showing shadows according the elevation. The best part about this view is that it extends FrameLayout and it can be displayed on all the platforms of android since it’s available through the Support v7 library. Lets have a look at some of its properties:"};
Context mContext;
LayoutInflater mLayoutInflater;
public VerticlePagerAdapter(Context context) {
mContext = context;
mLayoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return mResources.length;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == ((LinearLayout) object);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
View itemView = mLayoutInflater.inflate(R.layout.content_main, container, false);
TextView label = (TextView) itemView.findViewById(R.id.textView);
label.setText(mResources[position]);
container.addView(itemView);
return itemView;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((LinearLayout) object);
}
}
VerticalViewPager.java
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() {
// The majority of the magic happens here
setPageTransformer(true, new VerticalPageTransformer());
// The easiest way to get rid of the overscroll drawing that happens on the left and right
setOverScrollMode(OVER_SCROLL_NEVER);
}
private class VerticalPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.75f;
#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 <= 0) { // [-1,0]
// Use the default slide transition when moving to the left 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]
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -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);
}
}
}
/**
* 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));
}
}
I got the solution for your problem as inshorts app using vertical view pager. I am sharing some code that can serve your purpose.
public class VerticalViewPager extends ViewPager {
public VerticalViewPager(Context context) {
this(context, null);
}
public VerticalViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
setPageTransformer(false, new DefaultTransformer());
}
private MotionEvent swapTouchEvent(MotionEvent event) {
float width = getWidth();
float height = getHeight();
float swappedX = (event.getY() / height) * width;
float swappedY = (event.getX() / width) * height;
event.setLocation(swappedX, swappedY);
return event;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean intercept = super.onInterceptTouchEvent(swapTouchEvent(event));
//If not intercept, touch event should not be swapped.
swapTouchEvent(event);
return intercept;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(swapTouchEvent(ev));
}
}
As you can see the class above uses the DefaultTransformer class for transformation which implement ViewPager.PageTransformer for custom animation this class code is given below
public class DefaultTransformer implements ViewPager.PageTransformer {
#Override
public void transformPage(View view, float position) {
float alpha = 0;
if (0 <= position && position <= 1) {
alpha = 1 - position;
} else if (-1 < position && position < 0) {
alpha = position + 1;
}
System.out.println("alpha--" + alpha);
view.setAlpha(alpha);
System.out.println("position--" + position);
System.out.println("view.getWidth()--" + view.getWidth());
view.setTranslationX(view.getWidth() * -position);
float yPosition = position * view.getHeight();
System.out.println("yPosition---"+yPosition);
view.setTranslationY(yPosition);
}
}
and my activity code is like this
public class SwipeUpActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_swipe_layout);
setTitle("");
initViewPager();
}
private void initViewPager() {
VerticalViewPager viewPager = (VerticalViewPager) findViewById(R.id.vertical_viewpager);
//viewPager.setPageTransformer(false, new ZoomOutTransformer());
//viewPager.setPageTransformer(true, new StackTransformer());
String title = "ContentFragment";
viewPager.setAdapter(new ContentFragmentAdapter.Holder(getSupportFragmentManager())
.add(ContentFragment.newInstance(title, 1))
.add(ContentFragment.newInstance(title, 2))
.add(ContentFragment.newInstance(title, 3))
.add(ContentFragment.newInstance(title, 4))
.add(ContentFragment.newInstance(title, 5))
.set());
//If you setting other scroll mode, the scrolled fade is shown from either side of display.
viewPager.setOverScrollMode(View.OVER_SCROLL_NEVER);
}
The layout named activity_swipe_layout is like this
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="#A6000000"
android:layout_height="match_parent">
<gmaillogindemo.com.irk.transforms.VerticalViewPager
android:id="#+id/vertical_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
and the result is looking like this:
after swipe up
Does anybody has an idea how Pinterest or Tumblr has implemented there "swipe back" method.
i.e. on Pinterest you can click on a post on the news feed. Than the DetailActivity is started and displays the details for the selected post. Than you can press the back button to return to the news feed activity, or you can swipe (the details activity) to the left to come back to the news feed activity.
Video: http://youtu.be/eVcSCWetnTA
Normally I would use overridePendingTransition(), but overridePendingTransition() takes animations (Resource ids like R.anim.foo). Pinterest and Tumblr start the animation only if the user do a swipe gesture. They also support some kind of "frame by frame animation" according the fingers move. So they track the distance of the finger move and animate the transition to the corresponding percentage value.
I know how to use a "real java" Animation / AnimatorSet Object with FragmentTransaction to animate a fragment replacement. With fragments I have to override onCreateAnimator(), but I have no clue how to implement something like that with Activities. Is there a onCreateAnimator() (or something similar) for Activities? Also not sure how to swipe behaviour, since its not starting the animation right now, but more a step by step property changement of the Window / Activity/ Fragment or whatever ...
Any suggestions?
EDIT:
I have found a video of the pinterest app at youtube: http://youtu.be/eVcSCWetnTA
Thats what I want to implement.
I guess Pinterest is working with Fragments and onCreateAnimator() to achieve the "swipe back".
Since my App has already Fragment and ChildFragments in a activity it would be so much easier for me if I could implement that for Activities.
Once more: I know how to detect swipe gestures and thats not what I'm asking for. Watch the youtube video: http://youtu.be/eVcSCWetnTA
UPDATE:
I have created a little library, which has not exactly the same behavior like Pinterest or Tumblrs implementation, however for my apps this seems to me a good solution:
https://github.com/sockeqwe/SwipeBack?source=c
It seems that the effect you're looking for is one of the samples for ViewPager in the android developer's website.
Check out http://developer.android.com/training/animation/screen-slide.html#depth-page , in the Depth page transformer section. It has a video and source code.
Using a ViewPager.PageTransformer you can decide how the pages behave when switching from one to the next.
The only difference between the sample and the video you linked to is that left-right seems to be inverted, but should be a good starting point for what I saw on the YouTube video linked in the question. The actions on the two views would have to be swaped. As shown in this piece of code (the 1st parameter to mPager.setPageTransformer should be reverseDrawingOrder = false). Note the middle 2 if sections are swaped and the position variable is handled slightly different to switch sides. The bouncy effect is left as an exercise. Please share when you get that!
package com.example.android.animationsdemo;
import android.support.v4.view.ViewPager;
import android.view.View;
public class SinkPageTransformer implements ViewPager.PageTransformer {
private static float MIN_SCALE = 0.75f;
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]
// 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 if (position <= 1) { // (0,1]
// Use the default slide transition when moving to the left page
view.setAlpha(1);
view.setTranslationX(0);
view.setScaleX(1);
view.setScaleY(1);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
And just in case the page with the sample goes poof, here's that section's original code:
public class DepthPageTransformer implements ViewPager.PageTransformer {
private static float MIN_SCALE = 0.75f;
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 - 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);
}
}
}
Update:
fixed memory usage problem for this project and changed the slide back style to iOS like.
I wrote a demo exactly like Pinterest and tumblr like,you just extend the BaseActivity and you get a swipe back effect,works smoothly!
check this:https://github.com/chenjishi/SlideActivity
and the screenshot:
I found a GitHub project that is based on SwipeBack like Pinterest.
It is really a great open source project that should solve your problem. It does as you needed like go to previous screen by pressing back or simple swipe. As this project having option
1. Swipe left to Right
2. Swipe Right to Left
3. Swipe Bottom to top
https://github.com/Issacw0ng/SwipeBackLayout
and also you install this demo application from Google Play.
https://play.google.com/store/apps/details?id=me.imid.swipebacklayout.demo
Attached Screenshots:-
Hope this will help you.
I was able to do this in 15 minutes, it is not bad for a start. If you spend some time, you might be able to optimize it.
package mobi.sherif.activitydrag;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.FrameLayout.LayoutParams;
public class MainActivity extends Activity {
private static final double PERCENT_OF_SCROLL_OF_ACTIVITY_TO_FINISH = 0.3;
View mView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mView = LayoutInflater.from(this).inflate(R.layout.activity_main, null);
setContentView(mView);
}
private boolean isDragging = false;
int startX;
int currentX;
#Override
public boolean onTouchEvent(MotionEvent event) {
Log.v("sherif", isDragging?"YES":"NO" + ": " + event.getX());
if(!isDragging) {
if(event.getAction() == MotionEvent.ACTION_DOWN && event.getX()<24) {
isDragging = true;
startX = (int) event.getX();
currentX = 0;
return true;
}
return super.onTouchEvent(event);
}
switch(event.getAction()) {
case MotionEvent.ACTION_MOVE:
currentX = (int) event.getX() - startX;
LayoutParams params = (LayoutParams) mView.getLayoutParams();
params.leftMargin = currentX;
params.rightMargin = -1 * currentX;
mView.requestLayout();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
isDragging = false;
double currentPercent1 = (double) currentX / mView.getWidth();
float currentPercent = (float) currentPercent1;
if(currentX > PERCENT_OF_SCROLL_OF_ACTIVITY_TO_FINISH * mView.getWidth()) {
AnimationSet animation = new AnimationSet(false);
Animation anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 1.0f - currentPercent, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
anim.setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime));
anim.setInterpolator(new LinearInterpolator());
anim.setStartTime(AnimationUtils.currentAnimationTimeMillis());
animation.addAnimation(anim);
anim = new AlphaAnimation(1.0f, 0.5f);
anim.setDuration(getResources().getInteger(android.R.integer.config_shortAnimTime));
anim.setInterpolator(new LinearInterpolator());
anim.setStartTime(AnimationUtils.currentAnimationTimeMillis());
animation.addAnimation(anim);
animation.setFillAfter(true);
animation.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationRepeat(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
finish();
}
});
mView.startAnimation(animation);
}
else {
AnimationSet animation = new AnimationSet(false);
Animation anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f -1 * currentPercent, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
anim.setDuration(getResources().getInteger(android.R.integer.config_shortAnimTime));
anim.setInterpolator(new LinearInterpolator());
anim.setStartTime(AnimationUtils.currentAnimationTimeMillis());
animation.addAnimation(anim);
animation.setFillAfter(true);
animation.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationRepeat(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
LayoutParams params = (LayoutParams) mView.getLayoutParams();
params.leftMargin = 0;
params.rightMargin = 0;
mView.requestLayout();
mView.clearAnimation();
}
});
mView.startAnimation(animation);
}
break;
}
return true;
}
}
I just checked with hierarchy viewer. It seems like they are using ViewPager with a screenshot of the previous activity.
I would suggest doing the following:
Firstly detect the gesture that the user is doing in the device. You can refer to this link
I am not going to copy the relevant code from the above link, as I believe it is the accepted answer
Secondly you can in this method
public void onSwipeLeft() {
Toast.makeText(MyActivity.this, "left", Toast.LENGTH_SHORT).show();
}
Do the following as suggested by this question
They there talk about finishing an activity with an animation
Look into doing it through a theme. You can define enter exit animations for activities or the entire application
Hope this helps you
So I guess I found the solution by my self:
First of all:
Pinterest indeed uses a ViewPager with a custom Page Transformer like #frozenkoi has mentioned in his answer. You can see the oversroll edge effect of the view pager in the pinterest app.
#Amit Gupta has pointed to library that let the activity slide. Its pretty the same concept like various Navigation drawers does and sets also the theme to translucent. They slide the layout. But thats not exactly what I was looking for, because it slides the top activity to the right and than simply calls finish(). But the underneath activity will not be animated in.
The solution is (and I guess this is was Tumblr does) to write your very own Animation with Animation Objects and animate it step by step.
This can be done with ActivityOptions. In my opinion this will be the solution.
I wrote a project. It allows you to develop an app navigated by Fragments easily, performs just like Pinterest.
https://github.com/fengdai/FragmentMaster
Maybe it's not the answer what you want. But I hope it's useful to someone else.
I was dealing with this one in project I am currently working on and came up with following code. Maybe it's not relevant for you now, but it could help someone new in this post. :)
Basically it's ViewPager implementation as you mention in your answer, but I think it's the simplest and quickest solution to your question. The cons are that it's only for Fragments (could be easily changed for Objects) and if you want to add ActionBar into swipe, you probably end up creating a custom one.
public class DoubleViewPager extends FrameLayout implements ViewPager.OnPageChangeListener {
/**
* Represents number of objects in DelegateViewPager. In others words it stands for one main content
* window and one content detail window
*/
private static final int SCREEN_COUNT = 2;
private static final int CONTENT_SCREEN = 0;
private static final int DETAIL_SCREEN = 1;
private DelegateViewPager delegateViewPager;
private SparseArray<Fragment> activeScreens = new SparseArray<Fragment>(SCREEN_COUNT) ;
private DelegateAdapter adapter;
public DoubleViewPager(Context context) {
this(context, null);
}
public DoubleViewPager(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DoubleViewPager(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
delegateViewPager = new DelegateViewPager(context);
delegateViewPager.setId(R.id.main_page_id);
delegateViewPager.setOverScrollMode(ViewPager.OVER_SCROLL_NEVER);
final FrameLayout.LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER);
addView(delegateViewPager, params);
}
/**
* Create a new PagerAdapter and set content fragment as a first object in ViewPager;
* #param fragment Fragment you want to use as a main content
* #param fm FragmentManager required for ViewPager transactions
*/
public void initialize(final Fragment fragment, final FragmentManager fm) {
adapter = new DelegateAdapter(fm);
delegateViewPager.setAdapter(adapter);
activeScreens.put(CONTENT_SCREEN, fragment);
adapter.notifyDataSetChanged();
}
/**
* Adds fragment to stack and set it as current selected item. Basically it the same thing as calling
* startActivity() with some transitions effects
* #param fragment Fragment you want go into
*/
public void openDetailScreen(Fragment fragment) {
activeScreens.put(DETAIL_SCREEN, fragment);
adapter.notifyDataSetChanged();
delegateViewPager.setCurrentItem(1, true);
}
public void hideDetailScreen() {
delegateViewPager.setCurrentItem(CONTENT_SCREEN);
if (activeScreens.get(DETAIL_SCREEN) != null) {
activeScreens.remove(DETAIL_SCREEN);
adapter.notifyDataSetChanged();
}
}
#Override
public void onPageScrolled(int i, float v, int i2) {
// unused
}
#Override
public void onPageSelected(int i) {
if (i == CONTENT_SCREEN) hideDetailScreen();
}
#Override
public void onPageScrollStateChanged(int i) {
// unused
}
private class DelegateViewPager extends ViewPager {
public DelegateViewPager(Context context) {
super(context);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return getCurrentItem() != CONTENT_SCREEN && super.onInterceptTouchEvent(event);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
return getCurrentItem() != CONTENT_SCREEN && super.onTouchEvent(event);
}
}
private final class DelegateAdapter extends FragmentPagerAdapter {
public DelegateAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
return activeScreens.get(i);
}
#Override
public int getCount() {
return activeScreens.size();
}
}
}
Here is activity which implements it with another ViewPager as a SlidingMenu. (as extra)
public class DoubleViewPagerActivity extends FragmentActivity {
DoubleViewPager doubleViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_double_view_pager);
doubleViewPager = (DoubleViewPager) findViewById(R.id.doublePager);
doubleViewPager.initialize(new MainContentFragment(), getSupportFragmentManager());
}
public static final class MainContentFragment extends Fragment {
public MainContentFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_doublepager_content_window, parent, false);
final ViewPager pager = (ViewPager) view.findViewById(R.id.contentPager);
pager.setAdapter(new SimpleMenuAdapter(getChildFragmentManager()));
pager.setOffscreenPageLimit(2);
pager.setCurrentItem(1);
return view;
}
}
public static final class SimpleMenuAdapter extends FragmentPagerAdapter {
public SimpleMenuAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
return DoubleViewPagerActivity.PagerFragment.instance(i);
}
#Override
public int getCount() {
return 3;
}
#Override
public float getPageWidth(int position) {
switch (position) {
case 0:
case 2:
return 0.7f;
}
return super.getPageWidth(position);
}
}
public static final class PagerFragment extends Fragment {
public static PagerFragment instance(int position) {
final PagerFragment fr = new PagerFragment();
Bundle args = new Bundle();
args.putInt("position", position);
fr.setArguments(args);
return fr;
}
public PagerFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
final FrameLayout fl = new FrameLayout(getActivity());
fl.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
int position = getArguments().getInt("position");
switch (position) {
case 0:
fl.setBackgroundColor(Color.RED);
break;
case 1:
fl.setBackgroundColor(Color.GREEN);
initListView(fl);
break;
case 2:
fl.setBackgroundColor(Color.BLUE);
break;
}
return fl;
}
private void initListView(FrameLayout fl) {
int max = 50;
final ArrayList<String> items = new ArrayList<String>(max);
for (int i = 1; i <= max; i++) {
items.add("Items " + i);
}
ListView listView = new ListView(getActivity());
fl.addView(listView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER));
listView.setAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, items));
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
((DoubleViewPagerActivity) getActivity()).doubleViewPager.openDetailScreen(new DetailFragment());
}
});
}
}
public final static class DetailFragment extends Fragment {
public DetailFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
FrameLayout l = new FrameLayout(getActivity());
l.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
l.setBackgroundColor(getResources().getColor(android.R.color.holo_purple));
return l;
}
}
}
This library allows you to open fragments as in iOS and close them using swipes
https://github.com/shikleev/fragula
Navigation library
Here is a library fully integrated with NavComponent.
I'm still working on it, but it's already stable so you can use it in production.
https://github.com/massivemadness/Fragula
Note: it works only with fragments
Does anybody has an idea how Pinterest or Tumblr has implemented there "swipe back" method.
i.e. on Pinterest you can click on a post on the news feed. Than the DetailActivity is started and displays the details for the selected post. Than you can press the back button to return to the news feed activity, or you can swipe (the details activity) to the left to come back to the news feed activity.
Video: http://youtu.be/eVcSCWetnTA
Normally I would use overridePendingTransition(), but overridePendingTransition() takes animations (Resource ids like R.anim.foo). Pinterest and Tumblr start the animation only if the user do a swipe gesture. They also support some kind of "frame by frame animation" according the fingers move. So they track the distance of the finger move and animate the transition to the corresponding percentage value.
I know how to use a "real java" Animation / AnimatorSet Object with FragmentTransaction to animate a fragment replacement. With fragments I have to override onCreateAnimator(), but I have no clue how to implement something like that with Activities. Is there a onCreateAnimator() (or something similar) for Activities? Also not sure how to swipe behaviour, since its not starting the animation right now, but more a step by step property changement of the Window / Activity/ Fragment or whatever ...
Any suggestions?
EDIT:
I have found a video of the pinterest app at youtube: http://youtu.be/eVcSCWetnTA
Thats what I want to implement.
I guess Pinterest is working with Fragments and onCreateAnimator() to achieve the "swipe back".
Since my App has already Fragment and ChildFragments in a activity it would be so much easier for me if I could implement that for Activities.
Once more: I know how to detect swipe gestures and thats not what I'm asking for. Watch the youtube video: http://youtu.be/eVcSCWetnTA
UPDATE:
I have created a little library, which has not exactly the same behavior like Pinterest or Tumblrs implementation, however for my apps this seems to me a good solution:
https://github.com/sockeqwe/SwipeBack?source=c
It seems that the effect you're looking for is one of the samples for ViewPager in the android developer's website.
Check out http://developer.android.com/training/animation/screen-slide.html#depth-page , in the Depth page transformer section. It has a video and source code.
Using a ViewPager.PageTransformer you can decide how the pages behave when switching from one to the next.
The only difference between the sample and the video you linked to is that left-right seems to be inverted, but should be a good starting point for what I saw on the YouTube video linked in the question. The actions on the two views would have to be swaped. As shown in this piece of code (the 1st parameter to mPager.setPageTransformer should be reverseDrawingOrder = false). Note the middle 2 if sections are swaped and the position variable is handled slightly different to switch sides. The bouncy effect is left as an exercise. Please share when you get that!
package com.example.android.animationsdemo;
import android.support.v4.view.ViewPager;
import android.view.View;
public class SinkPageTransformer implements ViewPager.PageTransformer {
private static float MIN_SCALE = 0.75f;
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]
// 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 if (position <= 1) { // (0,1]
// Use the default slide transition when moving to the left page
view.setAlpha(1);
view.setTranslationX(0);
view.setScaleX(1);
view.setScaleY(1);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
And just in case the page with the sample goes poof, here's that section's original code:
public class DepthPageTransformer implements ViewPager.PageTransformer {
private static float MIN_SCALE = 0.75f;
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 - 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);
}
}
}
Update:
fixed memory usage problem for this project and changed the slide back style to iOS like.
I wrote a demo exactly like Pinterest and tumblr like,you just extend the BaseActivity and you get a swipe back effect,works smoothly!
check this:https://github.com/chenjishi/SlideActivity
and the screenshot:
I found a GitHub project that is based on SwipeBack like Pinterest.
It is really a great open source project that should solve your problem. It does as you needed like go to previous screen by pressing back or simple swipe. As this project having option
1. Swipe left to Right
2. Swipe Right to Left
3. Swipe Bottom to top
https://github.com/Issacw0ng/SwipeBackLayout
and also you install this demo application from Google Play.
https://play.google.com/store/apps/details?id=me.imid.swipebacklayout.demo
Attached Screenshots:-
Hope this will help you.
I was able to do this in 15 minutes, it is not bad for a start. If you spend some time, you might be able to optimize it.
package mobi.sherif.activitydrag;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.FrameLayout.LayoutParams;
public class MainActivity extends Activity {
private static final double PERCENT_OF_SCROLL_OF_ACTIVITY_TO_FINISH = 0.3;
View mView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mView = LayoutInflater.from(this).inflate(R.layout.activity_main, null);
setContentView(mView);
}
private boolean isDragging = false;
int startX;
int currentX;
#Override
public boolean onTouchEvent(MotionEvent event) {
Log.v("sherif", isDragging?"YES":"NO" + ": " + event.getX());
if(!isDragging) {
if(event.getAction() == MotionEvent.ACTION_DOWN && event.getX()<24) {
isDragging = true;
startX = (int) event.getX();
currentX = 0;
return true;
}
return super.onTouchEvent(event);
}
switch(event.getAction()) {
case MotionEvent.ACTION_MOVE:
currentX = (int) event.getX() - startX;
LayoutParams params = (LayoutParams) mView.getLayoutParams();
params.leftMargin = currentX;
params.rightMargin = -1 * currentX;
mView.requestLayout();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
isDragging = false;
double currentPercent1 = (double) currentX / mView.getWidth();
float currentPercent = (float) currentPercent1;
if(currentX > PERCENT_OF_SCROLL_OF_ACTIVITY_TO_FINISH * mView.getWidth()) {
AnimationSet animation = new AnimationSet(false);
Animation anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 1.0f - currentPercent, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
anim.setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime));
anim.setInterpolator(new LinearInterpolator());
anim.setStartTime(AnimationUtils.currentAnimationTimeMillis());
animation.addAnimation(anim);
anim = new AlphaAnimation(1.0f, 0.5f);
anim.setDuration(getResources().getInteger(android.R.integer.config_shortAnimTime));
anim.setInterpolator(new LinearInterpolator());
anim.setStartTime(AnimationUtils.currentAnimationTimeMillis());
animation.addAnimation(anim);
animation.setFillAfter(true);
animation.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationRepeat(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
finish();
}
});
mView.startAnimation(animation);
}
else {
AnimationSet animation = new AnimationSet(false);
Animation anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f -1 * currentPercent, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
anim.setDuration(getResources().getInteger(android.R.integer.config_shortAnimTime));
anim.setInterpolator(new LinearInterpolator());
anim.setStartTime(AnimationUtils.currentAnimationTimeMillis());
animation.addAnimation(anim);
animation.setFillAfter(true);
animation.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationRepeat(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
LayoutParams params = (LayoutParams) mView.getLayoutParams();
params.leftMargin = 0;
params.rightMargin = 0;
mView.requestLayout();
mView.clearAnimation();
}
});
mView.startAnimation(animation);
}
break;
}
return true;
}
}
I just checked with hierarchy viewer. It seems like they are using ViewPager with a screenshot of the previous activity.
I would suggest doing the following:
Firstly detect the gesture that the user is doing in the device. You can refer to this link
I am not going to copy the relevant code from the above link, as I believe it is the accepted answer
Secondly you can in this method
public void onSwipeLeft() {
Toast.makeText(MyActivity.this, "left", Toast.LENGTH_SHORT).show();
}
Do the following as suggested by this question
They there talk about finishing an activity with an animation
Look into doing it through a theme. You can define enter exit animations for activities or the entire application
Hope this helps you
So I guess I found the solution by my self:
First of all:
Pinterest indeed uses a ViewPager with a custom Page Transformer like #frozenkoi has mentioned in his answer. You can see the oversroll edge effect of the view pager in the pinterest app.
#Amit Gupta has pointed to library that let the activity slide. Its pretty the same concept like various Navigation drawers does and sets also the theme to translucent. They slide the layout. But thats not exactly what I was looking for, because it slides the top activity to the right and than simply calls finish(). But the underneath activity will not be animated in.
The solution is (and I guess this is was Tumblr does) to write your very own Animation with Animation Objects and animate it step by step.
This can be done with ActivityOptions. In my opinion this will be the solution.
I wrote a project. It allows you to develop an app navigated by Fragments easily, performs just like Pinterest.
https://github.com/fengdai/FragmentMaster
Maybe it's not the answer what you want. But I hope it's useful to someone else.
I was dealing with this one in project I am currently working on and came up with following code. Maybe it's not relevant for you now, but it could help someone new in this post. :)
Basically it's ViewPager implementation as you mention in your answer, but I think it's the simplest and quickest solution to your question. The cons are that it's only for Fragments (could be easily changed for Objects) and if you want to add ActionBar into swipe, you probably end up creating a custom one.
public class DoubleViewPager extends FrameLayout implements ViewPager.OnPageChangeListener {
/**
* Represents number of objects in DelegateViewPager. In others words it stands for one main content
* window and one content detail window
*/
private static final int SCREEN_COUNT = 2;
private static final int CONTENT_SCREEN = 0;
private static final int DETAIL_SCREEN = 1;
private DelegateViewPager delegateViewPager;
private SparseArray<Fragment> activeScreens = new SparseArray<Fragment>(SCREEN_COUNT) ;
private DelegateAdapter adapter;
public DoubleViewPager(Context context) {
this(context, null);
}
public DoubleViewPager(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DoubleViewPager(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
delegateViewPager = new DelegateViewPager(context);
delegateViewPager.setId(R.id.main_page_id);
delegateViewPager.setOverScrollMode(ViewPager.OVER_SCROLL_NEVER);
final FrameLayout.LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER);
addView(delegateViewPager, params);
}
/**
* Create a new PagerAdapter and set content fragment as a first object in ViewPager;
* #param fragment Fragment you want to use as a main content
* #param fm FragmentManager required for ViewPager transactions
*/
public void initialize(final Fragment fragment, final FragmentManager fm) {
adapter = new DelegateAdapter(fm);
delegateViewPager.setAdapter(adapter);
activeScreens.put(CONTENT_SCREEN, fragment);
adapter.notifyDataSetChanged();
}
/**
* Adds fragment to stack and set it as current selected item. Basically it the same thing as calling
* startActivity() with some transitions effects
* #param fragment Fragment you want go into
*/
public void openDetailScreen(Fragment fragment) {
activeScreens.put(DETAIL_SCREEN, fragment);
adapter.notifyDataSetChanged();
delegateViewPager.setCurrentItem(1, true);
}
public void hideDetailScreen() {
delegateViewPager.setCurrentItem(CONTENT_SCREEN);
if (activeScreens.get(DETAIL_SCREEN) != null) {
activeScreens.remove(DETAIL_SCREEN);
adapter.notifyDataSetChanged();
}
}
#Override
public void onPageScrolled(int i, float v, int i2) {
// unused
}
#Override
public void onPageSelected(int i) {
if (i == CONTENT_SCREEN) hideDetailScreen();
}
#Override
public void onPageScrollStateChanged(int i) {
// unused
}
private class DelegateViewPager extends ViewPager {
public DelegateViewPager(Context context) {
super(context);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return getCurrentItem() != CONTENT_SCREEN && super.onInterceptTouchEvent(event);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
return getCurrentItem() != CONTENT_SCREEN && super.onTouchEvent(event);
}
}
private final class DelegateAdapter extends FragmentPagerAdapter {
public DelegateAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
return activeScreens.get(i);
}
#Override
public int getCount() {
return activeScreens.size();
}
}
}
Here is activity which implements it with another ViewPager as a SlidingMenu. (as extra)
public class DoubleViewPagerActivity extends FragmentActivity {
DoubleViewPager doubleViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_double_view_pager);
doubleViewPager = (DoubleViewPager) findViewById(R.id.doublePager);
doubleViewPager.initialize(new MainContentFragment(), getSupportFragmentManager());
}
public static final class MainContentFragment extends Fragment {
public MainContentFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_doublepager_content_window, parent, false);
final ViewPager pager = (ViewPager) view.findViewById(R.id.contentPager);
pager.setAdapter(new SimpleMenuAdapter(getChildFragmentManager()));
pager.setOffscreenPageLimit(2);
pager.setCurrentItem(1);
return view;
}
}
public static final class SimpleMenuAdapter extends FragmentPagerAdapter {
public SimpleMenuAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
return DoubleViewPagerActivity.PagerFragment.instance(i);
}
#Override
public int getCount() {
return 3;
}
#Override
public float getPageWidth(int position) {
switch (position) {
case 0:
case 2:
return 0.7f;
}
return super.getPageWidth(position);
}
}
public static final class PagerFragment extends Fragment {
public static PagerFragment instance(int position) {
final PagerFragment fr = new PagerFragment();
Bundle args = new Bundle();
args.putInt("position", position);
fr.setArguments(args);
return fr;
}
public PagerFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
final FrameLayout fl = new FrameLayout(getActivity());
fl.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
int position = getArguments().getInt("position");
switch (position) {
case 0:
fl.setBackgroundColor(Color.RED);
break;
case 1:
fl.setBackgroundColor(Color.GREEN);
initListView(fl);
break;
case 2:
fl.setBackgroundColor(Color.BLUE);
break;
}
return fl;
}
private void initListView(FrameLayout fl) {
int max = 50;
final ArrayList<String> items = new ArrayList<String>(max);
for (int i = 1; i <= max; i++) {
items.add("Items " + i);
}
ListView listView = new ListView(getActivity());
fl.addView(listView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER));
listView.setAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, items));
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
((DoubleViewPagerActivity) getActivity()).doubleViewPager.openDetailScreen(new DetailFragment());
}
});
}
}
public final static class DetailFragment extends Fragment {
public DetailFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
FrameLayout l = new FrameLayout(getActivity());
l.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
l.setBackgroundColor(getResources().getColor(android.R.color.holo_purple));
return l;
}
}
}
This library allows you to open fragments as in iOS and close them using swipes
https://github.com/shikleev/fragula
Navigation library
Here is a library fully integrated with NavComponent.
I'm still working on it, but it's already stable so you can use it in production.
https://github.com/massivemadness/Fragula
Note: it works only with fragments