前回は、ちょっと一休みで軽い話題でしたが、いよいよ、高低図の表示に取りかかります。
alasixosaka.hatenablog.com
Viewを分割する
高低図を表示するために、まず地図の画面の下に高低図を表示する領域を作成する。まあ、なくても重ね書きすることもできるけど、見辛いので、専用の領域を作成することにしました。
レイアウトを変更
地図を表示しているレイアウトファイルは、rotatemapviewer.xmlなので、これを修正する。Viewを分割するには、LinearLayoutにViewを並べて、weightを設定するのがやり易そうだ。もとのViewはRelativeLayoutで作成されているので、こいつの外側にLinearLayoutを配置する。2つのViewは縦に配置するので、orientationはverticalにする。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="fill_parent" android:layout_width="fill_parent" android:orientation="vertical"> <RelativeLayout android:id="@+id/mainView" android:layout_width="fill_parent" android:layout_height="0dp" android:layout_weight="4">
そして、下側にcanvasを配置する。
高低図を書くやり方もいろいろ考えたがcanvasで書くことにした。mapsforgeのサンプルプログラムにdualmapviewerというのがあって2つの地図を表示できるみたいだ、こいつを使うという方法も考えた。だが、地図上にプロットしようとすると、経度、緯度で座標を入力する必要があり、計算が面倒になる。メリットとしては現在地を表示するのが楽になるという点。だが結局canvasを使う方法にすることにした。
2つの画面の大きさの比率は4:1にした。比率の設定はweightに値を入力するだけなので、楽に設定できる。
下の画面にcanvasを書くために、Paintviewという専用のクラスを作成し、レイアウトファイルを書き換える。mpf_rotaitonCはこのプロジェクトの名称。
</RelativeLayout> <com.example.mpf_rotationC.PaintView android:id="@+id/height" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> </LinearLayout>
rotatemapviewerが呼ばれるとpaintviewのonDrawが実行される。onDrawにグラフの枠と縦軸を書くようにした。まず、Paint paint = new Paint() でPaintをnewし、paint.setColor(Color.BLACK)で線の色を黒に指定。
paint.setStyle(Paint.Style.STROKE)で線を実線にし、paint.setStrokeWidth(3)で線の幅を指定する。
Canvasの幅と高さはそれぞれ、canvas.getWidth()、canvas.getHeight()で得ることができる。これを4分割して、ループでcanvas.drawLine() コマンドで線を引いた。また、外枠はcanvas.drawRect() コマンドで描いている。
public class PaintView extends View { public PaintView(Context context, AttributeSet attribute){ super(context,attribute); } @Override public void onDraw(Canvas canvas){ Paint paint = new Paint(); paint.setColor(Color.BLACK); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(3); int cheight = canvas.getHeight(); int cwidth = canvas.getWidth(); try { for (int i=0;i<4;i++){ canvas.drawLine(i*cwidth/4,0,i*cwidth/4,cheight,paint); } canvas.drawRect(new Rect(0, 0, cwidth, cheight), paint); }catch (Exception e){ Log.e("PaintView","error"); } } }
Canvasの外枠が画面の淵と重なってよくわからなくなっているが、画面はこんな感じになった。
ここに高低図と現在地を表示すれば完成になるが、書くのは簡単だが、そう簡単ではない。
高低図を書くやり方は次回にして、今回はレイアウトの勉強をしたついでに、メニュー画面のレイアウトもconstraintLayoutを使って書き直した。
ConstraintLayoutの詳細は参考サイトに詳しく書いてあるのでそちらを見て下さい。
今までは見映えより、実際の機能を搭載することを重視したので、メニュー画面についてはお世辞にも見映えが良い画面とは言えなかった。今回は、各ボタンが縦に均等に、かつ真ん中に配置するようにした。また、高低図を表示するかしないかを選択するラジオボタンを追加した。さらに、紛らわしい表現だった、GPSOn/OffのラジオボタンとRotationalViewのボタンの名称も変更し、それぞれRotateOn/OffとMap Viewとした。
ConstraintLayoutはそれぞれの部品の配置を相対的な制約によって記述するので、RelativeLayoutに似ている。違いは更に柔軟に記述ができるということだが、詳細に説明できるほど理解していないので、やったことだけを書いておく。
まず、一番上の"Map File Select"のボタンを基準点にした。幅は各ボタンのサイズを揃えるために200dpとしている。高さは”wrap content"で揃えた。
画面の一番上からのマージンを50dpとしている。左右は均等になるように(つまりセンタリングするために)、 app:layout_constraintEnd_toEndOf="parent"と app:layout_constraintStart_toStartOf="parent"としている。これは、画面の右端と左端とボタンをそれぞれ制約するということで、これでセンタリングになる。片側だけに制約をつけるとどちらかに寄った表示(つまり左寄せや右寄せ)になる。
また、各パーツを均等に配置するためにこの基準パーツにだけ、app:layout_constraintVertical_chainStyle="spread"としている。これで、各パーツが上下に均等に配置される。
2番目のパーツ”GPX File Select”ボタンは、上を先ほどのパーツ”Map File Select”で制約し、下を次のパーツ”POI File Select”で規定している。このようにして、各パーツを数珠つなぎにして記述すると、きれいに均等配置になった。
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerHorizontal="true"> <Button android:id="@+id/btMapFileSelect" android:layout_width="200dp" android:layout_height="wrap_content" android:layout_marginTop="50dp" android:text="@string/map_file_select" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_chainStyle="spread" /> <Button android:id="@+id/btGPXSelect" android:layout_width="200dp" android:layout_height="wrap_content" android:text="@string/gpx_file_select" app:layout_constraintBottom_toTopOf="@id/btPOISelect" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/btMapFileSelect" /> <Button android:id="@+id/btPOISelect" android:layout_width="200dp" android:layout_height="wrap_content" android:text="@string/poi_file_select" app:layout_constraintBottom_toTopOf="@id/btRotationalView" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/btGPXSelect" /> <Button android:id="@+id/btRotationalView" android:layout_width="200dp" android:layout_height="wrap_content" android:text="@string/RotationalView" app:layout_constraintBottom_toTopOf="@id/radiogroup" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/btPOISelect" /> <Button android:id="@+id/btSelectTheme" android:layout_width="200dp" android:layout_height="wrap_content" android:text="@string/select_theme" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/radiogroup" /> <RadioGroup android:id="@+id/radiogroup" android:layout_width="350dp" android:layout_height="wrap_content" android:background="#df7401" android:orientation="horizontal" android:paddingLeft="10dp" android:paddingTop="10dp" android:paddingRight="10dp" android:paddingBottom="10dp" app:layout_constraintBottom_toTopOf="@id/radiogroup2" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/btRotationalView"> <RadioButton android:id="@+id/rbOn" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:layout_marginLeft="25dp" android:layout_marginRight="25dp" android:background="#ffffff" android:text="@string/onGPS" /> <RadioButton android:id="@+id/rbOff" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:layout_marginLeft="25dp" android:layout_marginRight="25dp" android:background="#ffffff" android:text="@string/offGPS" /> </RadioGroup> <RadioGroup android:id="@+id/radiogroup2" android:layout_width="350dp" android:layout_height="80dp" android:background="#df7401" android:orientation="horizontal" android:paddingLeft="10dp" android:paddingTop="15dp" android:paddingRight="10dp" android:paddingBottom="0dp" app:layout_constraintBottom_toTopOf="@id/btSelectTheme" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/radiogroup"> <RadioButton android:id="@+id/rb2On" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:layout_marginLeft="25dp" android:layout_marginRight="25dp" android:layout_gravity="center_vertical" android:background="#ffffff" android:text="@string/on" /> <RadioButton android:id="@+id/rb2Off" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:layout_gravity="center_vertical" android:layout_marginLeft="25dp" android:layout_marginRight="25dp" android:background="#ffffff" android:text="@string/off" /> </RadioGroup> <TextView android:id="@+id/heightMap" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/heightMap" android:textColor="#3F51B5" android:textSize="18sp" android:textStyle="bold" app:layout_constraintStart_toStartOf="@id/radiogroup2" app:layout_constraintTop_toTopOf="@id/radiogroup2" tools:ignore="MissingConstraints" /> </android.support.constraint.ConstraintLayout>
参考にしたサイト
比率で幅や高さを指定する方法 - レイアウトの weight - ユーザーインターフェイス - Android 開発入門
AndroidのCanvasを使いこなす! – 基本的な描画 – PSYENCE:MEDIA
[Android] Custom Canvas をレイアウトに挿入する
XMLで始めるConstraintLayout - Qiita
[Android] ConstraintLayout レイアウト逆引きまとめ - Qiita