Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/google-maps/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-apps-script/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用Google Maps for Android V2处理地图移动结束?_Android_Google Maps_Android Mapview_Google Maps Android Api 2 - Fatal编程技术网

如何使用Google Maps for Android V2处理地图移动结束?

如何使用Google Maps for Android V2处理地图移动结束?,android,google-maps,android-mapview,google-maps-android-api-2,Android,Google Maps,Android Mapview,Google Maps Android Api 2,我想在地图中心更改后立即对地址进行地理编码 我如何使用新的Android V2谷歌地图处理地图移动端?(我在谈论这个案例,然后用户用手指拖动地图)我会尝试一个。每次摄影机移动完成时,都会调用侦听器。侦听器还将为您提供新位置。在我的测试中,在拖动过程中经常调用侦听器,也许有更好的解决方案。以下是确定拖动开始和拖动结束事件的可能解决方法: 您必须扩展SupportMapFragment或MapFragment。在onCreateView中,您必须将地图视图包装在自定义的框架布局中(在下面的示例中,它

我想在地图中心更改后立即对地址进行地理编码


我如何使用新的Android V2谷歌地图处理地图移动端?(我在谈论这个案例,然后用户用手指拖动地图)

我会尝试一个。每次摄影机移动完成时,都会调用侦听器。侦听器还将为您提供新位置。在我的测试中,在拖动过程中经常调用侦听器,也许有更好的解决方案。

以下是确定拖动开始和拖动结束事件的可能解决方法:

您必须扩展SupportMapFragment或MapFragment。在onCreateView中,您必须将地图视图包装在自定义的框架布局中(在下面的示例中,它是“TouchableWrapper”类),在该类中,您可以截取触摸事件并识别地图是否被点击。如果调用了“onCameraChange”,只需检查是否按下了地图视图(在下面的示例中,这是变量“mMapIsTouched”)

示例代码:

更新1:

  • 返回在getView()中创建的原始视图
  • 使用dispatchTouchEvent()而不是onInterceptTouchEvent()
自定义框架布局:

private class TouchableWrapper extends FrameLayout {

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mMapIsTouched = true;
                break;
            case MotionEvent.ACTION_UP:
                mMapIsTouched = false;
                break;
        }

        return super.dispatchTouchEvent(ev);

    }

}
在自定义的MapFragment中:

@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;
}
在相机更改回调方法中:

private final OnCameraChangeListener mOnCameraChangeListener = 
        new OnCameraChangeListener() {

    @Override
    public void onCameraChange(CameraPosition cameraPosition) {
        if (!mMapIsTouched) {
            refreshClustering(false);
        }
    }
};

过时的改用新的地图API。请参阅朋克斯塔的答案

在使用了上面AZ13的解决方案之后,遇到了评论中提到的问题,我创建了以下解决方案,它更可靠地解决了问题。但是,由于我在onRelease事件之后使用计时器来确定贴图是否仍在动画中,因此此解决方案中有一点延迟

可通过以下链接在Github上找到代码:

我的解决方案可通过以下方式从活动中使用:

new MapStateListener(mMap, mMapFragment, this) {
  @Override
  public void onMapTouched() {
    // Map touched
  }

  @Override
  public void onMapReleased() {
    // Map released
  }

  @Override
  public void onMapUnsettled() {
    // Map unsettled
  }

  @Override
  public void onMapSettled() {
    // Map settled
  }
};

我认为地图中的onclick事件是:map.setonmaclick。。。
但是事件拖动是:map.onCameraChangeListener,因为我在这两个函数中调用了log.e,它显示为onClick视图和onDrag视图。因此,只需为您使用它们。

从play services maps 9.4.0开始,您可以简单地使用
GoogleMap.OnCameraMoveStartedListener
GoogleMap.OnCameraMoveListener
GoogleMap.onCameradleListener

如果出于某种原因,您希望使用现在已弃用的旧API,则可以使用
onCamerachenglistener
。但你必须意识到两件事:

  • 当您拖动地图时,
    onCameraChange()
    可能会被多次调用,或者仅被调用一次(当拖动停止时)
  • 上次调用
    onCameraChange()
    时的相机位置可能与最终相机位置略有不同
  • 以下代码考虑了这两个问题:

    private static final int MESSAGE_ID_SAVE_CAMERA_POSITION = 1;
    private static final int MESSAGE_ID_READ_CAMERA_POSITION = 2;
    private CameraPosition lastCameraPosition;
    private Handler handler;
    private GoogleMap googleMap;
    
    public void onMapReady(GoogleMap theGoogleMap) {
        googleMap = theGoogleMap;
    
        handler = new Handler() {
            public void handleMessage(Message msg) {
                if (msg.what == MESSAGE_ID_SAVE_CAMERA_POSITION) {
                    lastCameraPosition = googleMap.getCameraPosition();
                } else if (msg.what == MESSAGE_ID_READ_CAMERA_POSITION) {
                    if (lastCameraPosition.equals(googleMap.getCameraPosition())) {
                        Log.d(LOG, "Camera position stable");
                    }
                }
            }
        };
    
        googleMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
            @Override
            public void onCameraChange(CameraPosition cameraPosition) {
                handler.removeMessages(MESSAGE_ID_SAVE_CAMERA_POSITION);
                handler.removeMessages(MESSAGE_ID_READ_CAMERA_POSITION);
                handler.sendEmptyMessageDelayed(MESSAGE_ID_SAVE_CAMERA_POSITION, 300);
                handler.sendEmptyMessageDelayed(MESSAGE_ID_READ_CAMERA_POSITION, 600);
            }
        });
    }
    

    基于Tobus answer的Xamarin Android中具有处理程序内部类的增强解决方案:

    public void OnMapReady(GoogleMap googleMap)
    {
            _googleMap = googleMap;
    
            if (_googleMap != null)
            {
                _cameraPositionHandler = new CameraPositionlHandler(_googleMap);
    
                _googleMap.CameraChange += OnCameraChanged; 
    
            }
    }
    
    void OnCameraChanged (object sender, GoogleMap.CameraChangeEventArgs e)
    {   
        _cameraPositionHandler.RemoveMessages(MESSAGE_ID_SAVE_CAMERA_POSITION);
        _cameraPositionHandler.RemoveMessages(MESSAGE_ID_READ_CAMERA_POSITION);                 
        _cameraPositionHandler.SendEmptyMessageDelayed(MESSAGE_ID_SAVE_CAMERA_POSITION, 300);
        _cameraPositionHandler.SendEmptyMessageDelayed(MESSAGE_ID_READ_CAMERA_POSITION, 600);
    
    }
    
    具有以下内部类:

        private class CameraPositionlHandler :  Handler 
        {
            private CameraPosition _lastCameraPosition;
            private GoogleMap _googleMap;
    
            public CameraPositionlHandler (GoogleMap googleMap)
            {
                _googleMap = googleMap;
            }
    
            public override void HandleMessage(Message msg) 
            {
                if (_googleMap != null) 
                {
                    if (msg.What == MESSAGE_ID_SAVE_CAMERA_POSITION) {
                        _lastCameraPosition = _googleMap.CameraPosition;
                    } else if (msg.What == MESSAGE_ID_READ_CAMERA_POSITION) {
                        if (_lastCameraPosition.Equals(_googleMap.CameraPosition)) {
                            Console.WriteLine("Camera position stable");
                            //do what you want
                        }
                    }
                }
            }
        }
    

    查看新的地图api

     @Override
    public void onMapReady(GoogleMap map) {
        mMap = map;
    
        mMap.setOnCameraIdleListener(this);
        mMap.setOnCameraMoveStartedListener(this);
        mMap.setOnCameraMoveListener(this);
        mMap.setOnCameraMoveCanceledListener(this);
    
        // Show Sydney on the map.
        mMap.moveCamera(CameraUpdateFactory
                .newLatLngZoom(new LatLng(-33.87365, 151.20689), 10));
    }
    
    @Override
    public void onCameraMoveStarted(int reason) {
    
        if (reason == OnCameraMoveStartedListener.REASON_GESTURE) {
            Toast.makeText(this, "The user gestured on the map.",
                           Toast.LENGTH_SHORT).show();
        } else if (reason == OnCameraMoveStartedListener
                                .REASON_API_ANIMATION) {
            Toast.makeText(this, "The user tapped something on the map.",
                           Toast.LENGTH_SHORT).show();
        } else if (reason == OnCameraMoveStartedListener
                                .REASON_DEVELOPER_ANIMATION) {
            Toast.makeText(this, "The app moved the camera.",
                           Toast.LENGTH_SHORT).show();
        }
    }
    
    @Override
    public void onCameraMove() {
        Toast.makeText(this, "The camera is moving.",
                       Toast.LENGTH_SHORT).show();
    }
    
    @Override
    public void onCameraMoveCanceled() {
        Toast.makeText(this, "Camera movement canceled.",
                       Toast.LENGTH_SHORT).show();
    }
    
    @Override
    public void onCameraIdle() {
        Toast.makeText(this, "The camera has stopped moving.",
                       Toast.LENGTH_SHORT).show();
    }
    

    只要用户拖动地图,我就必须将标记设置为中心动画。我已经用Stas Shakirov的答案实现了它

    MapDragListenerFragment.class

    public class MapDragListenerFragment extends Fragment implements OnMapReadyCallback, GoogleMap.OnMapLoadedCallback {
    
        private Context mContext;
        private SupportMapFragment supportMapFragment;
        private Marker centerMarker;
        private LatLng mapCenterLatLng;
        private TextView tvLocationName;
        private Button btnFinalizeDestination;
        private GoogleMap mGoogleMap;
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            return inflater.inflate(R.layout.fragment_map_drag_listener, container, false);
        }
    
        @Override
        public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            mContext = getActivity();
    
            tvLocationName = (TextView) view.findViewById(R.id.tv_location_name);
        }
    
        @Override
        public void onActivityCreated(@Nullable Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
    
            FragmentManager fm = getActivity().getSupportFragmentManager();//getChildFragmentManager();//
            supportMapFragment = (SupportMapFragment) fm.findFragmentById(R.id.map_container);
            if (supportMapFragment == null) {
                //// FIXME: 2/13/2017 crashes at casting to TouchableMapFragment
                supportMapFragment = SupportMapFragment.newInstance();
                fm.beginTransaction().replace(R.id.map_container, supportMapFragment).commit();
            }
            supportMapFragment.getMapAsync(this);
    
        }
    
        @Override
        public void onMapReady(GoogleMap googleMap) {
    
            if (googleMap != null) {
                mGoogleMap = googleMap;
    
                centerMarker = mGoogleMap.addMarker(new MarkerOptions().position(mGoogleMap.getCameraPosition().target)
                        .title("Center of Map")
                        .icon(BitmapDescriptorFactory.fromResource(R.drawable.end_green)));
    
                mGoogleMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
                    @Override
                    public void onCameraIdle() {
                        mapCenterLatLng = mGoogleMap.getCameraPosition().target;
    
                        animateMarker(centerMarker,mapCenterLatLng,false);
    
                        Toast.makeText(mContext, "The camera has stopped moving.",
                                Toast.LENGTH_SHORT).show();
    
                        String address = getCompleteAddressString(mapCenterLatLng.longitude,mapCenterLatLng.longitude);
                        tvLocationName.setText(address);
                    }
                });
                mGoogleMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
                    @Override
                    public void onCameraMoveStarted(int reason) {
                        if (reason == GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE) {
                            ///tvLocationName.setText("Lat " + mapCenterLatLng.latitude + "  Long :" + mapCenterLatLng.longitude);
                            Toast.makeText(mContext, "The user gestured on the map.",
                                    Toast.LENGTH_SHORT).show();
                        } else if (reason == GoogleMap.OnCameraMoveStartedListener
                                .REASON_API_ANIMATION) {
                            Toast.makeText(mContext, "The user tapped something on the map.",
                                    Toast.LENGTH_SHORT).show();
                        } else if (reason == GoogleMap.OnCameraMoveStartedListener
                                .REASON_DEVELOPER_ANIMATION) {
                            Toast.makeText(mContext, "The app moved the camera.",
                                    Toast.LENGTH_SHORT).show();
                        }
                    }
                });
                mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
                    @Override
                    public void onCameraMove() {
                        Toast.makeText(mContext, "The camera is moving.",
                                Toast.LENGTH_SHORT).show();
                    }
                });
                mGoogleMap.setOnCameraMoveCanceledListener(new GoogleMap.OnCameraMoveCanceledListener() {
                    @Override
                    public void onCameraMoveCanceled() {
                        Toast.makeText(mContext, "Camera movement canceled.",
                                Toast.LENGTH_SHORT).show();
                    }
                });
    
                mapCenterLatLng = mGoogleMap.getCameraPosition().target;// it should be done on MapLoaded.
    
                if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) !=
                        PackageManager.PERMISSION_GRANTED &&
                        ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) !=
                                PackageManager.PERMISSION_GRANTED) {
                    return;
                }
                mGoogleMap.setMyLocationEnabled(true);
                mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(15));
    
                mGoogleMap.setOnMapLoadedCallback(this);
                mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
                    @Override
                    public void onCameraMove() {
    
                    }
                });
            }
        }
    
        public void animateMarker(final Marker marker, final LatLng toPosition,
                                  final boolean hideMarker) {
            final Handler handler = new Handler();
            final long start = SystemClock.uptimeMillis();
            Projection proj = mGoogleMap.getProjection();
            Point startPoint = proj.toScreenLocation(marker.getPosition());
            final LatLng startLatLng = proj.fromScreenLocation(startPoint);
             final long duration = 500;
            final Interpolator interpolator = new LinearInterpolator();
            handler.post(new Runnable() {
                @Override
                public void run() {
                    long elapsed = SystemClock.uptimeMillis() - start;
                    float t = interpolator.getInterpolation((float) elapsed
                            / duration);
                    double lng = t * toPosition.longitude + (1 - t)
                            * startLatLng.longitude;
                    double lat = t * toPosition.latitude + (1 - t)
                            * startLatLng.latitude;
                    marker.setPosition(new LatLng(lat, lng));
                    if (t < 1.0) {
                        // Post again 16ms later.
                        handler.postDelayed(this, 16);
                    } else {
                        if (hideMarker) {
                            marker.setVisible(false);
                        } else {
                            marker.setVisible(true);
                        }
                    }
                }
            });
        }
    }
    
    活动\u映射\u拖动\u侦听器.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1">
    
            <fragment
                android:id="@+id/map_container"
                android:name="com.google.android.gms.maps.SupportMapFragment"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
    
            <ImageView
                android:id="@+id/iv_center_overlay"
                android:layout_width="25dp"
                android:layout_height="25dp"
                android:visibility="gone"
                android:layout_centerInParent="true"
                android:src="@drawable/start_blue" />
        </RelativeLayout>
    
    
        <TextView
            android:id="@+id/tv_location_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="4dp"
            android:text="Location Name" />
    </LinearLayout>
    
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <Button
            android:id="@+id/btn_select_place"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Select Place" />
    
        <FrameLayout
            android:id="@+id/frame_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    </LinearLayout>
    
    
    


    最简单的方法是使用SetOnCameraideListener方法来处理地图片段上触摸侦听器的移动结束状态。 请参见下面的示例:

    mMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
        @Override
        public void onCameraMoveStarted(int i) {
            mapPin.startAnimation(animZoomOut);
        }
    });
    
    mMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
        @Override
        public void onCameraIdle() {
            mapPin.startAnimation(animZoomIn);
        }
    });
    

    onTouchEvent方法对你没有帮助?谷歌仍然没有这个内置的!疯狂..我发现了那个方法,但正如你说的,它经常开火。我只需要在用户停止拖动地图并将手指移开时进行地理编码。所以我似乎也需要自己来处理触摸。但是在新的地图api中没有onTouch处理程序。@AlexeyZakharov是对的,它被触发太频繁,导致动画被卡住。AZ13的答案非常好。嘿@Alexey Zakharov,请查看Google地图问题跟踪器上的线程:这是真的。不能保证在您确定ACTION\u UP事件后调用onCameraChanged()。无论如何,我也希望谷歌能尽快解决这个问题@AZ13我得到错误“类型MyMapFragment的getActivity()方法未定义”。你是如何声明MyMapFragment的?@AZ13我检查了你的实现,必须承认该事件仍然没有在每个地图移动中触发。查看.Nice,但实际上您不需要实现定制的框架布局,只需执行
    setOnTouchListener(newview.OnTouchListener())…
    在framelayout上,其中包含事件处理代码。此问题被标记为低质量,因为如果其长度和内容不正确。您能否添加一个解释,说明这是如何解决问题的,或者引用所使用的函数?对我来说似乎很好,这是对@Az13解决方案的一个很好的增强:)@Mads Frandsen,您可以分享如何将您的库与Marker setOnMarkerClickListener结合起来吗?我尝试使用您的库,当按下任何标记时,代码将始终在apsetled上执行fuction@simeh是的,我认为任何接触都将被视为未解决。在将其设置为“未结算”之前,您可能会检查是否有任何移动,这样可以避免只需单击一下就可以进行onMapsetled调用。如果您当时还没有解决问题,我可能会在这个周末或下个周末浏览我的(旧)代码。@Mads Frandsen,我将这个库与另一个检测单触的代码片段结合起来,设法解决了这个问题。谢谢你的回复,但是如果你能把它上传到Maven或者像jitpack.io一样,这样我们就可以在gradle上使用它了。完美的解决方案!
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <Button
            android:id="@+id/btn_select_place"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Select Place" />
    
        <FrameLayout
            android:id="@+id/frame_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    </LinearLayout>
    
     googleMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
            @Override
            public void onCameraIdle() {
               //Called when camera movement has ended, there are no pending animations and the user has stopped interacting with the map.
            }
     });
    
    mMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
        @Override
        public void onCameraMoveStarted(int i) {
            mapPin.startAnimation(animZoomOut);
        }
    });
    
    mMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
        @Override
        public void onCameraIdle() {
            mapPin.startAnimation(animZoomIn);
        }
    });