Desliza hacia atrás como Pinterest o Tumblr

¿Alguien tiene una idea de cómo Pinterest o Tumblr ha implementado allí "golpear atrás" método.

Es decir, en Pinterest puedes hacer clic en un mensaje en el feed de noticias. Se inicia la actividad de DetailActivity y se muestran los detalles de la publicación seleccionada. Puede presionar el botón de retroceso para volver a la actividad de feed de noticias, o puede deslizar (la actividad de detalles) a la izquierda para volver a la actividad de feed de noticias.

Video: http://youtu.be/eVcSCWetnTA

Normalmente usaría overridePendingTransition() , pero overridePendingTransition() toma animaciones ( R.anim.foo recursos como R.anim.foo ). Pinterest y Tumblr comienzan la animación sólo si el usuario hace un gesto de deslizamiento. También apoyan una cierta "animación del marco por cuadro" según el movimiento de los dedos. Así que rastrea la distancia del movimiento del dedo y anima la transición al valor de porcentaje correspondiente.

Sé cómo utilizar un "real java" Animation / AnimatorSet objeto con FragmentTransaction para animar un reemplazo de fragmentos. Con fragmentos tengo que anular onCreateAnimator() , pero no tengo ni idea de cómo implementar algo así con Actividades. ¿Hay un onCreateAnimator() (o algo similar) para Actividades? También no está seguro de cómo deslizar el comportamiento, ya que no está empezando la animación ahora, pero más un paso a paso la propiedad de cambio de la ventana / actividad / fragmento o lo que sea …

¿Alguna sugerencia?

EDIT: He encontrado un video de la aplicación pinterest en youtube: http://youtu.be/eVcSCWetnTA Eso es lo que quiero implementar.

Supongo que Pinterest está trabajando con Fragments y onCreateAnimator() para lograr el "retroceso". Ya que mi aplicación ya tiene fragmentos y fragmentos de niños en una actividad, sería mucho más fácil para mí si pudiera implementar eso para las actividades.

Una vez más: sé cómo detectar gestos de golpe y eso no es lo que estoy pidiendo. Mira el video de youtube: http://youtu.be/eVcSCWetnTA


ACTUALIZACIÓN: He creado una pequeña biblioteca, que no tiene exactamente el mismo comportamiento que la de Pinterest o Tumblrs, sin embargo para mis aplicaciones esto me parece una buena solución: https://github.com/sockeqwe/SwipeBack?source=c

Parece que el efecto que estás buscando es una de las muestras de ViewPager en el sitio web del desarrollador android.

Echa un vistazo a http://developer.android.com/training/animation/screen-slide.html#depth-page , en la sección Transformador de página de profundidad . Tiene un video y código fuente.

Usando un ViewPager.PageTransformer puede decidir cómo se comportan las páginas al cambiar de una a la siguiente.

La única diferencia entre la muestra y el video al que estás vinculado es que la izquierda-derecha parece estar invertida, pero debería ser un buen punto de partida para lo que vi en el video de YouTube vinculado en la pregunta. Las acciones en las dos visiones tendrían que ser pasadas. Como se muestra en esta pieza de código (el primer parámetro a mPager.setPageTransformer debe ser reverseDrawingOrder = false). Observe el centro 2 if secciones se cambian y la variable de position se maneja ligeramente diferente para cambiar de lado. El efecto de saltar se deja como un ejercicio. ¡Por favor comparta cuando usted consiga eso!

  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); } } } 

Y sólo en caso de que la página con la muestra va poof, aquí está el código original de esa sección:

  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); } } } 

Actualización: problema de uso de memoria fija para este proyecto y cambió el estilo de diapositiva a iOS.

Introduzca aquí la descripción de la imagen

Escribí una demo exactamente como Pinterest y tumblr como, sólo ampliar el BaseActivity y obtendrá un golpe de nuevo efecto, funciona sin problemas!

Compruebe esto: https://github.com/chenjishi/SlideActivity

Y la captura de pantalla: Introduzca aquí la descripción de la imagen

He encontrado un proyecto GitHub que se basa en SwipeBack como Pinterest.

Es realmente un gran proyecto de código abierto que debe resolver su problema. Hace lo que necesitas como ir a la pantalla anterior presionando hacia atrás o simplemente deslizar. Como este proyecto tiene opción

1. Deslizar hacia la izquierda a la derecha

2. Deslizar de derecha a izquierda

3. Deslizar la parte inferior hacia arriba

https://github.com/Issacw0ng/SwipeBackLayout

Y también instalas esta aplicación de demostración de Google Play.

https://play.google.com/store/apps/details?id=me.imid.swipebacklayout.demo

Imágenes adjuntas: –

Introduzca aquí la descripción de la imagen

Espero que esto te ayudará.

Pude hacer esto en 15 minutos, no es malo para empezar. Si pasa algún tiempo, podría optimizarlo.

 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; } } 

Acabo de comprobar con el visor de jerarquía. Parece que están usando ViewPager con una captura de pantalla de la actividad anterior.

Yo sugeriría hacer lo siguiente:

En primer lugar detectar el gesto que el usuario está haciendo en el dispositivo. Puede consultar este enlace

No voy a copiar el código relevante del enlace anterior, ya que creo que es la respuesta aceptada

En segundo lugar se puede en este método

 public void onSwipeLeft() { Toast.makeText(MyActivity.this, "left", Toast.LENGTH_SHORT).show(); } 

Haga lo siguiente como sugiere esta pregunta

Allí hablan de terminar una actividad con una animación

 Look into doing it through a theme. You can define enter exit animations for activities or the entire application 

Espero que esto te ayude

Así que supongo que encontré la solución por mí mismo:

En primer lugar: Pinterest realmente utiliza un ViewPager con un transformador de página personalizado como @frozenkoi ha mencionado en su respuesta. Puede ver el efecto de borde de oversroll del paginador de vista en la aplicación pinterest.

@Amit Gupta ha señalado a la biblioteca que permiten la actividad de diapositivas. Es bastante el mismo concepto como varios cajones de navegación hace y establece también el tema a translúcido. Deslizan el diseño. Pero eso no es exactamente lo que estaba buscando, porque se desliza la actividad superior a la derecha y que simplemente llama a finish (). Pero la actividad debajo no será animada en.

La solución es (y supongo que esto fue Tumblr) para escribir tu propia animación con animación objetos y animar paso a paso. Esto se puede hacer con ActivityOptions . En mi opinión, esta será la solución.

Escribí un proyecto. Le permite desarrollar una aplicación navegada por Fragmentos fácilmente, se realiza igual que Pinterest.

https://github.com/fengdai/FragmentMaster

Tal vez no es la respuesta lo que quieres. Pero espero que sea útil para alguien más.

Estaba tratando con este proyecto en el que actualmente estoy trabajando y surgió con el código siguiente. Tal vez no es relevante para usted ahora, pero podría ayudar a alguien nuevo en este post. 🙂

Básicamente es la implementación ViewPager como mencionas en tu respuesta, pero creo que es la solución más simple y más rápida a tu pregunta. Los contras son que es sólo para Fragmentos (se podría cambiar fácilmente para los objetos) y si desea agregar ActionBar en golpe, probablemente terminan creando uno personalizado.

 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(); } } 

}

Aquí está la actividad que lo implementa con otro ViewPager como SlidingMenu. (Como 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; } } 

}

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.