내 프로젝트에 google maps
을 사용하고 있습니다. 마커가 화면에 나타나지 않으면 화살표를 화면에 놓고 싶습니다. 어떻게 화면을 제어 할 수 있습니까?Google지도 화면 제어
1
A
답변
0
실제로 질문에 대한 답변은 lakshman.pasala 개의 댓글이지만 구현은 조금 복잡합니다 (TLDR).
Google지도 스크린 컨트롤을 얻는 가장 좋은 방법은 MapView
클래스 인 implement custom view입니다. 이 경우 뷰 캔버스에서 그림을 완전히 제어 할 수 있습니다. 이를 수행하려면 MapView
이 FrameLayout
인 ViewGroup
까지 확장되어 있기 때문에 dispatchDraw()
메서드를 무시하고 해당 화살표 드로잉 내에 구현해야합니다. 뭐 그런 :
@Override
public void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
canvas.save();
drawArrowToMarker(canvas);
canvas.restore();
}
하고 모든 맵 이동/확대/회전에 invalidate()
를 통해 그것을 호출해야합니다. 지도 이동/확대/축소를 감지하려면 GoogleMap
(정확히 GoogleMap.setOnCameraMoveListener()
메쏘드)가 필요합니다. 사용자 지정 MapView 클래스 내에 GoogleMap
개체를 선언하고 setter를 통해 설정할 수 있지만 사용자 지정 MapView 클래스가 OnMapReadyCallback
인터페이스를 구현하고 onMapReady()
콜백에 있으면 더 좋습니다. 세그먼트 교차점을 결정, 추가/마커를 제거 또한 당신의 필요 여러 유틸리티 방법, 방향 등 사용자 지정보기의 전체 소스 코드 (예 : EnhanchedMapView
)은 같이 할 수있다 :
public class EnhanchedMapView extends MapView implements OnMapReadyCallback {
private final static int ARROW_PADDING = 50;
private final static double ARROW_ANGLE = Math.PI/6;
private final static double ARROW_LENGTH = 100;
private final static double ARROW_SIZE = 50;
private OnMapReadyCallback mMapReadyCallback;
private GoogleMap mGoogleMap;
private Marker mMarker;
private Paint mPaintArrow;
public EnhanchedMapView(@NonNull Context context) {
super(context);
init();
}
public EnhanchedMapView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public EnhanchedMapView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public EnhanchedMapView(@NonNull Context context, @Nullable GoogleMapOptions options) {
super(context, options);
init();
}
@Override
public void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
canvas.save();
drawArrowToMarker(canvas);
canvas.restore();
}
private void drawArrowToMarker(Canvas canvas) {
if (mGoogleMap == null || mMarker == null) {
return;
}
VisibleRegion visibleRegion = mGoogleMap.getProjection().getVisibleRegion();
LatLngBounds screenBounds = visibleRegion.latLngBounds;
LatLng mapCenter = screenBounds.getCenter();
Projection mapProjection = mGoogleMap.getProjection();
final Point pointMapCenter = mGoogleMap.getProjection().toScreenLocation(mapCenter);
final Point pointTopLeft = mapProjection.toScreenLocation(visibleRegion.farLeft);
final Point pointTopRight = mapProjection.toScreenLocation(visibleRegion.farRight);
final Point pointBottomLeft = mapProjection.toScreenLocation(visibleRegion.nearLeft);
final Point pointBottomRight = mapProjection.toScreenLocation(visibleRegion.nearRight);
final Point pointMarker = mapProjection.toScreenLocation(mMarker.getPosition());
final Point tl = new Point(pointTopLeft.x + ARROW_PADDING, pointTopLeft.y + ARROW_PADDING);
final Point tr = new Point(pointTopRight.x - ARROW_PADDING, pointTopRight.y + ARROW_PADDING);
final Point br = new Point(pointBottomRight.x - ARROW_PADDING, pointBottomRight.y - ARROW_PADDING);
final Point bl = new Point(pointBottomLeft.x + ARROW_PADDING, pointBottomLeft.y - ARROW_PADDING);
final Point pointIntersection = getBoundsIntersection(tl, tr, br, bl, pointMapCenter, pointMarker);
if (pointIntersection != null) {
double angle = Math.atan2(pointMarker.y - pointMapCenter.y, pointMarker.x - pointMapCenter.x);
int arrowX, arrowY;
arrowX = (int) (pointIntersection.x - ARROW_LENGTH * Math.cos(angle));
arrowY = (int) (pointIntersection.y - ARROW_LENGTH * Math.sin(angle));
canvas.drawLine(pointIntersection.x, pointIntersection.y, arrowX, arrowY, mPaintArrow);
arrowX = (int) (pointIntersection.x - ARROW_SIZE * Math.cos(angle + ARROW_ANGLE));
arrowY = (int) (pointIntersection.y - ARROW_SIZE * Math.sin(angle + ARROW_ANGLE));
canvas.drawLine(pointIntersection.x, pointIntersection.y, arrowX, arrowY, mPaintArrow);
arrowX = (int) (pointIntersection.x - ARROW_SIZE * Math.cos(angle - ARROW_ANGLE));
arrowY = (int) (pointIntersection.y - ARROW_SIZE * Math.sin(angle - ARROW_ANGLE));
canvas.drawLine(pointIntersection.x, pointIntersection.y, arrowX, arrowY, mPaintArrow);
}
}
private void init() {
setWillNotDraw(false);
mPaintArrow = new Paint();
mPaintArrow.setColor(Color.BLUE);
mPaintArrow.setStrokeWidth(15);
}
@Override
public void getMapAsync(OnMapReadyCallback callback) {
mMapReadyCallback = callback;
super.getMapAsync(this);
}
@Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
@Override
public void onCameraMove() {
invalidate();
}
});
if (mMapReadyCallback != null) {
mMapReadyCallback.onMapReady(googleMap);
}
}
public void addMarker(MarkerOptions markerOptions) {
removeMarker();
mMarker = mGoogleMap.addMarker(markerOptions);
}
public void removeMarker() {
mGoogleMap.clear();
}
private static boolean floatEquals(float f1, float f2) {
final double EPS = 1e-6;
return (Math.abs(f1 - f2) < EPS);
}
private static Point getBoundIntersection(Point p11, Point p12, Point p21, Point p22) {
double x, y;
Point intersectionPoint = null;
// test intersection with vertical bound
if (floatEquals(p12.x, p11.x) || floatEquals(p22.x, p21.x)) {
if (floatEquals(p12.x, p11.x) && floatEquals(p22.x, p21.x) && !floatEquals(p11.x, p21.x)) {
return null;
} else {
if (floatEquals(p12.x, p11.x)) {
x = p11.x;
y = (x - p21.x)/(p22.x - p21.x) * (p22.y - p21.y) + p21.y;
if (x >= Math.min(p21.x, p22.x) && x <= Math.max(p21.x, p22.x)
&& y >= Math.min(p11.y, p12.y) && y <= Math.max(p11.y, p12.y)) {
intersectionPoint = new Point((int) x, (int) y);
}
} else {
x = p21.x;
y = (x - p11.x)/(p12.x - p11.x) * (p12.y - p11.y) + p11.y;
if (x >= Math.min(p11.x, p12.x) && x <= Math.max(p11.x, p12.x)
&& y >= Math.min(p21.y, p22.y) && y <= Math.max(p21.y, p22.y)) {
intersectionPoint = new Point((int) x, (int) y);
}
}
}
} else {
// test intersection with horizontal bound
if (floatEquals(p12.y, p11.y) || floatEquals(p22.y, p21.y)) {
if (floatEquals(p12.y, p11.y) && floatEquals(p22.y, p21.y) && !floatEquals(p11.y, p21.y)) {
return null;
} else {
if (floatEquals(p12.y, p11.y)) {
y = p12.y;
x = (y - p21.y)/(p22.y - p21.y) * (p22.x - p21.x) + p21.x;
if (x >= Math.min(p11.x, p12.x) && x <= Math.max(p11.x, p12.x)
&& y >= Math.min(p21.y, p22.y) && y <= Math.max(p21.y, p22.y)) {
intersectionPoint = new Point((int) x, (int) y);
}
} else {
y = p21.y;
x = (y - p11.y)/(p12.y - p11.y) * (p12.x - p11.x) + p11.x;
if (x >= Math.min(p21.x, p22.x) && x <= Math.max(p21.x, p22.x)
&& y >= Math.min(p11.y, p12.y) && y <= Math.max(p11.y, p12.y)) {
intersectionPoint = new Point((int) x, (int) y);
}
}
}
}
}
return intersectionPoint;
}
private static Point getBoundsIntersection(Point tl, Point tr, Point br, Point bl, Point p1, Point p2) {
Point intersectionPoint = null;
if ((intersectionPoint = getBoundIntersection(tl, tr, p1, p2)) != null) {
return intersectionPoint;
} else if ((intersectionPoint = getBoundIntersection(tr, br, p1, p2)) != null) {
return intersectionPoint;
} else if ((intersectionPoint = getBoundIntersection(br, bl, p1, p2)) != null) {
return intersectionPoint;
} else if ((intersectionPoint = getBoundIntersection(bl, tl, p1, p2)) != null) {
return intersectionPoint;
}
return null;
}
}
그리고 당신은 MainActivity
이 방법에서 사용할 수 있습니다 : 당신은 말아야 결과
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="{YOUR_PACKAGE_NAME}.MainActivity">
<{YOUR_PACKAGE_NAME}.EnhanchedMapView
android:id="@+id/mapview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</RelativeLayout>
:
public class MainActivity extends AppCompatActivity {
private static final String MAP_VIEW_BUNDLE_KEY = "MapViewBundleKey";
static final LatLng KYIV = new LatLng(50.450311, 30.523730);
private EnhanchedMapView mMapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Bundle mapViewBundle = null;
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle(MAP_VIEW_BUNDLE_KEY);
}
mMapView = (EnhanchedMapView) findViewById(R.id.mapview);
mMapView.onCreate(mapViewBundle);
mMapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(GoogleMap googleMap) {
mMapView.addMarker(new MarkerOptions().position(KYIV).title("Kyiv"));
}
});
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Bundle mapViewBundle = outState.getBundle(MAP_VIEW_BUNDLE_KEY);
if (mapViewBundle == null) {
mapViewBundle = new Bundle();
outState.putBundle(MAP_VIEW_BUNDLE_KEY, mapViewBundle);
}
mMapView.onSaveInstanceState(mapViewBundle);
}
@Override
protected void onResume() {
super.onResume();
mMapView.onResume();
}
@Override
protected void onStart() {
super.onStart();
mMapView.onStart();
}
@Override
protected void onStop() {
super.onStop();
mMapView.onStop();
}
@Override
protected void onPause() {
mMapView.onPause();
super.onPause();
}
@Override
protected void onDestroy() {
mMapView.onDestroy();
super.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mMapView.onLowMemory();
}
}
activity_main.xml
처럼가 될 수 있습니다
왜 화살표를 추가 하시겠습니까 : 그런 뭔가를 얻을 거라고? –
마커 방향을 표시하고 싶습니다. (마커가 오른쪽 화살표로 표시되면 오른쪽에 나타납니다) –
카메라 중심의 위도와 경도를 가져 와서 마커 방향을 얻습니다. 각도에 따라지도 상단에 오른쪽, 왼쪽, 위쪽, 아래쪽 화살표를 중첩 할 수 있습니다. –