2017-12-28 32 views
1

私のプロジェクトでgoogle mapsを使用しています。マーカーが画面に表示されていない場合は、矢印を画面に表示します。どうすれば画面を制御できますか?Googleマップスクリーンコントロール

+0

なぜ矢印を追加しますか? –

+0

マーカーの方向を表示したい(マーカーが右矢印に表示されている場合) –

+1

カメラの中心の緯度、経度を取得し、マーカーの方向を取得します。角度に基づいて、地図の上に右、左、上、下の矢印を重ねることができます。 –

答えて

0

実際、質問の回答はlakshman.pasalaコメントですが、その実装はやや複雑です(TLDR)。

Googleマップのスクリーンコントロールを取得する最も良い方法は、MapViewクラスを拡張するimplement custom viewです。その場合は、ビューキャンバス上で描画を完全に制御できます。これを行うには、MapViewFrameLayoutViewGroup)に拡張されているため、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からこの方法でそれを使用することができますあなたがshoul結果

<?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> 

activity_main.xmlはのようにすることができ

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(); 
    } 

} 

dは次のようになります。

Arrow to marker