回転表示の見栄えを調整する(アンドロイド地図アプリの開発 その6)

今日は膝の状態を考えてチャリトレ。樫田から清阪峠を越えて安威川ダムの予定地を回る40km のコース。水曜日の状態を考えるとかなりきつい道のりになりそうと覚悟していましたが、思った以上に体が動いて、トレーニング不足の時はきつく感じる清阪峠もすいすい登れました。このぶんなら21日のレースも膝さえ持てばなんとかなりそう。
でもって、本日のお題のアプリ開発のお話しです。
早いもので、いつの間にか6回目です。連載状態になってきましたが、前回はようやく地図が回転表示できるようになったところまで書きました。
alasixosaka.hatenablog.com
ただ、前回の表示は、地図は回転できるもののスケールバーやズームイン、ズームアウトボタンが表示されないなど、ちょっと不満が残る形になっていました。
今回は、サンプルアプリに従ってプログラムを改造して、スケールバー、ズームイン、ズームアウトボタンを表示させます。ついでにrotateボタンが表示されますが、これは後々に消す予定です。
また、全画面表示に対応させました。

スケールバーの表示

まずレイアウトファイルを変更します。Activity_main_xmlに下記を追記します。

<com.example.mapsforgerotate5.MapScaleBarView
        android:id="@+id/mapScaleBarView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_marginLeft="5dp" />

ここで、最初の行はサンプルでは、

<org.mapsforge.samples.android.scalebar.MapScaleBarView

となっています。しかし、このままではエラーが出て動きません。
実は、mapsforge-samples-androidのsrcフォルダにscalebarというフォルダがあり、そこに2つのファイルMapScaleBarImpl.javaとMapScaleBarView.javaの2つのファイルがあります。後者のほうが、エラーに対応したファイルで、但し書きに、fix map rotation exampleの記述があります。ですので、このファイルを使うことにします。Andriod Studioで左のMainActivityにカーソルを持っていき右クリック New ー> Java Classで新規にjavaファイルを作成します。新規ファイル作成のダイアログが表示されたら、ファイル名をMapScaleBarViewとしてOKします。これで、ファイルが作成されました。中身は、先ほどのMapScaleBarViewをそのままコピーします。レイアウトファイルの最初の行はファイルの位置を示していますので、com.example.mapsforterotate5の部分はそれぞれのプログラムに応じて変更する必要があります。
また、同様にして、MapScaleBarImpl.javaも作成します。
次は、MainActivityです。
createMapViews()の最後に下記の部分を追記します。

// Use external scale bar
        mapView.getMapScaleBar().setVisible(false);
        MapScaleBarImpl mapScaleBar = new MapScaleBarImpl(
                mapView.getModel().mapViewPosition,
                mapView.getModel().mapViewDimension,
                AndroidGraphicFactory.INSTANCE, mapView.getModel().displayModel);
        mapScaleBar.setVisible(true);
        mapScaleBar.setScaleBarMode(DefaultMapScaleBar.ScaleBarMode.BOTH);
        mapScaleBar.setDistanceUnitAdapter(MetricUnitAdapter.INSTANCE);
        mapScaleBar.setSecondaryDistanceUnitAdapter(ImperialUnitAdapter.INSTANCE);
        MapScaleBarView mapScaleBarView = (MapScaleBarView) findViewById(R.id.mapScaleBarView);
        mapScaleBarView.setMapScaleBar(mapScaleBar);
        mapView.getModel().mapViewPosition.addObserver(mapScaleBarView);

これでスケールバーが表示されます。
次はボタンの設定です。

ボタンを表示し、設定する

まず、displaymap();のtryの最後の部分にcreateControls();を追記します。

try {
            createMapViews();
           ~省略~
            createControls();
        }catch (Exception e) {
            ~省略~

createControls()の本体は次のようになります。サンプルのRotationMapView.javaそのままコピーです。

//@Override
    protected void createControls() {
        Button rotateButton = (Button) findViewById(R.id.rotateButton);
        rotateButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                RotateView rotateView = (RotateView) findViewById(R.id.rotateView);
                rotateView.setHeading(rotateView.getHeading() - 45f);
                rotateView.postInvalidate();
            }
        });

        ImageButton zoomInButton = (ImageButton) findViewById(R.id.zoomInButton);
        zoomInButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mapView.getModel().mapViewPosition.zoomIn();
            }
        });

        ImageButton zoomOutButton = (ImageButton) findViewById(R.id.zoomOutButton);
        zoomOutButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mapView.getModel().mapViewPosition.zoomOut();
            }
        });
    }

rotateボタンとズームインボタン、ズームアウトボタンそれぞれにリスナ―を設定し、処理を書いています。回転は前回と同様に右45度です。というかこっちがオリジナルなんです。
次に、createMapViews()の最後に下記の部分を追記します。

// Use external scale bar
        ~省略~
        //mapView.setBuiltInZoomControls(hasZoomControls());
        mapView.setBuiltInZoomControls(false);
        //mapView.getMapZoomControls().setZoomLevelMin(getZoomLevelMin());
        mapView.getMapZoomControls().setZoomLevelMin((byte) 0);
        //mapView.getMapZoomControls().setZoomLevelMax(getZoomLevelMax());
        mapView.getMapZoomControls().setZoomLevelMax((byte) 24);
        //initializePosition(mapView.getModel().mapViewPosition);

どうも、MapViewにデフォルトのズームコントロールボタンはうまく表示できないので、ズームコントロールをデフォルトのものでなく新しく作ったものを使うよということのようです。コメントアウトしてあるのはサンプルファイルに書いてあった記述で、値をとってきているだけなので、書き換えてそのまま記入しています。すなわち、setBuiltInZoomControlsはfalse、setZoomLevelMinは0、setZoomLevelMaxは24。また、イニシャルポジションは別途設定しているのでコメントアウトしています。

地図を目いっぱい表示する

ボタンは表示されるようになりましたが、地図はなるべく大きくみたいので画面いっぱいに表示できるように変更します。
まず、レイアウトファイルにpaddingが記載されていたので削除します。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="16dp"       ~取る
    android:paddingLeft="16dp"     ~取る
    android:paddingRight="16dp"   ~取る
    android:paddingTop="16dp"     ~取る
    tools:context=".com.example.mapsforgeRotate4.MainActivity">

次に、ステータスバー、タイトルバー、ナビゲーションバーを非表示にしてみます。
MainActivityに次のオブジェクトを追記します。

private void stickyImmersiveMode(){
        View decorView = getWindow().getDecorView();
        decorView.setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                        | View.SYSTEM_UI_FLAG_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
        );

        decorView.setOnSystemUiVisibilityChangeListener
                (new View.OnSystemUiVisibilityChangeListener() {
                    @Override
                    public void onSystemUiVisibilityChange(int visibility) {
                        // Note that system bars will only be "visible" if none of the
                        // LOW_PROFILE, HIDE_NAVIGATION, or FULLSCREEN flags are set.
                        if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
                            Log.d("debug","The system bars are visible");
                        } else {
                            Log.d("debug","The system bars are NOT visible");
                        }
                    }
                });
    }

そして、AppCompactActivtyの代わりにActivityを使うためにimportの次の文をコメントアウトします。

//import android.support.v7.app.AppCompatActivity;

そして、MainActivityクラスの継承をAppCompatActivityからActivityに変更します。

public class MainActivity extends Activity

これでフルスクリーン表示になり、スワイプするとステータスバーとナビゲーションバーが半透明で現れ、しばらくするとまた消えます。

f:id:alasixOsaka:20190706170443j:plain
フルスクリーン表示
f:id:alasixOsaka:20190706170654j:plain
前回の表示
f:id:alasixOsaka:20190706171109j:plain
フリックするとバーが半透明で表示される
これで結構見栄えが良くなった。