前回の記事ではFusedLocationProviderClient
を利用して、GPS測位位置を地図上に反映させました。しかしOsmdroidのサンプルをよく見ると、ライブラリの機能だけで現在位置を反映できるようです。
Osmdroidのライブラリの活用
Osmdroidのドキュメントを参考に
- 自位置の反映
- コンパス
- スケールバー
- 出典
- センターボタン
を実装します。
自位置の反映とフォロー
val locationOverlay = MyLocationNewOverlay(GpsMyLocationProvider(applicationContext), mapView)
locationOverlay.enableMyLocation()
locationOverlay.enableFollowLocation()
mapView.overlays.add(locationOverlay)
ライブラリでGPS測位位置を取得しているため、呼び出す前に別途パーミッションを得る必要があります。
enableMyLocation
は測位位置の表示、enableFollowLocation
は自位置をセンターにして自位置が変わった(移動した)場合、センターを追従します。
コンパス
val compassOverlay = CompassOverlay(applicationContext, InternalCompassOrientationProvider(applicationContext), mapView)
compassOverlay.enableCompass()
mapView.overlays.add(compassOverlay)
スケールバー
val scaleBar = ScaleBarOverlay(mapView) scaleBar.setAlignRight(true) scaleBar.setScaleBarOffset(100, 100) scaleBar.setTextSize(14 * this.resources.displayMetrics.density) mapView.overlays.add(scaleBar)
出典
val copyrightOverlay = CopyrightOverlay(applicationContext) copyrightOverlay.setAlignRight(true) copyrightOverlay.setTextSize(14) mapView.overlays.add(copyrightOverlay)
出典はXYTileSource
のcopyrightで指定した文字列が出力されます。
センターボタン
val centerMap = findViewById<ImageView>(R.id.center_map)
centerMap.setOnClickListener {
mapController.animateTo(locationOverlay.myLocation)
locationOverlay.enableFollowLocation()
}
地図を手動で動かすとフォローが解除されてしまうため、センターボタン押下時に再度フォローするようにしています。
activity_main.xml
<ImageView android:id="@+id/center_map" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="40dp" android:layout_marginBottom="40dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:srcCompat="@drawable/osm_ic_center_map" />
レイアウトにセンターボタンのイメージを追加します。オーバーレイで追加するのが正しい形なのかもしれません。でもそこまでするメリットはないような気もします。
実装結果とMainActivity.kt全体
自位置はデフォルトで人型です。
MyLocationNewOverlay#setPersonIcon(Bitmap icon)
で変更できるようです。
MainActivity.kt
import android.Manifest import android.content.pm.PackageManager import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.widget.ImageView import androidx.preference.PreferenceManager import androidx.appcompat.app.AlertDialog import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import org.osmdroid.config.Configuration import org.osmdroid.tileprovider.tilesource.XYTileSource import org.osmdroid.views.MapView import org.osmdroid.views.overlay.CopyrightOverlay import org.osmdroid.views.overlay.ScaleBarOverlay import org.osmdroid.views.overlay.compass.CompassOverlay import org.osmdroid.views.overlay.compass.InternalCompassOrientationProvider import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay class MainActivity : AppCompatActivity() { private val PERMISSION_REQUEST_CODE = 1000 private lateinit var mapView: MapView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Configuration.getInstance().load(applicationContext, PreferenceManager.getDefaultSharedPreferences(applicationContext)) setContentView(R.layout.activity_main) mapView = findViewById(R.id.mapview) val tileSource = XYTileSource("GSI", 5, 18, 256, ".png", arrayOf("https://cyberjapandata.gsi.go.jp/xyz/std/"), "地理院タイル")) mapView.setTileSource(tileSource) mapView.setMultiTouchControls(true) if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // パーミッション未許可 if(ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) { AlertDialog.Builder(this) .setMessage("ロケーションの権限が必要です。") .setPositiveButton("OK", ({_, _ -> ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), PERMISSION_REQUEST_CODE) })).show() } else { ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), PERMISSION_REQUEST_CODE) } } else { // パーミッション許可済 startActivity() } } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { when(requestCode) { PERMISSION_REQUEST_CODE -> { if((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) { startActivity() } else { finish() } } else -> { super.onRequestPermissionsResult(requestCode, permissions, grantResults) } } } private fun startActivity() { val mapController = mapView.controller mapController.setZoom(16.0) // スケールバー表示 val scaleBar = ScaleBarOverlay(mapView) scaleBar.setAlignRight(true) scaleBar.setScaleBarOffset(100, 100) scaleBar.setTextSize(14 * this.resources.displayMetrics.density) mapView.overlays.add(scaleBar) // コンパス表示 val compassOverlay = CompassOverlay(applicationContext, InternalCompassOrientationProvider(applicationContext), mapView) compassOverlay.enableCompass() mapView.overlays.add(compassOverlay) // 自位置表示 val locationOverlay = MyLocationNewOverlay(GpsMyLocationProvider(applicationContext), mapView) locationOverlay.enableMyLocation() locationOverlay.enableFollowLocation() mapView.overlays.add(locationOverlay) // センターボタン val centerMap = findViewById<ImageView>(R.id.center_map) centerMap.setOnClickListener { mapController.animateTo(locationOverlay.myLocation) // 地図を動かすとfollowがとまるので、センター押下時は再度followさせる locationOverlay.enableFollowLocation() } // 出典 val copyrightOverlay = CopyrightOverlay(applicationContext) copyrightOverlay.setAlignRight(true) copyrightOverlay.setTextSize(14) mapView.overlays.add(copyrightOverlay) } override fun onPause() { super.onPause() mapView.onPause() } override fun onResume() { super.onResume() mapView.onResume() } }