新しい Google Maps API v2 でマップ タッチをインターセプトする方法の例が見つかりません。
スレッドを停止するために、ユーザーがいつマップにタッチしたかを知る必要があります (現在の場所を中心にマップをセンタリングします)。
新しい Google Maps API v2 でマップ タッチをインターセプトする方法の例が見つかりません。
スレッドを停止するために、ユーザーがいつマップにタッチしたかを知る必要があります (現在の場所を中心にマップをセンタリングします)。
@ape は、マップのクリックをインターセプトする方法についてここに回答を書きましたが、タッチをインターセプトする必要があります。その後、回答のコメントで次のリンクを提案しました。.
その解決策は可能な回避策のようですが、提案されたコードは不完全でした。このため、書き直してテストしたところ、動作するようになりました。
ここに作業コードがあります:
クラス MySupportMapFragment.java を作成しました
import com.google.android.gms.maps.SupportMapFragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class MySupportMapFragment extends SupportMapFragment {
public View mOriginalContentView;
public TouchableWrapper mTouchView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
mOriginalContentView = super.onCreateView(inflater, parent, savedInstanceState);
mTouchView = new TouchableWrapper(getActivity());
mTouchView.addView(mOriginalContentView);
return mTouchView;
}
@Override
public View getView() {
return mOriginalContentView;
}
}
クラス TouchableWrapper.java も作成しました。
import android.content.Context;
import android.view.MotionEvent;
import android.widget.FrameLayout;
public class TouchableWrapper extends FrameLayout {
public TouchableWrapper(Context context) {
super(context);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
MainActivity.mMapIsTouched = true;
break;
case MotionEvent.ACTION_UP:
MainActivity.mMapIsTouched = false;
break;
}
return super.dispatchTouchEvent(event);
}
}
レイアウトでは、次のように宣言します。
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mapFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_below="@+id/buttonBar"
class="com.myFactory.myApp.MySupportMapFragment"
/>
メインのアクティビティでのテストのために、次のことだけを書きました。
public class MainActivity extends FragmentActivity {
public static boolean mMapIsTouched = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
ユーザーの選択に基づいて場所を取得する簡単なソリューションを次に示します (マップ上のオプションをクリックします)。
googleMap.setOnMapClickListener(new OnMapClickListener() {
@Override
public void onMapClick(LatLng arg0) {
// TODO Auto-generated method stub
Log.d("arg0", arg0.latitude + "-" + arg0.longitude);
}
});
レイアウトの MapFragment の上に空の FrameLayout を重ねて作成しました。次に、このビューに onTouchListener を設定して、いつマップがタッチされたかを認識しますが、タッチがマップに渡されるように false を返します。
<FrameLayout
android:id="@+id/map_touch_layer"
android:layout_width="match_parent"
android:layout_height="match_parent" />
mapTouchLayer.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Utils.logDebug(TAG, "Map touched!");
timeLastTouched = System.currentTimeMillis();
return false; // Pass on the touch to the map or shadow layer.
}
});
Gauchoには素晴らしい答えがあり、多くの賛成票を見て、別の実装が必要かもしれないと思いました:
リスナーを使用するために必要だったので、タッチで反応でき、常にチェックする必要がありません。
次のように使用できる 1 つのクラスにすべてを入れます。
mapFragment.setNonConsumingTouchListener(new TouchSupportMapFragment.NonConsumingTouchListener() {
@Override
public void onTouch(MotionEvent motionEvent) {
switch (motionEvent.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
// map is touched
break;
case MotionEvent.ACTION_UP:
// map touch ended
break;
default:
break;
// use more cases if needed, for example MotionEvent.ACTION_MOVE
}
}
});
mapfragment は TouchSupportMapFragment タイプである必要があり、レイアウト xml では次の行が必要です。
<fragment class="de.bjornson.maps.TouchSupportMapFragment"
...
クラスは次のとおりです。
package de.bjornson.maps;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.google.android.gms.maps.SupportMapFragment;
public class TouchSupportMapFragment extends SupportMapFragment {
public View mOriginalContentView;
public TouchableWrapper mTouchView;
private NonConsumingTouchListener mListener;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
mOriginalContentView = super.onCreateView(inflater, parent, savedInstanceState);
mTouchView = new TouchableWrapper(getActivity());
mTouchView.addView(mOriginalContentView);
return mTouchView;
}
@Override
public View getView() {
return mOriginalContentView;
}
public void setNonConsumingTouchListener(NonConsumingTouchListener listener) {
mListener = listener;
}
public interface NonConsumingTouchListener {
boolean onTouch(MotionEvent motionEvent);
}
public class TouchableWrapper extends FrameLayout {
public TouchableWrapper(Context context) {
super(context);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (mListener != null) {
mListener.onTouch(event);
}
return super.dispatchTouchEvent(event);
}
}
}
このリンクを参照してください。インターフェースを実装し、onMapClick()
メソッドまたは必要なものを入力onMapClickListener
して、適切な実装に設定します。
public class YourActivity extends Activity implements OnMapClickListener {
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
...
my_map.setOnMapClickListener(this)
...
}
public void onMapClick (LatLng point) {
// Do Something
}
}
// Initializing
markerPoints = new ArrayList<LatLng>();
// Getting reference to SupportMapFragment of the activity_main
SupportMapFragment sfm = (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);
// Getting Map for the SupportMapFragment
map = sfm.getMap();
// Enable MyLocation Button in the Map
map.setMyLocationEnabled(true);
// Setting onclick event listener for the map
map.setOnMapClickListener(new OnMapClickListener() {
@Override
public void onMapClick(LatLng point) {
// Already two locations
if(markerPoints.size()>1){
markerPoints.clear();
map.clear();
}
// Adding new item to the ArrayList
markerPoints.add(point);
// Creating MarkerOptions
MarkerOptions options = new MarkerOptions();
// Setting the position of the marker
options.position(point);
if(markerPoints.size()==1){
options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
}else if(markerPoints.size()==2){
options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
}
// Add new marker to the Google Map Android API V2
map.addMarker(options);
// Checks, whether start and end locations are captured
if(markerPoints.size() >= 2){
LatLng origin = markerPoints.get(0);
LatLng dest = markerPoints.get(1);
//Do what ever you want with origin and dest
}
}
});
モノ愛好家のために:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Widget;
using Android.Gms.Maps;
namespace apcurium.MK.Booking.Mobile.Client.Controls
{
public class TouchableMap : SupportMapFragment
{
public View mOriginalContentView;
public TouchableWrapper Surface;
public override View OnCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)
{
mOriginalContentView = base.OnCreateView(inflater, parent, savedInstanceState);
Surface = new TouchableWrapper(Activity);
Surface.AddView(mOriginalContentView);
return Surface;
}
public override View View
{
get
{
return mOriginalContentView;
}
}
}
public class TouchableWrapper: FrameLayout {
public event EventHandler<MotionEvent> Touched;
public TouchableWrapper(Context context) :
base(context)
{
}
public TouchableWrapper(Context context, IAttributeSet attrs) :
base(context, attrs)
{
}
public TouchableWrapper(Context context, IAttributeSet attrs, int defStyle) :
base(context, attrs, defStyle)
{
}
public override bool DispatchTouchEvent(MotionEvent e)
{
if (this.Touched != null)
{
this.Touched(this, e);
}
return base.DispatchTouchEvent(e);
}
}
}
とは異なる、より単純なソリューションがありTouchableWrapper
、これは の最新バージョンで動作しplay-services-maps:10.0.1
ます。このソリューションでは、マップ イベントのみを使用し、カスタム ビューは使用しません。非推奨の機能は使用せず、複数のバージョンをサポートする可能性があります。
最初に、マップがアニメーションまたはユーザー入力によって移動されているかどうかを格納するフラグ変数が必要です (このコードは、アニメーションによってトリガーされないすべてのカメラの動きがユーザーによってトリガーされることを前提としています)。
GoogleMap googleMap;
boolean movedByApi = false;
フラグメントまたはアクティビティはGoogleMap.OnMapReadyCallback
、 を実装する必要があります。GoogleMap.CancelableCallback
public class ActivityMap extends Activity implements OnMapReadyCallback, GoogleMap.CancelableCallback{
...
}
onMapReady
これにより、メソッド、、、onFinish
を実装する必要がありますonCancel
。また、 の googleMap オブジェクトはonMapReady
、カメラ移動用のイベント リスナーを設定する必要があります
@Override
public void onMapReady(GoogleMap mMap) {
//instantiate the map
googleMap = mMap;
[...] // <- set up your map
googleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
@Override
public void onCameraMove() {
if (movedByApi) {
Toast.makeText(ActivityMap.this, "Moved by animation", Toast.LENGTH_SHORT).show();
[...] // <-- do something whe you want to handle api camera movement
} else {
Toast.makeText(ActivityMap.this, "Moved by user", Toast.LENGTH_SHORT).show();
[...] // <-- do something whe you want to handle user camera movement
}
}
});
}
@Override
public void onFinish() {
//is called when the animation is finished
movedByApi = false;
}
@Override
public void onCancel() {
//is called when the animation is canceled (the user drags the map or the api changes to a ne position)
movedByApi = false;
}
最後に、マップを移動するための一般的な関数を作成すると、より良い結果が得られます
public void moveMapPosition(CameraUpdate cu, boolean animated){
//activate the flag notifying that the map is being moved by the api
movedByApi = true;
//if its not animated, just do instant move
if (!animated) {
googleMap.moveCamera(cu);
//after the instant move, clear the flag
movedByApi = false;
}
else
//if its animated, animate the camera
googleMap.animateCamera(cu, this);
}
または、マップを移動するたびに、アニメーションの前にフラグをアクティブにします
movedByApi = true;
googleMap.animateCamera(cu, this);
これが役立つことを願っています!