I am trying to put a Google map inside a scroll view, so that the user can scroll down other contents to see the map. The problem is that this scroll view is eating up all the vertical touching events, so the UI experience of map becomes very weird.
I know that in V1 of the google map, you could override onTouch, or setOnTouchListener to call requestDisallowInterceptTouchEvent upon MotionEvent.ACTION_DOWN. I have tried to implement the similar trick with V2 to no avail.
So far I have tried:
None of these remedied the scrolling problem. Am I missing something here? If anyone has a working example of a map inside scrolling view, could you please kindly share code example?
Apply a transparent image over the mapview fragment.
<RelativeLayout
android:id="@+id/map_layout"
android:layout_width="match_parent"
android:layout_height="300dp">
<fragment
android:id="@+id/mapview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="-100dp"
android:layout_marginBottom="-100dp"
android:name="com.google.android.gms.maps.MapFragment"/>
<ImageView
android:id="@+id/transparent_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@color/transparent" />
</RelativeLayout>
Then set requestDisallowInterceptTouchEvent(true)
for the main ScrollView. When the user touches the transparent image and moves disable the touch on the transparent image for MotionEvent.ACTION_DOWN
and MotionEvent.ACTION_MOVE
so that map fragment can take Touch Events.
ScrollView mainScrollView = (ScrollView) findViewById(R.id.main_scrollview);
ImageView transparentImageView = (ImageView) findViewById(R.id.transparent_image);
transparentImageView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
// Disallow ScrollView to intercept touch events.
mainScrollView.requestDisallowInterceptTouchEvent(true);
// Disable touch on transparent view
return false;
case MotionEvent.ACTION_UP:
// Allow ScrollView to intercept touch events.
mainScrollView.requestDisallowInterceptTouchEvent(false);
return true;
case MotionEvent.ACTION_MOVE:
mainScrollView.requestDisallowInterceptTouchEvent(true);
return false;
default:
return true;
}
}
});
This worked for me. Hope it helps you..
I encountered a similar problem and came up with a more general working solution based on In-Ho Yi and Данаил Димитров answers above.
public class CustomScrollView extends ScrollView {
List<View> mInterceptScrollViews = new ArrayList<View>();
public CustomScrollView(Context context) {
super(context);
}
public CustomScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void addInterceptScrollView(View view) {
mInterceptScrollViews.add(view);
}
public void removeInterceptScrollView(View view) {
mInterceptScrollViews.remove(view);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
// check if we have any views that should use their own scrolling
if (mInterceptScrollViews.size() > 0) {
int x = (int) event.getX();
int y = (int) event.getY();
Rect bounds = new Rect();
for (View view : mInterceptScrollViews) {
view.getHitRect(bounds);
if (bounds.contains(x, y + scrollY)) {
//were touching a view that should intercept scrolling
return false;
}
}
}
return super.onInterceptTouchEvent(event);
}
}
Thank you for suggestions,
After much try-and-error, pulling off my hairs and swearing at monitor and my poor Android test phone, I've figured that if I customise ScrollView, override onInterceptTouchEvent in which we return false when the event is on a map view no matter what, then the scrolling on a map does happen as expected.
class MyScrollView(c:Context, a:AttributeSet) extends ScrollView(c,a) {
val parent = c.asInstanceOf[MyActivity]
override def onInterceptTouchEvent(ev:MotionEvent):Boolean = {
var bound:Rect = new Rect()
parent.mMap.getHitRect(bound)
if(bound.contains(ev.getX.toInt,ev.getY.toInt))
false
else
super.onInterceptTouchEvent(ev)
}
}
This code is in Scala but you get the idea.
Note I've ended up using a raw map view (as shown in android-sdks\extras\google\google_play_services\samples\maps\src\com\example\mapdemoRawMapViewDemoActivity.java). Guess you can do the pretty much same thing with fragments, I just never liked fragments in the first place.
I think Google owes me an apology.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With