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
タッチイベントをオーバーライドできるように、カスタム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);
}
}
}
上記のクラスでは、FrameLayoutを拡張するTouchableWrapperクラスを使用してタッチイベントをインターセプトします。地図を処理するメインアクティビティMyMapActivityにタッチイベントをディスパッチするカスタムリスナーOnTouchListenerもあります。 touchイベントが発生すると、dispatchTouchEventが呼び出され、リスナーmListenerがそれを処理します。
次に、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);
}
});
}
});
}
更新:@ javacoder123による回答に基づいてgetMapAsyncに更新された回答
ただ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が前に動作しなかった場合、これに変更...
<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);
この回答を参照してください: https://stackoverflow.com/a/17317176/48371
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を作成する必要がないので、この方法が好きです。
私の提案は、この状況に対処するとき、グーグルマップのより軽いバージョンを使用することです。これで問題が解決しました。
この属性をフラグメントに追加します。
map:liteMode="true"
そして私の問題は解決しました。これに加えてcustomScrollViewも追加しました。しかし、liteModeプロパティを配置した後、私の問題は解決しました。
更新
@ Alok Nair's 答えは非常に良いですが、.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);
}
});
}
});
}