web-dev-qa-db-ja.com

スクロールビュー内で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
33
Malo

タッチイベントをオーバーライドできるように、カスタム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に更新された回答

100
Alok Nair

ただ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);
26

この回答を参照してください: 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を作成する必要がないので、この方法が好きです。

3
Chandler

私の提案は、この状況に対処するとき、グーグルマップのより軽いバージョンを使用することです。これで問題が解決しました。

この属性をフラグメントに追加します。

 map:liteMode="true"

そして私の問題は解決しました。これに加えてcustomScrollViewも追加しました。しかし、liteModeプロパティを配置した後、私の問題は解決しました。

3
Hammad Tariq

更新

@ 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);
                                }
                            });
                }
            });
        }
0
javacoder123