I have a ViewPager in which the pages contain ListViews. Everything works fine and my viewPAger as well as ListViews work as expected : it is possible to swipe from page to
I think I have found a workaround for this issue.
After some investigation, I think this only happens if you apply a PageTransformer
that changes the coordinates of the Views
so they are all on top of each other (the two example transformers do exactly this).
When you swipe in the direction such as the NEW VIEW has a Z-index LOWER than the OLD VIEW (normally a swipe backwards), what happens with those transformers is that the OLD VIEW is on top of the NEW VIEW, with Alpha==0, and is the one that later on gets the "ghost" touches.
Unfortunately, the solution by @ngatyrauks bringToFront()
didn't work for me (although it definitely should).
However, I have tweaked the transformer so invisible views
are changed its visibility to "GONE". And this does the trick.
I have yet to investigate if this Visibility change has any side effects (A GONE
view will return null
and zeros in layout etc, so maybe this breaks other things inside ViewPager
), but so far it's working perfect.
I post here a tweaked DepthPageTransformer
(the same in the docs) with these changes. Hope it helps anybody!
package com.regaliz.gui.fx;
import android.util.Log;
import android.view.View;
import android.support.v4.view.ViewPager;
public class DepthPageTransformer implements ViewPager.PageTransformer {
private static final String TAG="DepthTransformer";
private static float MIN_SCALE = 0.75f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
Log.d(TAG, "VIew "+view+" Position: "+position);
if (position <= -1) { // [-Infinity,-1) ] ***
// RLP> I Changed to include "-1" as well: When position is -1, the view is not visible
// This page is way off-screen to the left.
view.setAlpha(0);
Log.d(TAG, "VIew "+view+" Position: "+position+", way left");
view.setVisibility(View.GONE);
} 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);
if (position==0) {
Log.d(TAG, "View "+view+" focused now?");
}
if (view.getVisibility()!=View.VISIBLE)
view.setVisibility(View.VISIBLE);
} else if (position <= 1) { // (0,1]
// Fade the page out.
view.setAlpha(1 - position);
// Counteract the default slide transition
// I THINK THIS IS WHAT BREAKS EVERYTHING
// ViewPager normally has the views one after another, but this makes all views on top
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);
if (position==1) {
Log.d(TAG, "View "+view+" invisible now?");
view.setVisibility(View.GONE);
// we totally hide the view. This seems to solve focus issue
} else {
if (view.getVisibility()!=View.VISIBLE)
view.setVisibility(View.VISIBLE);
}
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
// we totally hide the view. This seems to solve focus issue
// I have to check for strange side-effects, but so far I found none :)
view.setVisibility(View.GONE);
Log.d(TAG, "VIew "+view+" Position: "+position+", way right");
}
}
}
I don't know if you got this working, but I have the same issue, with a PageDepthTransformer. I'm using a gridview though, the scrolling works, however my subsequent fragments seem to have focus and my top level Fragment doesn't register the correct onClick() events.
My work around for this was to add global layout listener to viewPager and bring the current view to the front
viewPager.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
View view = viewPager.getChildAt(currentFragmentPosition);
if (view != null) {
view.bringToFront();
}
}
)};
This seems like hackery to me, and I haven't quite got this working on rotation. But hopefully it might help you.
Here is the detail of the reason
after 4.1 that the framework respects a custom child drawing order as implied Z-ordering for dispatching touch events. If your views overlap after this page transformation they may not receive touch events in the expected order on older platform versions. Check which view is receiving the touch events to be certain.
If this is what you are seeing you have a few options:
- Enforce the desired ordering as you add/remove child views in your PagerAdapter
- Remove the X translation applied by the PageTransformer when a page is no longer fully visible - i.e. the "position" parameter reports a full -1 or 1.
And here is my solution
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
if (position <= -1 || position >= 1) { // [-Infinity,-1) ] ***
// [-Infinity,-1] or [1,+Infinity]
// This page is way off-screen to the left or way off-screen to the right.
view.setAlpha(0);
view.setTranslationX(0);
view.setScaleX(1);
view.setScaleY(1);
} 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);
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);
}
}
ref link: https://code.google.com/p/android/issues/detail?id=58918