ジェスチャー
利用開始の例からわかるように、マップ ビューでは、ピンチやダブルタップでズームインなど、一般的なすべてのマップジェスチャがデフォルトでサポートされています。 次の表に、使用可能なジェスチャと、マップ上の対応するデフォルトの動作の概要を示します。
| 1 本の指で画面をタップします。 このジェスチャには、定義済みのマップアクションがありません。 |
| 地図を一定の大きさでズームするには、 1 本の指で画面を 2 回タップします。 |
| 1 本の指を押して画面に移動します。 このジェスチャには、定義済みのマップアクションがありません。 |
| マップを移動 するには、 1 本の指を画面に合わせて押し続け、任意の方向に動かします。 指を持ち上げると、マップが少し勢いをつけて動き続けます。 |
| 地図を傾けるに は、 2 本の指を画面に合わせて押し続け、垂直方向に動かします。 他の方向の動作は事前に定義されていません。 |
| 一定の量をズームアウトするには、 2 本の指で画面をタップします。 |
| 連続的にズームインまたはズームアウトする には、 2 本の指を押したまま画面に移動し、その間の距離を増減します。 |
HERE SDK for Android では、次のジェスチャがサポートされています。
- タップ :
TapListener
- ダブルタップ :
DoubleTapListener
- 長押し :
LongPressListener
- パン :
PanListener
- 2 本指でパン :
TwoFingerPanListener
- 2 本指でタップ :
TwoFingerTapListener
- ピンチ回転 :
PinchRotateListener
各リスナーには、ユーザーが検出可能なアクション(特定のジェスチャの開始時や終了時など)を実行するたびに通知する専用のコールバックがあります。 通常は、ジェスチャが検出された後に、マップ マーカーを長押しした後に配置するなど、特定の動作をアプリケーションに追加します。
同じジェスチャには、一度に 1 つのリスナーのみを設定できます。
マップの操作を制御
リスナーを設定しても、ジェスチャのデフォルトのマップ動作には影響がありません。 個別に制御できます。 既定では、マップをダブルタップしたときのズームインなど、すべての既定の動作が有効になっています。
たとえば、次のように、ダブルタップ ( ズームイン ) および 2 本指タップ ( ズームアウト ) のデフォルトのマップジェスチャの動作を無効にできます。
mapView.getGestures().disableDefaultAction(GestureType.DOUBLE_TAP);
mapView.getGestures().disableDefaultAction(GestureType.TWO_FINGER_TAP);
既定のマップアクションを無効にしても、ジェスチャイベントをリッスンできます。 これは、例えば独自のズーム動作を実装するために、ジェスチャのデフォルトのアクションをオフにする場合に役立ちます。 タップと長押しを除くすべてのジェスチャで、デフォルトのマップアクションが提供されます。 詳細については、上の概要を参照してください。
デフォルトのマップジェスチャの動作を戻すには、次のように呼び出します。
mapView.getGestures().enableDefaultAction(GestureType.DOUBLE_TAP);
mapView.getGestures().enableDefaultAction(GestureType.TWO_FINGER_TAP);
ジェスチャーリスナーを添付
ジェスチャーリスナーをマップ ビューに添付する方法の例を見てみましょう。 マップ ビューでは、各ジェスチャに固有の setter が提供されています。 リスナーを設定するとすぐに、専用のコールバック (TapListener
の場合は onTap()
) を介して、そのジェスチャに関連するすべてのイベントを受信します。
private void setTapGestureHandler(MapViewLite mapView) {
mapView.getGestures().setTapListener(new TapListener() {
@Override
public void onTap(@NonNull Point2D touchPoint) {
GeoCoordinates geoCoordinates = mapView.getCamera().viewToGeoCoordinates(touchPoint);
Log.d(TAG, "Tap at: " + geoCoordinates);
}
});
}
リスナーを設定するとすぐに、ジェスチャが検出されたことを知らせる通知の受信が開始されます。
は touchPoint
、ジェスチャが発生したデバイスの画面からのポイントを指定します。 を呼び出すことで mapView.getCamera().viewToGeoCoordinates(touchPoint)
、ピクセルを地理座標に変換できます ( 上図を参照 ) 。
同様に、リスニングを停止するには、以下をコールします。
mapView.getGestures().setTapListener(null);
連続したジェスチャ ( 長押し、ピンチ、パン、 2 本の指のパンなど ) の場合 BEGIN
、ジェスチャの状態はジェスチャが検出されたことを示します。 指がディスプレイに触れている間に、指が持ち上げられたことを示すEND
状態になるまで、次のようなUPDATE
状態になることがあります。
private void setLongPressGestureHandler(MapViewLite mapView) {
mapView.getGestures().setLongPressListener(new LongPressListener() {
@Override
public void onLongPress(@NonNull GestureState gestureState, @NonNull Point2D touchPoint) {
GeoCoordinates geoCoordinates = mapView.getCamera().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);
}
}
});
}
たとえば、長押しのイベントが検出された後も、ユーザーが指を画面に置いたままにしたり、移動したりすることがあります。 ただし BEGIN
、長押しジェスチャが検出された時点でマークされるのはイベントのみです。
マップ上にマップ マーカーを配置する場合は、長押しのジェスチャが便利です。 この例については、アプリの検索 例を参照してください。
連続していないジェスチャ ( タップ、ダブルタップ、 2 本の指タップなど ) の 場合、ジェスチャイベントを処理するためにGestureState
は必要ありません。
チュートリアル : マップの操作をカスタマイズ
すでに確認したように、既定ではダブルタップジェスチャによって、都市レベルから通りのレベルに近い場所など、マップが個別のステップでズームされます。 このようなデフォルトのマップジェスチャアクションを無効にして独自のビヘイビアーを実装することも、既存のビヘイビアーに必要なアクションを追加することもできます。
必要に応じて、プラットフォームジェスチャ操作と HERE SDK ジェスチャ検出を組み合わせることもできます。 HERE SDK では、利便性のために、一般的な地図ジェスチャに重点を置いているため、すべての種類の低レベルのジェスチャイベントを提供するわけではありません。 より詳細な制御が必要な場合は、 HERE SDK で利用できるジェスチャ処理とネイティブの Android ジェスチャ検出をいつでも組み合わせることができます。
このチュートリアルで は、カスタムズームアニメーションを有効にする方法を示します。 ユーザー がダブルタップまたは 2 本の指でタップした後、マップが徐々に拡大または縮小されます。 ズームのアニメーションはしばらくすると遅くなります。
カスタムのズーム動作を追加
アニメーションから始めましょう。 このために、 Android の アニメーションフレームワーク と ValueAnimator
を使用して、特定の開始値と終了値の間で補間を行うことができます。
便宜上、GestureMapAnimator
という名前の新しいクラスを作成します。このクラスは、ジェスチャに関連するすべてのアニメーションを処理する必要があります。 マップをカメラでズームする必要があるため、マップのCamera
インスタンスへの参照が必要です。
既定では、地図は、途中のステップを使わずに、指が地図に触れる位置で、 1 つの個別のステップでズームイン / ズームアウトします。 このチュートリアルでは、既定のターゲットの場所でマップをズームする動作を単純化しますが、必要なアニメーションを紹介する中間ステップを追加します。 後で、指のタッチポイントでズームインする方法についても説明します。
必要なジェスチャイベントをフックしてみましょう。
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) {
gestureMapAnimator.zoomIn();
}
});
mapView.getGestures().setTwoFingerTapListener(new TwoFingerTapListener() {
@Override
public void onTwoFingerTap(@NonNull Point2D origin) {
gestureMapAnimator.zoomOut();
}
});
魔法のような HERE はありません 2 つのジェスチャイベントをリッスンするだけです。 既定のズーム動作を事前に無効にしておく必要があります。 上記の方法zoomIn()
およびzoomOut()
方法を使用すると、以下に示すGestureMapAnimator
新しい方法を利用できます。
public void zoomIn() {
startZoomAnimation(true);
}
public void zoomOut() {
startZoomAnimation(false);
}
新しい GestureMapAnimator
クラス内の実装では ValueAnimator
、次のものが使用されます。
private void startZoomAnimation(boolean zoomIn) {
stopAnimations();
zoomValueAnimator = createZoomValueAnimator(zoomIn);
zoomValueAnimator.start();
}
private ValueAnimator createZoomValueAnimator(boolean zoomIn) {
ValueAnimator zoomValueAnimator = ValueAnimator.ofFloat(0.1F, 0);
zoomValueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
zoomValueAnimator.addUpdateListener(animation -> {
float zoomVelocity = (float) animation.getAnimatedValue();
double zoom = camera.getZoomLevel();
zoom = zoomIn ? zoom + zoomVelocity : zoom - zoomVelocity;
camera.setZoomLevel(zoom);
});
long halfSecond = 500;
zoomValueAnimator.setDuration(halfSecond);
return zoomValueAnimator;
}
0.1 ValueAnimator
~ 0 の値を補間するには、を使用します。 これらの値によって、ズーム速度が決まります。 に AccelerateDecelerateInterpolator
は、中間値があり、最後にスローダウンの影響があります に設定したリスナー ValueAnimator
は zoomVelocity
、が 0 に達するまで定期的に実行 zoomVelocity
されます。は、マップのズームに使用できるアニメーション値です。 現在のズーム値を前のフレームから変更するには、引数として使用します。 zoomVelocity
ゆっくりと 0 に達すると、ズームステップのサイズが小さくなります。
地図を拡大または 縮小するかどうかを示すブール型値が提供されます。 これにより、両方のズームケースでコードを使用できます。 唯一の違い は、アニメーション化された値zoomVelocity
が現在のズーム レベルから追加または削除されることです。
上記のメソッドstopAnimations()
は、対応するインスタンス ValueAnimator
の進行中のアニメーションをキャンセルするだけです。
public void stopAnimations() {
if (zoomValueAnimator != null) {
zoomValueAnimator.cancel();
}
}
タッチポイントでズームインします
上の図では、タッチの原点を無視してカスタムの拡大動作を単純化しています。 マップは、指が画面に触れた位置でズームインするのが理想的です。 これを可能にする方法 既定では、すべてのプログラミングマップ操作は、マップ ビューを中心とするターゲットのアンカーポイントに基づいています。 そのため、地図は地図の中央の位置をズームします。 ターゲットの基準点の概念 HERE の詳細については、を参照してください。
このポイントを、指が画面に触れたポイントに変更するだけでかまいません。 その結果、マップをズームする呼び出しでは、この新しいアンカーポイントがターゲットとして使用されます。 ダブルタップジェスチャは Point2D
、タッチの起点を示すインスタンスをすでに提供しています。 ターゲットのアンカーポイントの変更は簡単です。ズームイン方法には、コードの行をさらに 1 行追加するだけで済みます。
public void zoomIn(MapViewLite mapView, Point2D touchPoint) {
camera.setTargetAnchorPoint(getAnchorPoint(mapView, touchPoint));
startZoomAnimation(true);
}
アンカーポイントは 、正規化 された座標で指定できます。 (0, 0) は、マップ ビューの左上隅と右下隅 (1,1) を示します。 反対に、ダブルタップジェスチャから送られたタッチポイントがマップ ビューのピクセル位置を提供しています。 これを行うには、次の方法で新しいアンカーを計算する必要があります。
private Anchor2D getAnchorPoint(MapViewLite mapView, Point2D mapViewPoint) {
float normalizedX = (float) ((1F / mapView.getWidth()) * mapViewPoint.x);
float normalizedY = (float) ((1F / mapView.getHeight()) * mapViewPoint.y);
Anchor2D transformationCenter = new Anchor2D(normalizedX, normalizedY);
return transformationCenter;
}
まず、マップ ビューのピクセルサイズを取得する必要があります。 次に、そのビューで正規化されたタッチポイントを計算して、新しい Anchor2D
インスタンスを構成します。 この新しいターゲットアンカーポイントを設定すると、マップがタッチした位置でスムーズにズームインされます。
ズームアウトは 2 本の指で行うため、地図の中央をターゲットとして使用してジェスチャを実行することをお勧めします。 そのため、アニメーションを停止するとき に 、必要に応じてアンカーポイントをデフォルトの位置にリセットすることができます。
camera.setTargetAnchorPoint(new Anchor2D(0.5F, 0.5F));
アプリケーションで別のアンカーポイントが必要な場合は、ズームアニメーションを開始する前に前のアンカーポイントを保存し、アニメーションが停止した後で元のアンカーポイントにリセットできます。 ターゲットのアンカーポイントによって、マップ ビューを基準にして新しい地図の場所が表示される場所も決まります。通常は、この場所がビューの中央にある必要があります。
これで、小旅行になりました。 上記のコードスニペットは、ご自身のニーズに合わせて自由に変更できます。 たとえば、さまざまな補間法、さまざまなアニメーション値、またはアニメーションのデュレーションを使用して再生を開始します。