android - studio - MapFragment en ScrollView
map fragment android studio (8)
Tengo uno de los nuevos MapFragment
en un ScrollView
. En realidad es un SupportMapFragment
, pero de todos modos. Funciona, pero hay dos problemas:
Cuando se desplaza, deja una máscara negra detrás. El negro cubre exactamente el área donde estaba el mapa, a excepción de un agujero donde estaban los botones +/- del zoom. Vea la captura de pantalla a continuación. Esto es en Android 4.0.
La vista no usa
requestDisallowInterceptTouchEvent()
cuando el usuario interactúa con el mapa para evitar los toques de interceptación deScrollView
, por lo que si intenta desplazarse verticalmente en el mapa, simplemente desplaza elScrollView
que lo contiene. En teoría, podría derivar una clase de vistaMapView
y agregar esa funcionalidad, pero ¿cómo puedo hacer queMapFragment
use miMapView
personalizado en lugar del estándar?
Aplicar una imagen transparente sobre el fragmento mapview parece resolver el problema. No es el más bonito, pero parece funcionar. Aquí hay un fragmento de XML que muestra esto:
<RelativeLayout
android:id="@+id/relativeLayout1"
android:layout_width="match_parent"
android:layout_height="300dp" >
<fragment
android:id="@+id/map"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
<ImageView
android:id="@+id/imageView123"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/temp_transparent" />
</RelativeLayout>
Esto probablemente tiene sus raíces en el mismo lugar que causa el problema en esta pregunta . La solución es usar un marco transparente, que es un poco más ligero que una imagen transparente.
Hecho después de un montón de I + D:
fragment_one.xml debería verse así:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/scrollViewParent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="400dip" >
<com.google.android.gms.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<View
android:id="@+id/customView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@android:color/transparent" />
</RelativeLayout>
<!-- Your other elements are here -->
</LinearLayout>
</ScrollView>
Su clase de Java de FragmentOne.java se ve así:
private GoogleMap mMap;
private MapView mapView;
private UiSettings mUiSettings;
private View customView
onCreateView
mapView = (MapView) rootView.findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
if (mapView != null) {
mMap = mapView.getMap();
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
mUiSettings = mMap.getUiSettings();
mMap.setMyLocationEnabled(true);
mUiSettings.setCompassEnabled(true);
mUiSettings.setMyLocationButtonEnabled(false);
}
scrollViewParent = (ScrollView)rootView.findViewById(R.id.scrollViewParent);
customView = (View)rootView.findViewById(R.id.customView);
customView.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.
scrollViewParent.requestDisallowInterceptTouchEvent(true);
// Disable touch on transparent view
return false;
case MotionEvent.ACTION_UP:
// Allow ScrollView to intercept touch events.
scrollViewParent.requestDisallowInterceptTouchEvent(false);
return true;
case MotionEvent.ACTION_MOVE:
scrollViewParent.requestDisallowInterceptTouchEvent(true);
return false;
default:
return true;
}
}
});
No es necesario luchar con CustomScrollViews y archivos de diseño transparentes. simplemente use una versión más ligera de Google Map y su problema será resuelto.
map:liteMode="true"
agrega la propiedad anterior dentro del fragmento del mapa en tu archivo de diseño. y el problema será arreglado.
Para la segunda parte de la pregunta, puede derivar una clase de fragmento de SupportMapFragment y utilizarlo en su diseño. A continuación, puede anular Fragment#onCreateView y crear una instancia de su MapView personalizado allí.
Si eso no funciona, siempre puedes crear tu propio fragmento; luego, solo tienes que encargarte de llamar a todos los métodos del ciclo de vida (onCreate, onResume, etc.). Esta respuesta tiene más detalles.
Para mí, agregar un ImageView transparente no ayudó a eliminar completamente la máscara negra. Las partes superior e inferior del mapa mostraban la máscara negra mientras se desplazaban.
Entonces la solución para eso, encontré en esta respuesta con un pequeño cambio. Yo añadí,
android:layout_marginTop="-100dp"
android:layout_marginBottom="-100dp"
a mi fragmento de mapa ya que era scrollview vertical. Entonces mi diseño ahora se veía de esta manera:
<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>
Para resolver la segunda parte de la pregunta, establecí requestDisallowInterceptTouchEvent(true)
para mi ScrollView principal. Cuando el usuario tocó la imagen transparente y se movió, deshabilité el toque en la imagen transparente para MotionEvent.ACTION_DOWN
y MotionEvent.ACTION_MOVE
para que el fragmento del mapa pueda tomar 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;
}
}
});
Esto funcionó para mí. Espero que te ayude ...
Usé estas estructuras y superé el problema.
Usé una vista de contenedor para el fragmento de mapas.
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:text="Another elements in scroll view1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.erolsoftware.views.MyMapFragmentContainer
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="250dp">
<fragment
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/eventMap"
tools:context="com.erolsoftware.eventapp.EventDetails"
android:name="com.google.android.gms.maps.SupportMapFragment"/>
</com.erolsoftware.views.MyMapFragmentContainer>
<TextView
android:text="Another elements in scroll view2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>
La clase de contenedor:
public class MyMapFragmentContainer extends LinearLayout {
@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
if (ev.getActionMasked() == MotionEvent.ACTION_DOWN)
{
ViewParent p = getParent();
if (p != null)
p.requestDisallowInterceptTouchEvent(true);
}
return false;
}
public MyMapFragmentContainer(Context context) {
super(context);
}
public MyMapFragmentContainer(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyMapFragmentContainer(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
<ScrollView
android:layout_width="match_parent"
::
::
::
<FrameLayout
android:id="@+id/map_add_business_one_rl"
android:layout_width="match_parent"
android:layout_height="100dp"
>
<fragment
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="-100dp"
android:layout_marginBottom="-100dp"
/>
</FrameLayout>
::
::
::
</ScrollView>