Как установить фрагмент карты google внутри прокрутки
Я хочу установить фрагмент карты Google внутри вертикального ScrollView
, когда я не масштабирую карту по вертикали, как я могу переопределить прослушиватель событий касания на MapView
над слушателем ScrollView
?
Это мой xml-код:
<ScrollView android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_above="@id/footer"
android:layout_below="@id/title_horizontalScrollView">
///other things
<fragment
android:id="@+id/map"
android:layout_width="fill_parent"
android:layout_height="300dp"
class="com.google.android.gms.maps.SupportMapFragment"
/>
//other things
Ответы
Ответ 1
Создайте собственный SupportMapFragmet, чтобы мы могли переопределить его событие касания:
WorkaroundMapFragment.java
import android.content.Context;
import android.os.Bundle;
import android.widget.FrameLayout;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import com.google.android.gms.maps.SupportMapFragment;
public class WorkaroundMapFragment extends SupportMapFragment {
private OnTouchListener mListener;
@Override
public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle savedInstance) {
View layout = super.onCreateView(layoutInflater, viewGroup, savedInstance);
TouchableWrapper frameLayout = new TouchableWrapper(getActivity());
frameLayout.setBackgroundColor(getResources().getColor(android.R.color.transparent));
((ViewGroup) layout).addView(frameLayout,
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
return layout;
}
public void setListener(OnTouchListener listener) {
mListener = listener;
}
public interface OnTouchListener {
public abstract void onTouch();
}
public class TouchableWrapper extends FrameLayout {
public TouchableWrapper(Context context) {
super(context);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mListener.onTouch();
break;
case MotionEvent.ACTION_UP:
mListener.onTouch();
break;
}
return super.dispatchTouchEvent(event);
}
}
}
В этом классе мы перехватываем событие touch, используя класс TouchableWrapper, который расширяет FrameLayout. Существует также пользовательский прослушиватель OnTouchListener для отправки события касания к основной активности MyMapActivity, которая обрабатывает карту. Когда произойдет событие касания, будет вызван dispatchTouchEvent, и обработчик-слушатель обработает его.
Затем замените класс фрагмента в xml этим class="packagename.WorkaroundMapFragment"
вместо com.google.android.gms.maps.SupportMapFragment
Затем в вашей деятельности инициализируйте карту следующим образом:
private GoogleMap mMap;
внутри onCreate сделать это:
// check if we have got the googleMap already
if (mMap == null) {
SupportMapFragment mapFragment = (WorkaroundMapFragment) getChildFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(new OnMapReadyCallback() {
Override
public void onMapReady(GoogleMap googleMap)
{
mMap = googleMap;
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
mMap.getUiSettings().setZoomControlsEnabled(true);
mScrollView = findViewById(R.id.scrollMap); //parent scrollview in xml, give your scrollview id value
((WorkaroundMapFragment) getChildFragmentManager().findFragmentById(R.id.map))
.setListener(new WorkaroundMapFragment.OnTouchListener() {
@Override
public void onTouch()
{
mScrollView.requestDisallowInterceptTouchEvent(true);
}
});
}
});
}
Обновление: ответ обновлен до getMapAsync на основе ответа @javacoder123
Ответ 2
Просто сделайте CustomScrollView.class
,
public class CustomScrollView extends ScrollView {
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);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
//Log.i("CustomScrollView", "onInterceptTouchEvent: DOWN super false" );
super.onTouchEvent(ev);
break;
case MotionEvent.ACTION_MOVE:
return false; // redirect MotionEvents to ourself
case MotionEvent.ACTION_CANCEL:
// Log.i("CustomScrollView", "onInterceptTouchEvent: CANCEL super false" );
super.onTouchEvent(ev);
break;
case MotionEvent.ACTION_UP:
//Log.i("CustomScrollView", "onInterceptTouchEvent: UP super false" );
return false;
default:
//Log.i("CustomScrollView", "onInterceptTouchEvent: " + action );
break;
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
super.onTouchEvent(ev);
//Log.i("CustomScrollView", "onTouchEvent. action: " + ev.getAction() );
return true;
}
}
Затем в xml
<com.app.ui.views.CustomScrollView
android:id="@+id/scrollView"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:orientation="vertical">
</com.app.ui.views.CustomScrollView>
Если xml beffore не работает, измените это...
<com.myproyect.myapp.CustomScrollView
android:id="@+id/idScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:descendantFocusability="beforeDescendants"
>
</com.myproyect.myapp.CustomScrollView>
как использовать программный файл
CustomScrollView myScrollView = (CustomScrollView) findViewById(R.id.idScrollView);
Ответ 3
Мое предложение - использовать более легкую версию карты google при работе с этой ситуацией. это разрешило мою проблему.
добавить этот атрибут в фрагмент.
map:liteMode="true"
и моя проблема решена.
Я также добавил customScrollView в дополнение к этому. но после размещения свойства liteMode моя проблема решена.
Ответ 4
Пожалуйста, обратитесь к этому ответу:
fooobar.com/questions/117234/...
Он создает прозрачное представление с таким же размером mapFragment, в той же позиции, что и mapFragment, а затем вызывает requestDisallowInterceptTouchEvent (true), не позволяя его предкам перехватывать события касания.
Добавьте прозрачный вид фрагмента mapview :
<ScrollView>
...
<FrameLayout
android:layout_width="match_parent"
android:layout_height="300dp">
<FrameLayout
android:id="@+id/fl_google_map"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- workaround to make google map scrollable -->
<View
android:id="@+id/transparent_touch_panel"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</ScrollView>
Настройте сенсорный слушатель для этого прозрачного вида:
var transparentTouchPanel = view.FindViewById (Resource.Id.transparent_touch_panel);
transparentTouchPanel.SetOnTouchListener (this);
....
public bool OnTouch (View v, MotionEvent e) {
switch (e.Action) {
case MotionEventActions.Up:
v.Parent.RequestDisallowInterceptTouchEvent (false);
break;
default:
v.Parent.RequestDisallowInterceptTouchEvent (true);
break;
}
return false;
}
Я думал, что RequestDisallowInterceptTouchEvent может работать с вызовом только один раз, но, очевидно, его нужно вызывать для КАЖДОГО события касания, поэтому его нужно поместить в onTouchEvent. И родитель передаст этот запрос родительскому родителю.
Я попытался установить прослушиватель событий касания для fl_google_map или для mapFragment.getView(). Ни один из них не сработал, поэтому создание прозрачного представления о сестре - приемлемый обходной путь для меня.
Я пробовал, это решение работает отлично. Проверьте комментарии под оригинальным сообщением, если вы мне не верите. Я предпочитаю этот способ, потому что не нужно создавать пользовательские SupportMapFragmet.
Ответ 5
Обновить
Ответ Алока Наира очень хорош, однако метод.getMap() больше не работает с android 9.2 и далее. Измените метод getMap на.getMapAsync и добавьте код в метод onMapReady
Обновленное решение, которое работает во фрагментах
if (gMap == null)
{
getChildFragmentManager().findFragmentById(R.id.map);
SupportMapFragment mapFragment = (WorkaroundMapFragment) getChildFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(new OnMapReadyCallback()
{
@Override
public void onMapReady(GoogleMap googleMap)
{
gMap = googleMap;
gMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
gMap.getUiSettings().setZoomControlsEnabled(true);
mScrollView = mView.findViewById(R.id.advertScrollView); //parent scrollview in xml, give your scrollview id value
((WorkaroundMapFragment) getChildFragmentManager().findFragmentById(R.id.map))
.setListener(new WorkaroundMapFragment.OnTouchListener()
{
@Override
public void onTouch()
{
mScrollView.requestDisallowInterceptTouchEvent(true);
}
});
}
});
}
Ответ 6
Как Android Document,
Вы можете добавить так:
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="3"
android:orientation="horizontal" >
<fragment
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
</ScrollView>