Google Maps Android API v2-지도에서 터치 감지
새 Google Maps API v2에서지도 터치를 가로채는 방법에 대한 예를 찾을 수 없습니다.
스레드를 중지하기 위해 사용자가지도를 터치 할 때를 알아야합니다 (내 현재 위치를 중심으로지도 중심).
@ape는 여기에지도 클릭을 가로채는 방법에 대한 답변을 썼지 만 터치를 가로 채야합니다. 그런 다음 답변에 대한 댓글에서 다음 링크를 제안 했습니다. Google Map API v2에서지도에 대한 onTouch 이벤트를 처리하는 방법? .
이 솔루션이 가능한 해결 방법 인 것 같지만 제안 된 코드가 불완전했습니다. 이런 이유로 나는 그것을 다시 작성하고 테스트했으며 이제 작동합니다.
다음은 작동 코드입니다.
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);
}
});
이 기능과 더 많은 기능이 이제 지원됩니다. :)
이것은 개발자 노트 (문제 4636)입니다.
2016 년 8 월 릴리스에는 카메라 모션 시작, 진행 중 및 종료 이벤트에 대한 새로운 카메라 변경 리스너 세트가 도입되었습니다. 또한 사용자 제스처, 내장 API 애니메이션 또는 개발자 제어 움직임으로 인해 카메라가 움직이는 이유를 확인할 수 있습니다. 자세한 내용은 카메라 변경 이벤트 가이드를 참조 하세요 . https://developers.google.com/maps/documentation/android-api/events#camera-change-events
또한 출시 노트를 참조하세요 . https://developers.google.com/maps/documentation/android-api/releases#august_1_2016
다음은 문서 페이지의 코드 스 니펫입니다.
public class MyCameraActivity extends FragmentActivity implements
OnCameraMoveStartedListener,
OnCameraMoveListener,
OnCameraMoveCanceledListener,
OnCameraIdleListener,
OnMapReadyCallback {
private GoogleMap mMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_camera);
SupportMapFragment mapFragment =
(SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
@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();
}
}
레이아웃에서 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.
}
});
이 링크를 참조하십시오. 인터페이스를 구현하고 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
}
}
Gaucho는 훌륭한 답변을 가지고 있으며, 다른 구현이 필요하다고 생각한 많은 upvotes를 보았습니다.
리스너 를 사용하는 데 필요했기 때문에 터치에 반응하고 지속적으로 확인할 필요가 없었습니다.
다음과 같이 사용할 수있는 하나의 클래스에 모두 넣었습니다.
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);
}
}
}
// 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;
귀하의 fragament 또는 활동은 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);
이게 도움이 되길 바란다!
받아 들여진 답변에서 아이디어를 가져와 Kotlin으로 변환하고 터치 가능한 래퍼를 마크 업에 선언 할 수있는 생성자를 추가하고 터치 감지를위한 설정 가능한 콜백 속성을 사용하여 활동에 대한 결합을 직접 제거하여 개선했습니다. 더 쉽게 재사용 할 수 있습니다.
class TouchableWrapper : FrameLayout {
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
var onTouch: ((event :MotionEvent) -> Unit)? = null
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
onTouch?.invoke(event)
return super.dispatchTouchEvent(event)
}
}
그런 다음 레이아웃에서 :
<com.yourpackage.views.TouchableWrapper
android:id="@+id/viewMapWrapper"
android:layout_height="match_parent"
android:layout_width="match_parent">
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/map"
tools:context=".MapsActivity"
android:name="com.google.android.gms.maps.SupportMapFragment"/>
</com.yourpackage.views.TouchableWrapper>
그런 다음 다음과 같이 콜백을 설정합니다.
findViewById<TouchableWrapper>(R.id.viewMapWrapper)
.onTouch = {
if (MotionEvent.ACTION_DOWN == it.action) {
//Handle touch down on the map
}
}
@Gaucho MySupportMapFragment will obviously be used by some other fargment or activity(where there might be more view elements than the map fragment). So how can one dispatch this event to the next fragment where it is to be used. Do we need to write an interface again to do that?
참고URL : https://stackoverflow.com/questions/14013002/google-maps-android-api-v2-detect-touch-on-map
'developer tip' 카테고리의 다른 글
반환 유형별 오버로딩 (0) | 2020.11.03 |
---|---|
숭고한 텍스트 또는 다른 텍스트 편집기에서 모든 특수 악센트 문자를 강조 표시하는 방법이 있습니까? (0) | 2020.11.03 |
쿼리 작성기 또는 Eloquent를 사용하여 추가 조건이있는 조인 (0) | 2020.11.03 |
FontAwesome 아이콘의 글꼴 두께를 변경 하시겠습니까? (0) | 2020.11.03 |
java.util.Date 형식 변환 yyyy-mm-dd에서 mm-dd-yyyy로 (0) | 2020.11.03 |