Memo

メモ > 技術 > IDE: AndroidStudio > アプリの作成(XMLレイアウト / ドロワーメニュー)

■アプリの作成(XMLレイアウト / ドロワーメニュー)
以下で新規にプロジェクトを作成 プロジェクトの選択: Empty Activity プロジェクトの名前: drawer ビューバインディングを使えるようにする build.gradle を変更したら「Sync Now」をクリック メニュー用のフラグメントを作成する プロジェクトウインドウのツリーで「app」を右クリックし、 「New → Fragment → Fragment(Blank)」を選択する 表示されたダイアログで「Fragment Name」で「MenuFragment」と入力して、あとはデフォルトのまま「Finish」ボタンを押す プロジェクトウインドウのツリーに「MenuFragment.kt」と「fragment_menu.xml」が追加される fragment_menu.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.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"> <LinearLayout android:layout_width="0dp" android:layout_height="0dp" android:gravity="center_horizontal" android:orientation="vertical" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> <Button android:id="@+id/firstButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="8dp" android:text="First" /> <Button android:id="@+id/secondButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="8dp" android:text="Second" /> <Button android:id="@+id/thirdButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="8dp" android:text="Third" /> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout>
MenuFragment
package org.refirio.drawer import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Button import androidx.fragment.app.Fragment class MenuFragment() : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_menu, container, false) val firstButton = view.findViewById<Button>(R.id.firstButton) firstButton.setOnClickListener { val listener = context as? OnButtonClickListener listener?.onFirstButtonClicked() } val secondButton = view.findViewById<Button>(R.id.secondButton) secondButton.setOnClickListener { val listener = context as? OnButtonClickListener listener?.onSecondButtonClicked() } val thirdButton = view.findViewById<Button>(R.id.thirdButton) thirdButton.setOnClickListener { val listener = context as? OnButtonClickListener listener?.onThirdButtonClicked() } return view } interface OnButtonClickListener { fun onFirstButtonClicked() fun onSecondButtonClicked() fun onThirdButtonClicked() } }
コンテンツ用のフラグメントを作成する プロジェクトウインドウのツリーで「app」を右クリックし、 「New → Fragment → Fragment(Blank)」を選択する 表示されたダイアログで「Fragment Name」で「FirstFragment」と入力して、あとはデフォルトのまま「Finish」ボタンを押す プロジェクトウインドウのツリーに「FirstFragment.kt」と「fragment_first.xml」が追加される fragment_first.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.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"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="First" android:textAppearance="@style/TextAppearance.AppCompat.Large" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
FirstFragment.kt
package org.refirio.drawer import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment class FirstFragment() : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_first, container, false) return view } }
同様に SecondFragment と ThirdFragment を作成する (SecondFragment.kt と fragment_second.xml と ThirdFragment.kt と fragment_third.xml が追加される。) メインアクティビティとそのレイアウトを実装する activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawerLayout" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <!-- メインコンテンツ --> <FrameLayout android:id="@+id/container" android:layout_width="wrap_content" android:layout_height="wrap_content"> </FrameLayout> <!-- ドロワーコンテンツ --> <FrameLayout android:id="@+id/drawer" android:layout_width="240dp" android:layout_height="match_parent" android:layout_gravity="start" android:background="?android:attr/colorBackground"> <fragment android:id="@+id/fragment" android:name="org.refirio.drawer.MenuFragment" android:layout_width="match_parent" android:layout_height="match_parent" tools:layout="@layout/fragment_menu" /> </FrameLayout> </androidx.drawerlayout.widget.DrawerLayout>
MainActivity.kt
package org.refirio.drawer import android.content.res.Configuration import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.view.MenuItem import androidx.appcompat.app.ActionBarDrawerToggle import androidx.drawerlayout.widget.DrawerLayout class MainActivity : AppCompatActivity(), MenuFragment.OnButtonClickListener { // ドロワーの状態操作用オブジェクト private var drawerToggle : ActionBarDrawerToggle? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) if (supportFragmentManager.findFragmentByTag("ContentFragment") == null) { supportFragmentManager.beginTransaction() .add(R.id.container, FirstFragment(), "ContentFragment") .commit() } // レイアウトからドロワーを探す val drawerLayout = findViewById<DrawerLayout>(R.id.drawerLayout) // ドロワーを作成する val toggle = ActionBarDrawerToggle(this, drawerLayout, R.string.app_name, R.string.app_name) toggle.isDrawerIndicatorEnabled = true drawerLayout.addDrawerListener(toggle) // ドロワーの状態を保持 drawerToggle = toggle // ドロワーの設定を行う supportActionBar?.apply { setDisplayHomeAsUpEnabled(true) setHomeButtonEnabled(true) } } override fun onFirstButtonClicked() { supportFragmentManager.beginTransaction() .replace(R.id.container, FirstFragment()) .addToBackStack(null) .commit() } override fun onSecondButtonClicked() { supportFragmentManager.beginTransaction() .replace(R.id.container, SecondFragment()) .addToBackStack(null) .commit() } override fun onThirdButtonClicked() { supportFragmentManager.beginTransaction() .replace(R.id.container, ThirdFragment()) .addToBackStack(null) .commit() } // アクティビティの生成が終わった後に呼ばれる override fun onPostCreate(savedInstanceState: Bundle?) { super.onPostCreate(savedInstanceState) // ドロワーのトグルの状態を回復する drawerToggle?.syncState() } // 画面構成が変わったときに呼ばれる override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) // 状態の変化をドロワーに伝える drawerToggle?.onConfigurationChanged(newConfig) } // オプションメニューがタップされたときに呼ばれる override fun onOptionsItemSelected(item: MenuItem): Boolean { // ドロワーに伝える if (drawerToggle?.onOptionsItemSelected(item) == true) { return true } else { return super.onOptionsItemSelected(item) } } }
ここまででいったん完成 引き続き、 ・縦表示ならドロワーメニュー ・横表示ならサイドメニュー としてみる 横表示用にレイアウトを追加する activity_main.xml を開き、「Design」タブで表示する タブ内のツールバーから「Orientation in Editor → Create Landscape Variation」を選択する 以下のファイルが作成される。内容はもとの activity_main.xml と同じものになる app/src/main/res/layout-land/activity_main.xml このファイルを以下のように修正する (rootのIDをdrawerLayoutから別のものに変えると、「Configurations for activity_main.xml must agree on the root element's ID.」のエラーになった このエラーを回避するために、rootのDrawerLayoutは触らずにLinearLayoutを追加している 正しい方法かどうかは不明)
<?xml version="1.0" encoding="utf-8"?> <androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawerLayout" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <LinearLayout android:id="@+id/linearLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <!-- ドロワーコンテンツ --> <FrameLayout android:id="@+id/drawer" android:layout_width="240dp" android:layout_height="match_parent" android:layout_gravity="start" android:background="?android:attr/colorBackground"> <fragment android:id="@+id/fragment" android:name="org.refirio.drawer.MenuFragment" android:layout_width="match_parent" android:layout_height="match_parent" tools:layout="@layout/fragment_menu" /> </FrameLayout> <!-- メインコンテンツ --> <FrameLayout android:id="@+id/container" android:layout_width="wrap_content" android:layout_height="wrap_content"> </FrameLayout> </LinearLayout> </androidx.drawerlayout.widget.DrawerLayout>
MainActivity.kt を以下のように変更する
package org.refirio.drawer import android.content.res.Configuration import android.os.Bundle import android.view.MenuItem import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.AppCompatActivity import androidx.drawerlayout.widget.DrawerLayout class MainActivity : AppCompatActivity(), MenuFragment.OnButtonClickListener { // ドロワーの状態操作用オブジェクト private var drawerToggle : ActionBarDrawerToggle? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) if (supportFragmentManager.findFragmentByTag("ContentFragment") == null) { supportFragmentManager.beginTransaction() .add(R.id.container, FirstFragment(), "ContentFragment") .commit() } val orientation = resources.configuration.orientation // 縦向きの場合 if (orientation == Configuration.ORIENTATION_PORTRAIT) { val drawerLayout = findViewById<DrawerLayout>(R.id.drawerLayout) setupDrawer(drawerLayout) } } override fun onFirstButtonClicked() { supportFragmentManager.beginTransaction() .replace(R.id.container, FirstFragment()) .addToBackStack(null) .commit() } override fun onSecondButtonClicked() { supportFragmentManager.beginTransaction() .replace(R.id.container, SecondFragment()) .addToBackStack(null) .commit() } override fun onThirdButtonClicked() { supportFragmentManager.beginTransaction() .replace(R.id.container, ThirdFragment()) .addToBackStack(null) .commit() } // アクティビティの生成が終わった後に呼ばれる override fun onPostCreate(savedInstanceState: Bundle?) { super.onPostCreate(savedInstanceState) // ドロワーのトグルの状態を回復する drawerToggle?.syncState() } // 画面構成が変わったときに呼ばれる override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) // 状態の変化をドロワーに伝える drawerToggle?.onConfigurationChanged(newConfig) } // オプションメニューがタップされたときに呼ばれる override fun onOptionsItemSelected(item: MenuItem): Boolean { // ドロワーに伝える if (drawerToggle?.onOptionsItemSelected(item) == true) { return true } else { return super.onOptionsItemSelected(item) } } private fun setupDrawer(drawerLayout: DrawerLayout) { // ドロワーを作成する val toggle = ActionBarDrawerToggle(this, drawerLayout, R.string.app_name, R.string.app_name) toggle.isDrawerIndicatorEnabled = true drawerLayout.addDrawerListener(toggle) // ドロワーの状態を保持 drawerToggle = toggle // ドロワーの設定を行う supportActionBar?.apply { setDisplayHomeAsUpEnabled(true) setHomeButtonEnabled(true) } } }

Advertisement