Help us understand the problem. What is going on with this article?

Androidで個人的によく使うlayout系設定チートシート

はじめに

今流行り?のZennにも同じ記事を投稿してみました
個人的によく使うレイアウト系のチートシート。
よく忘れて毎回調べるのでメモ。
逐次更新

2018/5/9 ActionBarにアイコン表示を追加
2020/3/3 「EditTextを横幅いっぱいで右端にTextViewを配置」にConstraintLayout版を追加
2020/09/22 はじめににZennへのリンクを追加した

ボタンを横に等間隔で配置する

スクリーンショット 2017-07-04 16.19.34.png

        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <Button
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="Btn1"/>
            <Button
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="Btn2"/>
            <Button
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="Btn3"/>
        </LinearLayout>

実装のポイント

  • 各ボタンにlayout_width="match_parent",layout_weight="1"を設定

EditTextを横幅いっぱいで右端にTextViewを配置

スクリーンショット 2017-07-04 16.26.30.png

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:hint="きんがく"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="right"
            android:text="円"/>
    </LinearLayout>

実装のポイント

  • EditTextにlayout_weight="1",layout_width="wrap_content"を設定
  • TextViewにgravity="right",layout_width="wrap_content"を設定
constraintLayout
     <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <EditText
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:hint="きんがく"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/textView3"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/textView3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="円"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>

実装ポイント

  • EditTextにEditTextの右をTextViewの左にの制約をつける
    • app:layout_constraintEnd_toStartOf="@+id/textView3"
  • EditTextのwidthにMatch Constraintsの制約をつける
    • android:layout_width="0dp"

EditTextの入力を右寄せに

スクリーンショット 2017-07-04 16.32.13.png

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="right"
            android:hint="きんがく"
            android:text="123,456,789"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="right"
            android:text="円"/>
    </LinearLayout>

実装のポイント

  • EditTextにgravity="right"を設定
  • Hintも右寄せになるので注意

Viewに対してRippleエフェクト

以前、「AndroidのRecycleViewでrippleエフェクトが出ない時にチェックしたほうがいいこと」で書いた内容

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="match_parent"
             android:focusable="true"
             android:clickable="true"
             android:layout_height="wrap_content"
             android:foreground="?android:attr/selectableItemBackground">
    <LinearLayout android:orientation="vertical"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content">
    <!-- 中身 -->
    </LinearLayout>
</FrameLayout>

実装のポイント

  • 一番外のLayoutをFrameLayoutにする(これ以外のLayoutはNG)
  • FrameLayoutにandroid:focusable="true",android:clickable="true",android:foreground="?android:attr/selectableItemBackground"を設定する
  • 角丸ボタンを作ってそれにエフェクトをつけたい場合は「角丸ボタンにRipple Effectをつける」を参考

ScrollViewのBottomにFooterを固定する

スクリーンショット 2017-07-04 17.09.00.png

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:padding="@dimen/common_padding"
              android:orientation="vertical">
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1">
        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <!-- 中身 -->

        </LinearLayout>
    </ScrollView>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="bottom"
        android:orientation="horizontal">

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/cancel"/>
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/ok"/>
    </LinearLayout>
</LinearLayout>

実装のポイント

  • ScrollViewにlayout_weight="1"を設定
  • Footer用のLayoutにgravity="bottom",layout_height="wrap_content"を設定

ボタンの共通デザインを定義する

style.xml
    <style name="ImportantButtonStyle" parent="Theme.AppCompat">
        <item name="colorButtonNormal">@color/importantButtonNormal</item>
        <item name="colorControlHighlight">@color/importantButtonHighLight</item>
        <item name="android:textColor">@color/importantButtonTextColor</item>
    </style>
someFragment.xml
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/ImportantButtonStyle"
            android:text="決定"/>

実装のポイント

  • style.xmlにスタイルを定義
  • 呼び出したいボタンのthemeで定義したスタイルを呼び出す

ActionBarのハンバーガーアイコン、戻る矢印、メニューのテキスト、タイトルテキストの色を変える

StackOverFlowから転記(アイコンの色)
StackOverFlowから転記(Menuのテキスト)

styles.xml
<style name="ToolbarStyle" parent="@style/ThemeOverlay.AppCompat.ActionBar">
  <!-- Customize color of navigation drawer icon and back arrow --> 
  <item name="colorControlNormal">@color/actionbarItemColor</item>
  <!-- Customize color of menu item text-->
  <item name="actionMenuTextColor">@color/actionbarItemColor</item>

</style>
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar 
    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="wrap_content"
    app:titleTextColor="@color/actionbarItemColor"
    android:minHeight="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    app:theme="@style/ToolbarStyle" >
</android.support.v7.widget.Toolbar>

実装のポイント

  • styles.xmlでcolorControlNormalの要素を変更→アイコン系の色変更
  • styles.xmlでactionMenuTextColorの要素を変更→メニューのテキストの色変更
  • Toolbarの要素にapp:titleTextColorの要素を変更→タイトルのテキストの色変更
  • app:theme="@style/ToolbarStyle"を追加し、styleを反映
  • titleTextColorもstyles.xmlで指定できるが、APILv23以上を要求してくる

Tabレイアウトを作る

これはKotlin用のCleanArchitectureのテンプレート作ったよ!で書いた、CleanArchitecture前提

スクリーンショット 2017-07-14 14.42.44.png

tab_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              android:orientation="vertical">

    <android.support.design.widget.TabLayout
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <android.support.design.widget.TabItem
            android:id="@+id/details_tab_1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="tab1"/>

        <android.support.design.widget.TabItem
            android:id="@+id/details_tab_2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="tab2"/>
        <android.support.design.widget.TabItem
            android:id="@+id/details_tab_3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="tab3"/>
    </android.support.design.widget.TabLayout>
    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</LinearLayout>
TabFragment.kt
    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        var fragment1 = activity.supportFragmentManager.findFragmentById(R.id.details_tab_1) as Fragment1?
        var fragment2 = activity.supportFragmentManager.findFragmentById(R.id.details_tab_2) as Fragment2?
        var fragment3 = activity.supportFragmentManager.findFragmentById(R.id.details_tab_3) as Fragment3?

        if (fragment1 == null) {
            fragment1 = Fragment1.newInstance()
            activity.supportFragmentManager.beginTransaction().add(R.id.details_tab_1, fragment1).commit()
        }
        if (fragment2 == null) {
            fragment2 = Fragment2.newInstance()
            activity.supportFragmentManager.beginTransaction().add(R.id.details_tab_2, fragment2).commit()
        }
        if (fragment3 == null) {
            fragment3 = Fragment3.newInstance()
            activity.supportFragmentManager.beginTransaction().add(R.id.details_tab_3, fragment3).commit()
        }

        (activity.application as MyApplication).rootComponent
                .newFragment1Component(Fragment1Module(fragment1 as Fragment1Contract.View)).inject(fragment1)
        (activity.application as MyApplication).rootComponent
                .newFragment2Component(Fragment2Module(fragment2 as Fragment2Contract.View)).inject(fragment2)
        (activity.application as MyApplication).rootComponent
                .newFragment3Component(Fragment3Module(fragment3 as Fragment3Contract.View)).inject(fragment3)

        val adapter = SectionsPagerAdapter(activity.supportFragmentManager,fragment1,fragment2,fragment3)
        view_pager.adapter = adapter
        view_pager.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabs))
        view_pager.addOnPageChangeListener(object : ViewPager.SimpleOnPageChangeListener(){
            override fun onPageSelected(position: Int) {
                super.onPageSelected(position)

                when(position) {
                    TAB_1 -> fragment1.load()
                    TAB_2 -> fragment2.load()
                    TAB_3 -> fragment3.load()
                }
            }
        })
        tabs.addOnTabSelectedListener(TabLayout.ViewPagerOnTabSelectedListener(view_pager))

    }

    inner class SectionsPagerAdapter(fm: FragmentManager,
                                     private val fragment1: Fragment1,
                                     private val fragment2: Fragment2,
                                     private val ragment3: Fragment3)
        : FragmentPagerAdapter(fm) {

        override fun getItem(position: Int): Fragment {
            return when(position) {
                TAB_1 -> fragment1
                TAB_2 -> fragment2
                TAB_3 -> fragment3
                else -> fragment1
            }
        }

        override fun getCount(): Int {
            return 3
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        presenter.dispose()
    }

    companion object {
        fun newInstance(): DetailsFragment {
            val args = Bundle()
            val fragment = DetailsFragment()
            fragment.arguments = args
            return fragment
        }

        const val TAB_1 = 0
        const val TAB_2 = 1
        const val TAB_3 = 2
    }

実装のポイント

  • CleanArchitectureTemplateではActivityのonCreateで行なっていたinject処理を、onCreatedViewで行う
  • Tab管理にはFragmentPagerAdapterを利用する
  • view_pager.adapter = adapterでAdapterとViewPagerを紐づける
  • view_pager.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabs))でViewPagerが動いたらTabも動くようにしてる
  • view_pager.addOnPageChangeListener(object : ViewPager.SimpleOnPageChangeListener(){でページが切り替わったら各Tab内のFragment側でロード処理を行う。(画面が表示された時の処理)
  • tabs.addOnTabSelectedListener(TabLayout.ViewPagerOnTabSelectedListener(view_pager))でTabをタップしたらViewPager側も動くようにしている
  • Activityでも同様の実装が出来る。その場合、onCreatedViewの実装はonCreate内で行う

Headerがスクロールすると消えるやつ

CoordinatorLayoutでヘッダー隠す時の知見を得た話」これの話の要点まとめ

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <android.support.design.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <!-- AppbarLayout内にHeaderパーツを入れる -->
        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/AppTheme.AppBarOverlay">

            <android.support.v7.widget.Toolbar
                ...
                app:layout_scrollFlags="scroll|enterAlways"/>  
            <!-- 最初にscrollFlagsが設定されていないパーツが見つかった時点でスクロールが止まるようになる -->
        </android.support.design.widget.AppBarLayout>
         <!-- AppBarLayoutの下にスクロールさせたいパーツを配置する -->
         <!-- 指定できるパーツはNestedScrollViewかRecyclerViewのみ -->
         <!-- app:layout_behavior="@string/appbar_scrolling_view_behavior"この指定をすることで、リストの開始地点がAppBarLayoutの下になる。-->
         <!--  指定しないと画面トップからになる -->
         <android.support.v4.widget.NestedScrollView
            android:id="@+id/pager"
            android:layout_below="@+id/app_bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

            <!-- 中身 -->

        </android.support.v4.widget.NestedScrollView>

    </android.support.design.widget.CoordinatorLayout>

</LinearLayout>

実装のポイント

  • 構造は以下のとおり
 --- CoordinatorLayout
                + AppBarLayout
                |         + Headerでスクロールさせたいパーツ
                |         + Headerでスクロールさせたくないパーツ
                |
                + NestedScrollView or RecyclerView
                       + コンテンツの中身   
  • Headerのパーツは必ずスクロールさせたいパーツスクロールさせたくないパーツの順に並べる
  • スクロールさせたいHeaderパーツにはapp:layout_scrollFlags="scroll"の指定を行うこと
  • スクロールコンテンツはNestedScrollViewRecyclerViewのみ使える
  • スクロールコンテンツにapp:layout_behavior="@string/appbar_scrolling_view_behavior"の設定を行うと、Headerパーツの下からスクロールコンテンツが配置される。指定しないと画面トップからスクロールコンテンツが配置される(Headerの裏にスクロールコンテンツが隠れる感じ)
  • AppBarLayout配下のパーツにはAppThemeが自動で適応される。もしカスタマイズしたい場合はthemeの指定をする必要がある

Drawerメニューを追加する

drawer.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
                                        xmlns:app="http://schemas.android.com/apk/res-auto"
                                        android:id="@+id/menu_drawer_layout"
                                        android:fitsSystemWindows="true"
                                        android:layout_width="match_parent"
                                        android:layout_height="match_parent">
    <android.support.design.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <android.support.v7.widget.Toolbar
                android:id="@+id/menu_toolbar"
                app:title="?attr/toolbar_title"
                android:theme="@style/ToolbarStyle"
                app:titleTextColor="@color/actionbarItemColor"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary" />

        </android.support.design.widget.AppBarLayout>

        <FrameLayout
            android:paddingTop="?attr/actionBarSize"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/base_fragment"/>

    </android.support.design.widget.CoordinatorLayout>
    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:itemBackground="@drawable/navigation_drawer_item_bg_color"
        app:headerLayout="@layout/nav_header"
        app:menu="@menu/main_drawer" />
</android.support.v4.widget.DrawerLayout>
main_drawer.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:id="@+id/main_menu_group"
           android:checkableBehavior="single">
        <item android:id="@+id/nav_home"
              android:icon="@drawable/icon_home"
              android:title="@string/nav_home"/>
    </group>
    <group android:id="@+id/main_menu_link_group"
           android:checkableBehavior="none">
        <item android:id="@+id/nav_link"
              android:icon="@drawable/icon_link"
              android:title="@string/nav_link"/>
    </group>
</menu>
BaseActivity.kt
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.base_menu_activity)

        setSupportActionBar(menu_toolbar)
        val toggle = object : ActionBarDrawerToggle(
                this, menu_drawer_layout, menu_toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) {
            override fun onDrawerOpened(drawerView: View) {
                super.onDrawerOpened(drawerView)
                //Drawerが開いた時の処理
            }
        }

        menu_drawer_layout.addDrawerListener(toggle)
        toggle.syncState()
        nav_view.setNavigationItemSelectedListener { item ->
            val id = item.itemId
            launch(id)
            menu_drawer_layout.closeDrawer(GravityCompat.START)
            true
        }
        nav_view.menu.findItem(getCurrentNaviId()).isChecked = true
    }

    private fun launch(id: Int) {
        //idに応じて画面遷移など
    }
    override fun onBackPressed() {
        if (menu_drawer_layout.isDrawerOpen(GravityCompat.START)) {
            menu_drawer_layout.closeDrawer(GravityCompat.START)
        } else {
            super.onBackPressed()
        }
    }

実装ポイント

  • Layout.xmlでは一番外側の要素をDrawerLayoutにする
  • DrawerのデザインにはNavigationViewを使う
  • Drawerのメニュー指定はxml側にてapp:menu="@menu/main_drawer"で指定
  • Drawerのヘッダー指定はxml側にてapp:headerLayout="@layout/nav_header"で指定

画面切り替わり時にクロスフェード

anim/fade_in.xml
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
       android:interpolator="@android:anim/accelerate_interpolator"
       android:fromAlpha="0.0" android:toAlpha="1.0"
       android:duration="300" />
anim/fade_out.xml
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
       android:interpolator="@android:anim/accelerate_interpolator"
       android:fromAlpha="1.0" android:toAlpha="0.0"
       android:fillAfter="true"
       android:duration="300" />
fun someMethod() {
    someButton.onClickListener({ 
        SomeSubActivity.launch()
        overridePendingTransition(R.anim.fade_in, R.anim.fade_out)
    })
}

実装ポイント

  • intentStart処理の後にoverridePendingTransitionでフェードをかける

layoutのexpand/collapseアニメーション&アイコンくるり

RecycleViewで開閉(Expand/Collapse)のアニメーションを実装する」を参照

HeaderのタイトルをStyle.xmlで変える

共通のbase_activity.xmlを各Activityは使用する前提。
Header部分は「Headerがスクロールすると消えるやつ」の応用。Activity側でイベントを紐づけられるようにするため。

base_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              xmlns:app="http://schemas.android.com/apk/res-auto">
    <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
                                                     android:id="@+id/main_content"
                                                     android:layout_width="match_parent"
                                                     android:layout_height="match_parent">
        <android.support.design.widget.AppBarLayout
            android:id="@+id/appbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                app:title="?attr/toolbar_title"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                />

        </android.support.design.widget.AppBarLayout>
        <FrameLayout
            android:id="@+id/base_fragment"
            android:paddingTop="?attr/actionBarSize"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </android.support.design.widget.CoordinatorLayout>


</LinearLayout>
style.xml
<resources>
    <attr name="toolbar_title" format="reference" />

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="toolbar_title">@string/app_name</item>
    </style>

    <style name="CoordinatorLayoutHeader" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="HomeActivity" parent="AppTheme">
        <item name="toolbar_title">@string/home_title</item>
    </style>
</resources>
AndroidManifest.xml
        <activity
            android:name=".home.HomeActivity"
            android:launchMode="singleTask"
            android:theme="@style/HomeActivity" />

実装のポイント

  • base_activity.xmlのToolbarのapp:titleに対して?attr/toolbar_titleを設定する
  • style.xmlに<attr name="toolbar_title" format="reference" />を設定する
  • style.xmlにて、<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">を定義。ここではAppThemeをNoActionBarで上書きしたいために設定している。要素内でのcolorの定義やtoolbar_titleの定義は任意でOK。
  • CoordinatorLayoutHeaderの設定は任意。設定することで、スクロールすると消える部分の設定を行える。今回はHeader部分のみなので特に影響はない。
  • style.xmlにて、AppThemeを継承したstyleを定義する。(例の場合はHomeActivity)。その要素として<item name="toolbar_title">@string/home_title</item>を指定する
  • AndroidManifest.xmlにて、該当のActivityの属性としてandroid:theme="@style/HomeActivity"を指定する

検索ボタンをActionBarに追加する

menu/menu_search.xml
<?xml version="1.0" encoding="utf-8"?>
<menu
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item android:id="@+id/search_menu_item"
          android:title="@string/search"
          android:icon="@android:drawable/ic_menu_search"
          app:showAsAction="always"
          android:orderInCategory="100"
          app:actionViewClass="android.widget.SearchView"
          />
</menu>
SeachableActivity.kt
class SearchableActivity: AppCompatActivity(), SearchView.OnQueryTextListener {

    protected lateinit var searchView:SearchView

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.search_menu, menu)
        searchView = menu?.findItem(R.id.search_menu_item)?.actionView as SearchView
        searchView.setOnQueryTextListener(this)
        searchView.isSubmitButtonEnabled = false

        return super.onCreateOptionsMenu(menu)
    }

    override fun onQueryTextSubmit(query: String?): Boolean {
        //送信ボタン的なやつ押したら検索
        return false
    }

    override fun onQueryTextChange(newText: String?): Boolean {
        //インクリメンタル検索
        return false
    }
}

実装ポイント

  • 検索のメニューを用意して、OptionsMenuでそいつを追加。

RecycleViewの実装

単純なリスト形式
Adapter生成にはUseful-template-forKotlinを利用(露骨な宣伝)

some_list.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/some_list"
        android:layout_weight="1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:listitem="@layout/adapter_some"
        tools:context=".some.SomeListFragment"
        app:layoutManager="LinearLayoutManager"/>
</LinearLayout>
SomeListFragment.kt
fun loaded(data:List<SomeData>) {
        if (some_list != null && some_list.adapter == null) {
            some_list.adapter = SomeAdapter(data)
        } else {
            (some_list.adapter as SomeAdapter).data = data
            some_list.adapter.notifyDataSetChanged()
        }
}

実装ポイント

  • listのnullチェックは念のため。実装の仕方によっては不要かもしれない

ActionBarにアイコン表示

SomeActivity.kt
class SomeActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.base_activity)
        supportActionBar!!.setIcon(R.drawable.ic_launcher_small)
        supportActionBar!!.setDisplayShowHomeEnabled(true)
    }
}
style.xml
    <style name="SomeActivityTheme" parent="Theme.AppCompat.Light">
    </style>

実装ポイント

  • アイコンセットsupportActionBar!!.setIcon(R.drawable.ic_launcher_small)
  • アイコン表示の設定supportActionBar!!.setDisplayShowHomeEnabled(true)
  • デフォルトのActionBarを使うため、ActivityのテーマのparentにNoActionBarを設定しない
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away