地図を操作する
デフォルトでは、HERE SDKマップビューは、ピンチやダブルタップによるズームインなど、一般的なすべてのマップジェスチャーをサポートしています。以下の表に、使用できるジェスチャーとそれに対応する地図のデフォルト動作をまとめました。
![]() |
1 本の指で画面をタップします。このジェスチャーには事前定義されたマップアクションはありません。 |
![]() |
地図を一定の倍率でズーム インするには、1 本の指で画面を 2 回タップします。 |
![]() |
1本の指で画面をプレスアンドホールドします。このジェスチャーには事前定義されたマップアクションはありません。 |
![]() |
地図を移動させるには、画面を 1 本の指でプレス アンド ホールドしたまま、任意の方向に動かします。指を離した後も、地図は勢いで少し動き続けます。 |
![]() |
地図を傾斜させるには、2 本の指を画面にプレス アンド ホールドしたまま垂直に動かします。他の方向への動作は事前に定義されていません。 |
![]() |
一定の倍率でズーム アウトするには、2 本の指で画面をタップします。 |
![]() |
連続してズーム インまたはズーム アウトするには、2 本の指で画面をプレス アンド ホールドしたまま、指の間の距離を増減します。 地図を連続的に回転させるには、2 本の指を画面にプレス アンド ホールドして、両方の指を回転させるか一方の指を動かして、指の間の角度を変更します。 |
HERE SDK for Android では、次のジェスチャーがサポートされています。
- タップ:
TapListener - ダブル タップ:
DoubleTapListener - 長押し:
LongPressListener - パン:
PanListener - 2 本指のパン:
TwoFingerPanListener - 2 本指のタップ:
TwoFingerTapListener - ピンチによる回転:
PinchRotateListener
各リスナーには専用のコールバックがあり、検知可能なアクションをユーザーが実行するたびに通知します。たとえば、特定のジェスチャーの開始や終了などです。通常、長押しした後にマップ マーカーを配置するなど、ジェスチャーが検知された後にアプリケーションに特定の動作を追加する必要があります。
なお、同じジェスチャーに同時に設定できるリスナーは 1 つのみです。
ジェスチャー リスナーを実装する
ジェスチャー リスナーをマップ ビューに実装する方法の例を見てみましょう。マップ ビューでは、固有の setter が各ジェスチャーに用意されています。リスナーは、設定した直後からそのジェスチャーに関連するすべてのイベントを専用コールバック (たとえば、TapListener の場合は onTap()) 経由で受信します。
private void setTapGestureHandler(MapView mapView) {
mapView.getGestures().setTapListener(new TapListener() {
@Override
public void onTap(@NonNull Point2D touchPoint) {
GeoCoordinates geoCoordinates = mapView.viewToGeoCoordinates(touchPoint);
Log.d(TAG, "Tap at: " + geoCoordinates);
}
});
}
private fun setTapGestureHandler(mapView: MapView) {
mapView.gestures.tapListener = TapListener { touchPoint ->
val geoCoordinates = mapView.viewToGeoCoordinates(touchPoint)
Log.d(TAG, "Tap at: $geoCoordinates")
}
}
リスナーを設定するとすぐに、ジェスチャーが検出されるたびに通知の受信が開始されます。
touchPoint は、ジェスチャーが発生した MapView 座標を指定します。mapView.viewToGeoCoordinates(touchPoint) を呼び出すことで、ピクセルを地理座標に変換できます (上を参照)。
同様に、リッスンを停止するには以下を呼び出します。
mapView.getGestures().setTapListener(null);
mapView.getGestures().setTapListener(null)
連続ジェスチャー (長押し、ピンチ、パン、2 本指のパンなど) の場合、ジェスチャー状態 BEGIN はジェスチャーが検知されたことを示します。指が画面に触れている間は、指が離れたことを示す END 状態か、ジェスチャー検出がキャンセルされたことを示す CANCEL 状態になるまで、UPDATE 状態を受け取ることがあります。
private void setLongPressGestureHandler(MapView mapView) {
mapView.getGestures().setLongPressListener(new LongPressListener() {
@Override
public void onLongPress(@NonNull GestureState gestureState, @NonNull Point2D touchPoint) {
GeoCoordinates geoCoordinates = mapView.viewToGeoCoordinates(touchPoint);
if (gestureState == GestureState.BEGIN) {
Log.d(TAG, "LongPress detected at: " + geoCoordinates);
}
if (gestureState == GestureState.UPDATE) {
Log.d(TAG, "LongPress update at: " + geoCoordinates);
}
if (gestureState == GestureState.END) {
Log.d(TAG, "LongPress finger lifted at: " + geoCoordinates);
}
if (gestureState == GestureState.CANCEL) {
Log.d(TAG, "Map view lost focus. Maybe a modal dialog is shown or the app is sent to background.");
}
}
});
}
private fun setLongPressGestureHandler(mapView: MapView) {
mapView.gestures.longPressListener = LongPressListener { gestureState, touchPoint ->
val geoCoordinates = mapView.viewToGeoCoordinates(touchPoint)
if (gestureState == GestureState.BEGIN) {
Log.d(TAG, "LongPress detected at: $geoCoordinates")
}
if (gestureState == GestureState.UPDATE) {
Log.d(TAG, "LongPress update at: $geoCoordinates")
}
if (gestureState == GestureState.END) {
Log.d(TAG, "LongPress finger lifted at: $geoCoordinates")
}
if (gestureState == GestureState.CANCEL) {
Log.d(TAG, "Map view lost focus. Maybe a modal dialog is shown or the app is sent to background.")
}
}
}
たとえば、長押しイベントが検知された後、ユーザーは指を画面上に置いたままにしたり、指を動かしたりすることがあります。ただし、長押しジェスチャーが検知された時点をマークするのは BEGIN イベントのみです。
長押しジェスチャーは、地図にマップマーカーを配置する際に便利です。この例は「Search」サンプルアプリで確認できます。このサンプルアプリは、優先するプラットフォームのGitHubにあります。
なお、非連続ジェスチャー (タップ、ダブル タップ、2 本指のタップなど) の場合、ジェスチャー イベントの処理に GestureState は不要です。
注パン ジェスチャーがスワイプとなり、地図が動く可能性があります。ジェスチャーがすでに終了し、すべての指が離れているにもかかわらず、地図は動き続けます。地図の移動が終了したことを検知するには、
MapIdleListenerを使用できます。これはMapViewインスタンスから取得できるHereMapインスタンスに追加できます。ピンチによる回転ジェスチャーを開始すると、パンのジェスチャーはキャンセルされます。ピンチ回転ジェスチャー中に2本指のパン操作が検出されると、パンジェスチャーが開始され、パンとピンチ回転の両方のイベントが発生します。
コードスニペットとその他の使用法の例は、GitHubで「Gestures」サンプルアプリの一部として入手できます。
マップアクションを制御する
リスナーは設定してもジェスチャーのデフォルトの地図動作には影響がなく、独立して制御できます。デフォルトでは、地図をダブル タップしたときのズーム インなどの標準的な動作は、すべて有効になっています。
たとえば、ダブル タップ (ズーム イン) および 2 本指のタップ (ズーム アウト) のデフォルトのマップ ジェスチャー動作を無効にするには、次のようにします。
mapView.getGestures().disableDefaultAction(GestureType.DOUBLE_TAP);
mapView.getGestures().disableDefaultAction(GestureType.TWO_FINGER_TAP);
mapView.gestures.disableDefaultAction(GestureType.DOUBLE_TAP)
mapView.gestures.disableDefaultAction(GestureType.TWO_FINGER_TAP)
デフォルトのマップ アクションを無効にしても、ジェスチャー イベントをリッスンできます。これは、ジェスチャーのデフォルト アクションをオフにして独自のズーム動作を実装する場合などに役立ちます。タップと長押しを除くすべてのジェスチャーには、デフォルトのマップ アクションが用意されています。詳細については、上の概要を参照してください。
デフォルトのマップ ジェスチャー動作を戻すには、次の呼び出しを行います。
mapView.getGestures().enableDefaultAction(GestureType.DOUBLE_TAP);
mapView.getGestures().enableDefaultAction(GestureType.TWO_FINGER_TAP);
mapView.gestures.enableDefaultAction(GestureType.DOUBLE_TAP)
mapView.gestures.enableDefaultAction(GestureType.TWO_FINGER_TAP)
マップ アクションをカスタマイズする
すでに見てきたように、デフォルトでは、ダブル タップ ジェスチャーにより地図を非連続的にズーム インできます (市区町村レベルから番地レベルに近づくなど)。このようなデフォルトのマップ ジェスチャー アクションを無効にして、独自の動作を実装したり、既存の動作に必要なアクションを追加したりできます。
注必要に応じて、プラットフォームのジェスチャー処理と HERE SDK のジェスチャー検知を組み合わせることもできます。HERE SDK は、利便性を高めるために一般的なマップ ジェスチャーに重点を絞っているため、すべての種類の細かいジェスチャー イベントは用意していません。より詳細な制御が必要な場合は、HERE SDK で利用できるジェスチャー処理とネイティブの Android ジェスチャー検知をいつでも組み合わせることができます。
以下に、カスタム ズーム アニメーションを有効にする方法の例を示します。
カスタムズーム動作を追加する
このチュートリアルでは、マップのカスタム ズーム動作を実装する方法を説明します。具体的には、ユーザーがダブルタップまたは 2 本指のタップ ジェスチャーを実行した後、マップを徐々に拡大または縮小できるようにします。ズーム アニメーションは、しばらくするとスムーズに減速します。
アニメーションから始めましょう。このために、Android のアニメーション フレームワークおよび ValueAnimator を使用して、特定の開始値と終了値を補間できます。
便宜的に GestureMapAnimator という名前の新しいクラスを作成します。このクラスはジェスチャーに関連するすべてのアニメーションを処理します。地図はカメラを介してズームする必要があるため、地図の MapCamera インスタンスへの参照が必要です。
デフォルトでは、地図は指が地図に触れた位置で、1 つの非連続的なステップとしてズーム イン/outし、中間ステップはありません。
必要なジェスチャー イベントをつなげましょう。
mapView.getGestures().disableDefaultAction(GestureType.DOUBLE_TAP);
mapView.getGestures().disableDefaultAction(GestureType.TWO_FINGER_TAP);
mapView.getGestures().setDoubleTapListener(new DoubleTapListener() {
@Override
public void onDoubleTap(@NonNull Point2D touchPoint) {
// Start our custom zoom in animation.
gestureMapAnimator.zoomIn(touchPoint);
}
});
mapView.getGestures().setTwoFingerTapListener(new TwoFingerTapListener() {
@Override
public void onTwoFingerTap(@NonNull Point2D touchCenterPoint) {
// Start our custom zoom out animation.
gestureMapAnimator.zoomOut(touchCenterPoint);
}
});
// Disable the default map gesture behavior for DoubleTap (zooms in) and TwoFingerTap (zooms out)
// as we want to enable custom map animations when such gestures are detected.
mapView.gestures.disableDefaultAction(GestureType.DOUBLE_TAP)
mapView.gestures.disableDefaultAction(GestureType.TWO_FINGER_TAP)
private fun setDoubleTapGestureHandler(mapView: MapView) {
mapView.gestures.doubleTapListener = DoubleTapListener { touchPoint ->
// Start our custom zoom in animation.
gestureMapAnimator?.zoomIn(touchPoint)
}
}
private fun setTwoFingerTapGestureHandler(mapView: MapView) {
mapView.gestures.twoFingerTapListener = TwoFingerTapListener { touchCenterPoint ->
// Start our custom zoom out animation.
gestureMapAnimator?.zoomOut(touchCenterPoint)
}
}
内容は明瞭です。2 つのジェスチャー イベントをリッスンするのみです。デフォルトのズーム動作が事前に無効になっていることを確認する必要があります。上の zoomIn() および zoomOut() のメソッドは、以下に示す GestureMapAnimator の新しいメソッドにつながります。
// Starts the zoom in animation.
public void zoomIn(Point2D touchPoint) {
zoomOrigin = touchPoint;
startZoomAnimation(true);
}
// Starts the zoom out animation.
public void zoomOut(Point2D touchPoint) {
zoomOrigin = touchPoint;
startZoomAnimation(false);
}
// Starts the zoom in animation.
fun zoomIn(touchPoint: Point2D) {
zoomOrigin = touchPoint
startZoomAnimation(true)
}
// Starts the zoom out animation.
fun zoomOut(touchPoint: Point2D) {
zoomOrigin = touchPoint
startZoomAnimation(false)
}
地図のどこをズーム インまたはズーム アウトする必要があるかを知るために、zoomOrigin を保存しています。
新しい GestureMapAnimator クラス内の startZoomAnimation() の実装では、ValueAnimator を使用します。
private void startZoomAnimation(boolean zoomIn) {
stopAnimations();
// A new Animator that zooms the map.
zoomValueAnimator = createZoomValueAnimator(zoomIn);
// Start the animation.
zoomValueAnimator.start();
}
private ValueAnimator createZoomValueAnimator(boolean zoomIn) {
ValueAnimator zoomValueAnimator = ValueAnimator.ofFloat(0.1F, 0);
zoomValueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
zoomValueAnimator.addUpdateListener(animation -> {
// Called periodically until zoomVelocity is zero.
float zoomVelocity = (float) animation.getAnimatedValue();
double zoomFactor = 1;
zoomFactor = zoomIn ? zoomFactor + zoomVelocity : zoomFactor - zoomVelocity;
// zoomFactor values > 1 will zoom in and values < 1 will zoom out.
camera.zoomBy(zoomFactor, zoomOrigin);
});
long halfSecond = 500;
zoomValueAnimator.setDuration(halfSecond);
return zoomValueAnimator;
}
private fun startZoomAnimation(zoomIn: Boolean) {
stopAnimations()
// A new Animator that zooms the map.
zoomValueAnimator = createZoomValueAnimator(zoomIn)
// Start the animation.
zoomValueAnimator!!.start()
}
private fun createZoomValueAnimator(zoomIn: Boolean): ValueAnimator {
val zoomValueAnimator = ValueAnimator.ofFloat(0.1f, 0f)
zoomValueAnimator.interpolator = AccelerateDecelerateInterpolator()
zoomValueAnimator.addUpdateListener { animation: ValueAnimator ->
// Called periodically until zoomVelocity is zero.
val zoomVelocity = animation.animatedValue as Float
var zoomFactor = 1.0
zoomFactor = if (zoomIn) zoomFactor + zoomVelocity else zoomFactor - zoomVelocity
// zoomFactor values > 1 will zoom in and values < 1 will zoom out.
camera!!.zoomBy(zoomFactor, zoomOrigin!!)
}
val halfSecond: Long = 500
zoomValueAnimator.setDuration(halfSecond)
return zoomValueAnimator
}
ValueAnimator を使用して、0.1 から 0 までの値を補間します。これらの値によってズーム速度が決まります。AccelerateDecelerateInterpolator は中間値を提供し、最後に減速効果を与えます。ValueAnimator に設定したリスナーは、zoomVelocity が 0 に達するまで定期的に実行されます。zoomVelocity は、地図をズームするのに使用できるアニメーション値です。これを引数として使用してズーム率を設定します。zoomVelocity がゆっくりと 0 に近づくにつれて、結果のズーム ステップは小さくなります。
上では、zoomOriginに保存したタッチ原点を使用して、指が画面に触れたポイントにズームインします。ズーム アウトする場合、これは 2 本指のタップ ジェスチャーの間のポイントになります。次に、カメラの zoomBy() メソッドが非連続的なズーム ステップを指定された位置で実行します。
なお、ブール値を渡すことで、地図に対してズーム インまたはズーム アウトのどちらを行うかを示しています。これにより、どちらのズームの場合でもこのコードを使用できます。唯一の違いは、現在のズーム率に対してアニメーション値 zoomVelocity が加算または減算される点です。
ズーム率は、地図をどの程度ズーム インまたはズーム アウトするかを指定します。ズーム率が 1 の場合、現在のズーム レベルは変更されません。
上の stopAnimations() メソッドは、対応する ValueAnimator インスタンスの進行中のアニメーションを単純にキャンセルします。
public void stopAnimations() {
if (zoomValueAnimator != null) {
zoomValueAnimator.cancel();
}
}
fun stopAnimations() {
if (zoomValueAnimator != null) {
zoomValueAnimator!!.cancel()
}
}
それでは、説明はここまでです。上のコード スニペットは、ニーズに合わせて自由に変更してください。たとえば、さまざまな Interpolator、異なるアニメーション値、または異なるアニメーションの継続時間を使用して試してみましょう。
サンプルアプリを試す
上記のコードスニペットのほとんどは、「Gestures」サンプルアプリで利用できます。このサンプルアプリは、GitHubでお好みのプラットフォームのものを見つけることができます。
7 日前の更新

















