Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom ViewPager to allow child GoogleMap control to scroll horizontally

I am using a GoogleMap (v2 api) inside of a Fragment inside of a ViewPager. The original issue I was having was that the ViewPager was capturing all horizontal scrolling gestures so the map could only be dragged if the user started in the vertical or diagonal directions. All horizontal dragging was captured by the ViewPager. I found that the solution is to create a derived ViewPager class and override the canScroll method. The View being dragged is passed to this method, so you can make a decision based on the type of View it is.

In my case, my Fragment is a SupportMapFragment (from the com.google.android.gms.maps package) which gives me a GoogleMap object to interact with. However, the actual control I receive in the ViewPager's canScroll method is of type maps.j.b. I have fixed the problem with the following code inside my custom ViewPager class. However, I don't feel comfortable checking for this class name when I don't know anything about it. What is maps.j.b? Is this a dynamically created class at runtime? Is it possible for the type to change in a future update of the framework? Given only the View object, is there a more robust way of checking that the drag was initiated by a map control?

@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
    if(v.getClass().getName().equals("maps.j.b")) {
        return true;
    }
    return super.canScroll(v, checkV, dx, x, y);
}
like image 679
Rich Avatar asked Jan 17 '13 21:01

Rich


1 Answers

Is this a dynamically created class at runtime?

It's probably the output of a ProGuard rename.

Is it possible for the type to change in a future update of the framework?

AFAIK, yes. I am not aware that ProGuard guarantees that the names will stay the same between builds.

Note that this will be dependent upon the library project. When you take on a new edition of the library project, the class name may change. But, since that's tied to your own app, in a pinch, you could stick with the name game, and just need to fix up the name when you take on a new edition of the library project.

That being said, I agree that matching based on name is icky.

Given only the View object, is there a more robust way of checking that the drag was initiated by a map control?

Well, since this isn't a MapView, we have no way of knowing what precisely a maps.j.b is. We know it is not a MapView, as it is not named MapView, and Google left that name alone (via -keep directives in the ProGuard configuration, presumably) so we can use it from our apps.

You could try creating your own MapFragment with your own MapView and see if there you get a MapView instead of a maps.j.b (which might be some internal subclass of MapView used by SupportMapFragment). If you get passed the actual MapView, then you can do direct equality checks to see if the passed-in object is your MapFragment's MapView.

Or, you could see if instanceof says that a maps.j.b is a MapView.

Neither of those are guaranteed reliable over time, either, as conceivably Google could change matters such that the MapView is wrapped in something. However, my guess is that it is more likely to be stable than the generated class name.

maps.j.b inherits from SurfaceView. Hence, one way to semi-reliably detect whether or not a View passed into canScroll() is to test if (v instanceof SurfaceView). This fails if Maps V2 does something else later (e.g., extends TextureView on API Level 11+) or if your ViewPager pages have another SurfaceView (e.g., a VideoView).

I have filed an issue on this to try to get some stable means of making this determination added to the Maps V2 API.

like image 179
CommonsWare Avatar answered Sep 20 '22 12:09

CommonsWare