アンドロイド スマホのアプリの画面の表示の設定のXMLと、R.javaについて

 アンドロイド スマホのアプリでは画面の表示の設定のXMLをLinux Mintの場合は/home/◯◯◯/AndroidStudioProjects/◇◇◇/app/src/main/res/layout/ディレクトリに置かせます。


――――――――――――――――――――

/home/◯◯◯/AndroidStudioProjects/◇◇◇/app/src/main/res/layout/

――――――――――――――――――――

 ◯◯◯はLinux Mintのユーザー名です。

 ◇◇◇はユーザーが付けたAndroid Studioのプロジェクト名です。



 アンドロイド スマホのアプリでは、文字を表示するラベルやボタンなどの画面の部品をウィジェット(Widget)と呼びます。また、ウィジェット(Widget)をビュー(View)とも呼ぶようです。

 ただし、「Android ウィジェット」などで検索すると別の物まで引っかかってしまうので、「Android アプリ開発 ビュー」などで検索したほうが良いです。


 【既存の主なビュー(View)】

 ・テキスト ビュー(TextView) ……文字を表示するラベル

 ・オート コンプリート テキスト ビュー(AutoCompleteTextView)

 ・マルチ オート コンプリート テキスト ビュー(AutoCompleteTextView)

 ・イメージ ビュー(ImageView) ……画像の表示

 ・ビデオ ビュー(VideoView) ……動画の表示

 ・エディット テキスト(EditText) ……文字を入力できるテキスト ボックス

 ・ボタン(Button)

 ・イメージ ボタン(ImageButton)

 ・チェック ボックス(CheckBox)

 ・ラジオ ボタン(RadioButton)

 ・ラジオ グループ(RadioGroup)

 ・スピナー(Spinner) ……アダプターを設定すると、リスト ボックスにできる

 ・スクロール ビュー(ScrollView) ……ビューか下記のレイアウトを1つだけ縦スクロール可能にできる。2つ以上のビューを縦スクロール可能化する場合は2つ以上のビューを1つのレイアウトにまとめる。

 ・ホライゾンタル スクロール ビュー(HorizontalScrollView) ……横スクロール版のスクロール ビュー

 ・ウェブ ビュー(WebView) ……アプリ内ブラウザー。JavaScriptからアプリのActivityの処理を呼び出したりできる。ウェブ サイトとアプリの2つを提供する場合はウェブ ビューが有効の可能性が高いそうです。

 ・シーク バー(SeekBar)

 ・トグル ボタン(ToggleButton)

 ・レイティング バー(RatingBar)

 ・プログレス バー(ProgressBar)

 ・デート ピッカー(DatePicker)

 ・タイム ピッカー(TimePicker)

 ・デジタル クロック(DigitalClock)

 ・アナログ クロック(AnalogClock)

 ・クロノ メーター(Chronometer)

 ・リスト ビュー(ListView) …… 一覧表示。各行の一行分の一件分の画面の表示の設定は別のXMLファイルに書くようです。その別のXMLファイルの内容を設定するArrayAdapterのサブクラスを作成する事に成ります。アダプターと呼ばれる物のうち、ArrayAdapterを利用するのが一般的だそうです。

 ・チェックド テキスト ビュー(CheckedTextView)



 スクロール ビューの例

――――――――――――――――――――

<ScrollView

  android:layout_width="match_parent"

  android:layout_height="match_parent"

  android:fillViewport="true"

>

  <androidx.constraintlayout.widget.ConstraintLayout

    xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:app="http://schemas.android.com/apk/res-auto"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

  >

    <EditText

      android:id="@+id/editText"

      android:inputType="textMultiLine"

      android:layout_width="match_parent"

      android:layout_height="wrap_content"

      app:layout_constraintTop_toTopOf="parent"

      app:layout_constraintStart_toStartOf="parent"

      app:layout_constraintEnd_toEndOf="parent"

      app:layout_constraintBottom_toBottomOf="parent"

      app:layout_constraintHorizontal_bias="0.0"

      app:layout_constraintVertical_bias="0.0"

    >

      <requestFocus/>

    </EditText>

  </androidx.constraintlayout.widget.ConstraintLayout>

</ScrollView>

――――――――――――――――――――



 既存のビューは、そのままでは、指のジェスチャーのピンチ アウト、ピンチ イン、スクロールで拡大、縮小、移動しないので、拡大、縮小、移動させたい場合は、既存のビューを継承して自作する必要が有ります。

 ただし、ピンチ アウト、ピンチ イン、スクロールで拡大、縮小、移動するWebViewは簡単に自作できますが、ImageViewは難しいです。

 さて、Android Studioで、Kotlinで既存のビューを継承した物を自作すると、何もしなくても、画面の表示の設定のXMLで利用できます。

 例えば、既存のWebViewを継承してピンチ アウトとピンチ インで拡大縮小するZoomableWebView.ktを自作した場合、画面の表示の設定のXMLで「<WebView」という部分を「<◯◯◯.ZoomableWebView」に変更するだけです。

 ◯◯◯はKotlinのパッケージ名です。

 ちなみに、WebViewには拡大縮小のzoomIn()、zoomOut()という物が用意されています。



ピンチ アウト、ピンチ イン、スクロールで拡大、縮小、移動するWebViewの自作例

――――――――――――――――――――

package ◯◯◯


import android.content.Context

import android.util.AttributeSet

import android.view.MotionEvent

import android.view.ScaleGestureDetector

import android.webkit.WebView


class ZoomableWebView(

  context: Context,

  attributeSet: AttributeSet?,

  defaultStyleAttribute: Int,

  defaultStyleResourceId: Int

) : WebView(context, attributeSet, defaultStyleAttribute, defaultStyleResourceId), ScaleGestureDetector.OnScaleGestureListener {


  private val scaleGestureDetector = ScaleGestureDetector(context, this)


  private var lastScaleFactor = 1.0f


  constructor(context: Context, attributeSet: AttributeSet?, defaultStyleAttribute: Int) : this(context, attributeSet, defaultStyleAttribute, 0)

  constructor(context: Context, attributeSet: AttributeSet?) : this(context, attributeSet, 0, 0)

  constructor(context: Context) : this(context, null, 0, 0)


  override fun onTouchEvent(motionEvent: MotionEvent?): Boolean {

    scaleGestureDetector.onTouchEvent(motionEvent!!)

    return super.onTouchEvent(motionEvent)

  }


  override fun onScaleBegin(scaleGestureDetector: ScaleGestureDetector): Boolean {

    return true

  }


  override fun onScale(scaleGestureDetector: ScaleGestureDetector): Boolean {

    if ((lastScaleFactor / 0.05f).toInt() == (scaleGestureDetector.scaleFactor / 0.05f).toInt()) {

      return true

    }

    lastScaleFactor = scaleGestureDetector.scaleFactor


    //ピンチアウトの場合

    //

    //拡大の場合

    //

    if (1.0f < scaleGestureDetector.scaleFactor) {

      zoomIn()

    //ピンチインの場合

    //

    //縮小の場合

    //

    } else {

      zoomOut()

    }

    return true

  }


  override fun onScaleEnd(scaleGestureDetector: ScaleGestureDetector) {

  }

}

――――――――――――――――――――


――――――――――――――――――――

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

  android:orientation="vertical"

  android:layout_width="match_parent"

  android:layout_height="match_parent"

>

  <eliphas1810.bitflippedimageviewer.ZoomableWebView

    android:id="@+id/webView"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

  />

</LinearLayout>

――――――――――――――――――――



 ピンチ アウト、ピンチ イン、スクロールで拡大、縮小、移動するImageViewの自作例を書き残して置きますが、その自作のImageViewが複数の場合、複数のうち1つを拡大、縮小、移動すると他の物にも影響が及んでしまいました。


ピンチ アウト、ピンチ イン、スクロールで拡大、縮小、移動するImageViewの自作例

――――――――――――――――――――

package ◯◯◯


import android.content.Context

import android.graphics.Matrix

import android.util.AttributeSet

import android.view.GestureDetector

import android.view.MotionEvent

import android.view.ScaleGestureDetector

import androidx.appcompat.widget.AppCompatImageView



class ZoomableImageView(context: Context, attributeSet: AttributeSet?, defaultStyleAttribute: Int) : AppCompatImageView(context, attributeSet, defaultStyleAttribute), ScaleGestureDetector.OnScaleGestureListener {



  constructor(context: Context, attributeSet: AttributeSet?) : this(context, attributeSet, 0)

  constructor(context: Context) : this(context, null, 0)



  val scaleGestureDetector = ScaleGestureDetector(context, this)



  val simpleOnGestureListener = object : GestureDetector.SimpleOnGestureListener() {


    override fun onScroll(motionEvent1: MotionEvent, motionEvent2: MotionEvent, distanceX: Float, distanceY: Float): Boolean {


      val imageViewWidth = width

      val imageViewHeight = height


      val imageMatrixValues = FloatArray(9)

      imageMatrix.getValues(imageMatrixValues)


      val imageWidth = imageViewWidth * imageMatrixValues[Matrix.MSCALE_X]

      val imageHeight = imageViewHeight * imageMatrixValues[Matrix.MSCALE_Y]


      var x = 0.0f

      var y = 0.0f


      //縮小中の画像が画像ビューよりも小さい場合

      //

      //画像が画像ビューよりも小さい場合

      //

      if (imageWidth < imageViewWidth) {

        //画像を動かさない

        //x = 0.0f


      //拡大中の画像が画像ビューよりも大きい場合

      //

      //画像が画像ビューよりも大きい場合


      //画像の左端が画像ビューと画面よりも右に離れていて、更に指を左へ動かして、画像を逆方向の更に右へ動かそうとした場合

      } else if (distanceX < 0.0f && 0.0f < imageMatrixValues[Matrix.MTRANS_X]) {

        //画像を元にゼロに戻す

        x = 0.0f - imageMatrixValues[Matrix.MTRANS_X]


      //画像の右端が画像ビューと画面よりも左に離れていて、更に指を右へ動かして、画像を逆方向の更に左へ動かそうとした場合

      } else if ((imageWidth + imageMatrixValues[Matrix.MTRANS_X]) < imageViewWidth && 0.0f < distanceX) {


        //画像の右端を画像ビューと画面の右端に戻す

        //

        //画像の右端と、画像ビューと画面の右端の差分だけ戻す

        //

        x = imageViewWidth - (imageWidth + imageMatrixValues[Matrix.MTRANS_X])


      //その他の場合

      } else {

        //指で動かした分だけ逆方向へ動かす

        x = 0.0f - distanceX

      }


      //縮小中の画像が画像ビューよりも小さい場合

      //

      //画像が画像ビューよりも小さい場合

      //

      if (imageHeight < imageViewHeight) {

        //画像を動かさない

        //y = 0.0f


      //拡大中の画像が画像ビューよりも大きい場合

      //

      //画像が画像ビューよりも大きい場合


      //画像の上端が画像ビューと画面よりも下に離れていて、更に指を上へ動かして、画像を逆方向の更に下へ動かそうとした場合

      } else if (distanceY < 0.0f && 0.0f < imageMatrixValues[Matrix.MTRANS_Y]) {


        //画像を元にゼロに戻す

        y = 0.0f - imageMatrixValues[Matrix.MTRANS_Y]


      //画像の下端が画像ビューと画面よりも上に離れていて、更に指を下へ動かして、画像を逆方向の更に上へ動かそうとした場合

      } else if ((imageHeight + imageMatrixValues[Matrix.MTRANS_Y]) < imageViewHeight && 0.0f < distanceY) {


        //画像の下端を画像ビューと画面の下端に戻す

        //

        //画像の下端と、画像ビューと画面の下端の差分だけ戻す

        //

        y = imageViewHeight - (imageHeight + imageMatrixValues[Matrix.MTRANS_Y])


      //その他の場合

      } else {

        //指で動かした分だけ逆方向へ動かす

        y = 0.0f - distanceY

      }


      //画像を移動

      imageMatrix.postTranslate(x, y)


      //画像ビューの枠内の画像を再描画

      invalidate()


      return super.onScroll(motionEvent1, motionEvent2, distanceX, distanceY)

    }

  }



  val gestureDetector = GestureDetector(context, simpleOnGestureListener)



  val minScaleFactor = 0.5f



  override fun onTouchEvent(motionEvent: MotionEvent?): Boolean {

    gestureDetector.onTouchEvent(motionEvent!!)

    scaleGestureDetector.onTouchEvent(motionEvent!!)

    return true

  }


  override fun onScaleBegin(scaleGestureDetector: ScaleGestureDetector): Boolean {

    return true

  }


  override fun onScale(scaleGestureDetector: ScaleGestureDetector): Boolean {


    var scaleFactor = scaleGestureDetector.scaleFactor


    if (scaleFactor == 1.0f) {

      return true

    }


    if (scaleFactor < minScaleFactor) {

      scaleFactor = minScaleFactor

    }


    super.setScaleType(ScaleType.MATRIX)

    val imageMatrix = super.getImageMatrix()

    imageMatrix.postScale(scaleFactor, scaleFactor)

    super.setImageMatrix(imageMatrix)


    val layoutParams = super.getLayoutParams()

    layoutParams.width = (super.getWidth() * scaleFactor).toInt()

    layoutParams.height = (super.getHeight() * scaleFactor).toInt()

    super.setLayoutParams(layoutParams)


    return true

  }


  override fun onScaleEnd(scaleGestureDetector: ScaleGestureDetector) {

  }

}

――――――――――――――――――――



 アンドロイド スマホのアプリでは、文字を表示するラベルやボタンなどの画面の部品であるビュー(View)の並べ方をレイアウト(Layout)と呼びます。XMLではビューのタグをレイアウトのタグで囲む事に成ります。


 【既存の主なレイアウト(Layout)】

 ・リニア レイアウト(LinearLayout) …画面の部品であるビューを縦に並べるか、横に並べます。

 ・フレーム レイアウト(FrameLayout) …XMLの上から順に、先の物の上に後の物を重ね合わせて表示していきます。

 ・リラティブ レイアウト(RelativeLayout) …画面の部品であるビューを画面の端、画面の中央、別のビューの上下左右などに相対的な位置指定で並べます。

 ・コンストレイント レイアウト(ConstraintLayout) …リラティブ レイアウト(RelativeLayout)に似ています。リラティブ レイアウトよりも柔軟に画面の部品であるビューを配置できるそうです。

 ・テーブル レイアウト(TableLayout) …ウェブページのHTMLのtableタグのように格子こうし状に画面の部品であるビューを配置できます。ただし、複数の行や複数の列をまたぐ事はできないそうです。

 ・グリッド レイアウト(GridLayout) …格子こうし状に画面の部品であるビューを配置できます。テーブル レイアウト(TableLayout)とは違い、複数の列をまたぐ事などができるそうです。


 コンストレイント レイアウト(ConstraintLayout)では、画面やビューの上の辺をトップ(Top)、左の辺をスタート(Start)、右の辺をエンド(End)、下の辺をボトム(Bottom)と呼びます。

 最も下のビュー以外のビューは、そのトップが画面のトップか他のビューのボトムに対応している事と、そのスタートが画面のスタートか他のビューのエンドに対応している事と、そのエンドが画面のエンドか他のビューのスタートに対応している事を書きます。

 そして、ビューは対応関係の中間に配置されるので、左のビューを左上に寄せる場合は、水平のバイアスと、垂直のバイアスを0.0に設定します。右下に寄せる場合は1.0に設定します。中間は0.5です。


 コンストレイント レイアウト(ConstraintLayout)の例

――――――――――――――――――――

<androidx.constraintlayout.widget.ConstraintLayout

  xmlns:android="http://schemas.android.com/apk/res/android"

  xmlns:app="http://schemas.android.com/apk/res-auto"

  android:layout_width="match_parent"

  android:layout_height="match_parent"

>


  <TextView

    android:id="@+id/fileName"

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:text=""

    app:layout_constraintTop_toTopOf="parent"

    app:layout_constraintStart_toStartOf="parent"

    app:layout_constraintEnd_toEndOf="parent"

  />


  <Button

    android:id="@+id/readButton"

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:text="@string/read"

    app:layout_constraintTop_toBottomOf="@id/fileName"

    app:layout_constraintStart_toStartOf="parent"

  />


  <Button

    android:id="@+id/saveButton"

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:text="@string/save"

    app:layout_constraintTop_toBottomOf="@id/fileName"

    app:layout_constraintStart_toEndOf="@id/readButton"

    app:layout_constraintEnd_toEndOf="parent"

  />


  <EditText

    android:id="@+id/text"

    android:inputType="textMultiLine"

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    app:layout_constraintTop_toBottomOf="@id/readButton"

    app:layout_constraintStart_toStartOf="parent"

    app:layout_constraintEnd_toEndOf="parent"

    app:layout_constraintBottom_toBottomOf="parent"

    app:layout_constraintHorizontal_bias="0.0"

    app:layout_constraintVertical_bias="0.0"

  >

    <requestFocus/>

  </EditText>


</androidx.constraintlayout.widget.ConstraintLayout>

――――――――――――――――――――



 ウェブページのHTMLのCSSのようにマージンやパディングといった余白や、文字の色や背景の色や、右寄せなども指定できます。



 アンドロイド スマホのアプリの画面の表示の設定のXMLのタグのandroid:layout_width属性やandroid:layout_height属性の属性値のmatch_parentは画面の最大や、格納してくれている親要素の画面の部品の中での最大を意味します。


――――――――――――――――――――

android:layout_width="match_parent"

android:layout_height="match_parent"

――――――――――――――――――――



 アンドロイド スマホのアプリの画面の表示の設定のXMLのタグのandroid:layout_width属性やandroid:layout_height属性の属性値のwrap_contentは内容に合わせた大きさを意味します。例えば、文字を表示するラベルであるテキスト ビュー(TextView)では文字を全て十分に表示できる大きさを意味します。


――――――――――――――――――――

android:layout_width="wrap_content"

android:layout_height="wrap_content"

――――――――――――――――――――



 ちなみに、「dp」という単位を付けて数値で指定する方法も有るようです。



 ちなみに、文字の大きさ、フォント サイズを指定する場合は「sp」という単位を利用するようです。



 アンドロイド スマホのアプリの画面の表示の設定のXMLで、文字を表示するラベルやボタンなどの画面の部品であるビュー(View)に、唯一に特定するための名前であるidを付ける事ができます。Android Studioは自動でXMLファイルを解析してR.javaファイルを作成してくれるので、Kotlinなどのプログラムの中でR.idのidの名前のメンバーとしてidを参照する事ができます。それにより、名前の指定を誤ってしまった時にコンパイル エラーと成るので、気づく事ができます。

 Android StudioにJavaやKotlinなどのプログラムのコードをコピペして、「import android.R」が自動で追加されてしまったら、削除してください。

 「android.R」は、「R.layout.activity_main」や「R.id.◯◯◯」の「R」とは違います。

 そのため、「import android.R」が有ると、コンパイル エラーが発生してしまいます。



 各画面のボタンなどの各部品のidの全てが、1つの「R.id」に同列でまとめられます。

 そのため、各画面の各部品のidは「画面の名前 + 部品に表示するか利用する情報の名前」というルールで付けたほうが良いかもしれない、と個人的に思っております。間違っているかもしれませんが。

 例えば、「musicListArtistName」や「musicDetailArtistName」です。


――――――――――――――――――――

android:id="@+id/◯◯◯"

――――――――――――――――――――

R.id.◯◯◯

――――――――――――――――――――

 ※R.id.◯◯◯の内容はint型の数値です。


文字を表示するラベルの部品であるテキスト ビュー(TextView)のidが「musicListArtistName」の場合の例

――――――――――――――――――――

android:id="@+id/musicListArtistName"

――――――――――――――――――――

findViewById<TextView>(R.id.musicListArtistName)?.text = "西川の兄貴"

――――――――――――――――――――



 ちなみに、"@+id/◯◯◯"ではなく"@id/◯◯◯"はコンストレイント レイアウト(ConstraintLayout)などで他の、画面の部品であるウィジェット(Widget)を指定する時に利用します。


――――――――――――――――――――

app:layout_constraintTop_toBottomOf="@id/◯◯◯"

――――――――――――――――――――


 例

――――――――――――――――――――

app:layout_constraintTop_toBottomOf="@id/musicListArtistName"

――――――――――――――――――――



 Android Studioは自動でXMLファイルを解析してR.javaファイルを作成してくれるので、「R.layout.拡張子無しのXMLファイル名」という形で、アンドロイド スマホのアプリの画面の表示の設定のXMLファイルを参照できます。アクティビティ(Activity)のonCreate()内のsetContentView()のパラメーターに指定したりします。


――――――――――――――――――――

class MainActivity : AppCompatActivity() {


  override fun onCreate(savedInstanceState: Bundle?) {

    try {

      super.onCreate(savedInstanceState)

      setContentView(R.layout.activity_main)


      //ここに処理を書きます。


    } catch (exception: Exception) {

      Toast.makeText(applicationContext, exception.toString(), Toast.LENGTH_LONG).show()

      throw exception

    }

  }

}

――――――――――――――――――――

 「R.layout.activity_main」は「/home/◯◯◯/AndroidStudioProjects/◇◇◇/app/src/main/res/layout/activity_main.xml」ファイルの参照です。

 ◯◯◯はLinux Mintのユーザー名です。

 ◇◇◇はユーザーがAndroid Studioのプロジェクトに付けた名前です。

  • Xで共有
  • Facebookで共有
  • はてなブックマークでブックマーク

作者を応援しよう!

ハートをクリックで、簡単に応援の気持ちを伝えられます。(ログインが必要です)

応援したユーザー

応援すると応援コメントも書けます

新規登録で充実の読書を

マイページ
読書の状況から作品を自動で分類して簡単に管理できる
小説の未読話数がひと目でわかり前回の続きから読める
フォローしたユーザーの活動を追える
通知
小説の更新や作者の新作の情報を受け取れる
閲覧履歴
以前読んだ小説が一覧で見つけやすい
新規ユーザー登録無料

アカウントをお持ちの方はログイン

カクヨムで可能な読書体験をくわしく知る