android - example - OnPageChangeListener alpha crossfading
transition manager android (1)
ViewPager.PageTransformer
es tu amigo. Voy a tomar un enfoque diferente de lo que probó, pero resulta en lo que entiendo para lograr el resultado deseado: deslizar hacia la izquierda / derecha el contenido, pero se desvanece entre dos imágenes de fondo que no se mueven.
Cada Fragment
en ViewPager
tendrá un diseño como ese:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/image_view"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:scaleType="center" />
<LinearLayout
android:id="@+id/content_area"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- content goes here -->
</LinearLayout>
</FrameLayout>
Y creará un PageTransformer
que manipula el diseño en función de la posición en la que se ha deslizado:
public class CustomPageTransformer implements ViewPager.PageTransformer {
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
View imageView = view.findViewById(R.id.image_view);
View contentView = view.findViewById(R.id.content_area);
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left
} else if (position <= 0) { // [-1,0]
// This page is moving out to the left
// Counteract the default swipe
view.setTranslationX(pageWidth * -position);
if (contentView != null) {
// But swipe the contentView
contentView.setTranslationX(pageWidth * position);
}
if (imageView != null) {
// Fade the image in
imageView.setAlpha(1 + position);
}
} else if (position <= 1) { // (0,1]
// This page is moving in from the right
// Counteract the default swipe
view.setTranslationX(pageWidth * -position);
if (contentView != null) {
// But swipe the contentView
contentView.setTranslationX(pageWidth * position);
}
if (imageView != null) {
// Fade the image out
imageView.setAlpha(1 - position);
}
} else { // (1,+Infinity]
// This page is way off-screen to the right
}
}
}
Y finalmente enganche este PageTransformer
a su ViewPager
:
mViewPager.setPageTransformer(true, new CustomPageTransformer());
Lo probé en una aplicación existente y funciona bien siempre que los diseños de los fragmentos tengan un fondo transparente.
Hay muchas preguntas con respecto al crossfading en Android, pero todas incluyen animaciones. Mi pregunta es acerca del fundido cruzado usando el OnPageChangeListener de un ViewPager.
Tengo un ViewPager que podría tener un número ilimitado de vistas, pero en la práctica usa alrededor de 6 o 7 vistas. No pasa mucho allí.
Cada vista en ViewPager tiene un mapa de bits de fondo que debe fijarse y cruzarse con el fondo de la vista siguiente (o anterior) en lugar de desplazarse junto con el resto de la vista.
Para lograr esto, desacoplé los fondos y los agregué a ArrayList y los asigné a ImageViews más tarde. Pero como no quiero arriesgarme a la posibilidad de que mi actividad termine con numerosos ImageViews, pensé en la siguiente estructura:
<FrameLayout
android:id="@+id/backgroundContainer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/bottomImage"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:scaleType="center" />
<ImageView
android:id="@+id/middleImage"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:scaleType="center" />
<ImageView
android:id="@+id/topImage"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:scaleType="center" />
</FrameLayout>
Luego se asigna un OnPageChangeListener
a ViewPager para asignar los fondos a las ImageViews.
@Override
public void onPageSelected(int position) {
MyLog.i(TAG, "PAGE SELECTED: " + position);
if(position == 0) {
_bottomBackground.setImageBitmap(null);
_topBackground.setImageBitmap(_backgroundStack.get(position+1));
} else if (position == NUM_ITEMS-1) {
_bottomBackground.setImageBitmap(_backgroundStack.get(position-1));
_topBackground.setImageBitmap(null);
} else {
_bottomBackground.setImageBitmap(_backgroundStack.get(position-1));
_topBackground.setImageBitmap(_backgroundStack.get(position+1));
}
_middleBackground.setImageBitmap(_backgroundStack.get(position));
// Make the top front background transparent
_topBackground.setAlpha(0f);
_currentBackgroundPosition = position;
}
Esto funciona bien si me hubiera gustado cambiar los fondos. Quiero que los fondos se desvanezcan el uno al otro mientras el usuario desliza ViewPager. Tengo el desvanecimiento para un desplazamiento hacia adelante, pero no entiendo por qué el desvanecimiento del desplazamiento hacia atrás de alguna manera no da un buen resultado. Durante un desplazamiento hacia atrás, el fondo del medio debe desvanecerse en el fondo inferior.
Me temo que me estoy perdiendo algo. Nunca cambio el alfa del fondo inferior, pero los resultados del registro siempre muestran exactamente el mismo valor para getAlpha()
que para el fondo del medio.
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if(_currentBackgroundPosition == position) {
// scroll forward
_topBackground.setAlpha(positionOffset)
} else {
//scroll backward
_middleBackground.setAlpha(positionOffset);
}
MyLog.i(TAG, "Bottom BackgroundAlpha: " + _bottomBackground.getAlpha());
MyLog.i(TAG, "Middle BackgroundAlpha: " + _middleBackground.getAlpha());
MyLog.i(TAG, "Top BackgroundAlpha: " + _topBackground.getAlpha());
}
¡Y espera! Hay una cosa más que realmente no puedo resolver. Aunque el desvanecimiento de desplazamiento hacia adelante está funcionando. Hay un súper breve parpadeo en el fondo. Supongo que esto está sucediendo debido a la forma en que configuré el método onPageSelected
.
¿Hay alguna otra forma de cómo puedo crear / corregir este comportamiento?