Shytterv1.6をリリースしました!
本業が落ち着き、日曜プログラマ、ひさびさに再開です
バタバタしている間に、Material DesignがGoogle I/O 2014で発表されてから1年、Design Support LibraryがGoogle I/O 2015で発表されてから2ヶ月すぎてしまいました(;一_一)
やっとデザインの乗り換えができたので、いろいろの備忘録
取り込んでみたのは、
- ToolBar
- TabLayout
- DrawerLayout/NavigationView
- Floating Action Button(FAB)
- SwipeToRefresh/自動スクロール
の5つ!!
ちなみに、
こんな感じのが
こんな感じになりました♪
導入/準備
準備として、Design Support Libraryをbuild.gradleのdependenciesに追加します。
dependencies { compile 'com.android.support:design:23.0.0' compile 'com.android.support:appcompat-v7:23.0.1' compile 'com.android.support:support-v4:23.0.0' }
ToolBar
ActionBarの代わりとなったToolBar
基本的な使い方は簡単で、
- styleを
NoActionBar
にして - layoutに
<android.support.v7.widget.Toolbar>
を配置し、 - java側で
setSupportActionBar();
を使い、ToobarをActionBarとして扱えるようにする
だけ
values/styles.xml
styles.xmlはこんな感じで、Theme.AppCompat.Light.NoActionBar
を継承したテーマを使う
<resources> <!-- Base Application Theme --> <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> </style>
layout/main.xml (ToolBar)
レイアウトXMLはこんな感じ
ActionBarと違うのはレイアウトXML内にToolBarを配置すること
一番外側のViewでpaddingなどをしているとToolBarにも影響が出るので注意!!
<RelativeLayout 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"> <!-- ToolBar --> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" /> <!-- Contents --> <!-- ここに表示したいViewをいつもどおり配置する --> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> </RelativeLayout> </RelativeLayout>
MainActivity.java (ToolBar)
Java側はこんな感じ
public class MainActivity extends AppCompatActivity { Toolbar mToolBar; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //ToolBarの設定 mToolBar = (Toolbar) findViewById(R.id.toolbar); mToolBar.setTitle("ツールバーのタイトル"); setSupportActionBar(mToolBar); //ToolBarをActionBarとして扱うように設定 } }
ToolBarの色とか文字とかを変える
ToolBarの色やタイトルの文字を変えるときはこんな感じ
styles.xmlのattrを使うことで設定もできるけど、他のViewにも影響が出てしまうので、
よくわからないときは個別に設定するのがいいかも
android:background
で背景色を設定app:titleTextAppearance
でタイトルの色やtypefaceのstyleを設定app:subtitleTextAppearance
でサブタイトルの色やtypefaceのstyleを設定
<!-- layout/main.xml --> <android.support.v7.widget.Toolbar ・・・ android:background="@color/actionbar_background" app:subtitleTextAppearance="@style/MyActionBarSubTitleText" app:titleTextAppearance="@style/MyActionBarTitleText" /> <!-- values/styles.xml --> <style name="MyActionBarTitleText" parent="TextAppearance.AppCompat.Widget.ActionBar.Title"> <item name="android:textColor">@color/actionbar_textColor</item> <item name="android:textStyle">bold</item> <item name="android:typeface">sans</item> </style> <style name="MyActionBarSubTitleText" parent="TextAppearance.AppCompat.Widget.ActionBar.Subtitle"> <item name="android:textColor">@color/actionbar_textColor</item> <item name="android:typeface">sans</item> </style>
TabLayout(+ ViewPager)
TabLayoutもいい感じに設定できるようになった!
また、TabLayout自体にViewPagerと同期する機能が増えたので、
スワイプでのタブ切り替えも簡単になった気がする!
layout/main.xml (ToolBar + TabLayout)
レイアウトXMLはこんな感じ
<RelativeLayout 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"> <!-- ToolBar --> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" /> <!-- Contents --> <!-- ここに表示したいViewをいつもどおり配置する --> <android.support.design.widget.TabLayout android:id="@+id/tabs" android:layout_width="match_parent" android:layout_height="36dp" android:layout_below="@+id/toolbar" app:tabMaxWidth="0dp" /> <android.support.v4.view.ViewPager android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/tabs"/> </RelativeLayout>
はまった!!
app:tabMaxWidth
はデフォルト値が264dpなので、0dpを設定しないと、横向きにした時に、レイアウトが変な感じに。。。
他のattributesについてはAndroid - TabLayoutで設定できるattributes一覧 - Qiitaでまとめられているので参照のこと!!
MainActivity.java (ToolBar + TabLayout)
Java側はこんな感じ
public class MainActivity extends AppCompatActivity { Toolbar mToolBar; ViewPager mViewPager; TabLayout mTabLayout; PagerAdapter mPagerAdapter; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //ToolBarの設定 mToolBar = (Toolbar) findViewById(R.id.toolbar); mToolBar.setTitle("ツールバーのタイトル"); setSupportActionBar(mToolBar); //TabLayoutの設定 mPagerAdapter = new PagerAdapter(getSupportFragmentManager()); mViewPager.setAdapter(mPagerAdapter); mTabLayout.setupWithViewPager(mViewPager); //ViewPagerをTabLayoutにセット } //FragmentStatePagerAdapterを継承したアダプタークラス public class PagerAdapter extends FragmentStatePagerAdapter { //・・・ } }
TabLayoutのモードとかを変える
どういうふうにタブを表示するかを変えることができる
<android.support.design.widget.TabLayout ・・・ app:tabGravity="center" app:tabMode="scrollable" />
app:tabGravity
center
: 中央寄せで表示fill
: 画面いっぱいに表示
app:tabMode
scrollable
: スクロール可能。すべてのタブを表示しないfixed
: スクロール不可。すべてのタブを表示する
Tabとかの色を変える
こちらもToolBarと同様、styleのattrで設定できるけど、最初は個別のほうがいいかも?
<android.support.design.widget.TabLayout ・・・ app:tabBackground="@color/viewpager_background" app:tabIndicatorColor="@color/viewpager_textColor_selected" app:tabSelectedTextColor="@color/viewpager_textColor_selected" app:tabTextColor="@color/viewpager_textColor" />
app:tabBackground
: タブの背景の色app:tabIndicatorColor
: 選択しているタブの下の棒(インディケータ)の色app:tabSelectedTextColor
: 選択中のタブの文字の色app:tabTextColor
: 選択されていないタブの文字の色
DrawerLayout/NavigationView
横からぴょこっと出てくるメニュー?View?(Drawer)と
DrawerLayout内のViewを簡単に作成できるようにしてくれるNavigationView
便利だけど、Drawerの内容がmenu xml?でしか定義できないので、
おしゃれな見た目や凝った配置にしたい場合には、NavigationViewは使えないかも?
layout/main.xml (ToolBar + TabLayout + DrawerLayout/NavigationView)
レイアウトXMLはこんな感じ
android.support.v4.widget.DrawerLayout
が最上位のViewになって
Drawer以外のView(RelativeLayout
)とDrawerのView(android.support.design.widget.NavigationView
)を配置する感じに
<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/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- Drawer以外のViewを配置 --> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <!-- ToolBar --> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" /> <!-- Contents --> <!-- ここに表示したいViewをいつもどおり配置する --> <android.support.design.widget.TabLayout android:id="@+id/tabs" android:layout_width="match_parent" android:layout_height="36dp" android:layout_below="@+id/toolbar" app:tabMaxWidth="0dp" /> <android.support.v4.view.ViewPager android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/tabs" /> </RelativeLayout> <!-- DrawerのViewを配置 --> <android.support.design.widget.NavigationView android:id="@+id/navigation" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" app:headerLayout="@layout/view_drawer_header" app:menu="@menu/menu_drawer" /> </android.support.v4.widget.DrawerLayout>
layout/view_drawer_header.xml
Drawerのヘッダー(上の部分)のレイアウトXMLは個別に設定
例だと"menu"を表示するTextViewのみだけど、Gmailとかではアカウントの情報が表示されてる
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="56dp" android:background="@color/background_color"> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_marginLeft="16dp" android:gravity="center_vertical" android:text="menu" android:textSize="32sp" /> </FrameLayout>
menu/menu_drawer.xml
Drawerの中身のメニューXMLは個別に設定
ActionBarのmenuと同じ感じで設定できる
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu_search" android:title="検索" /> <item android:id="@+id/menu_reload" android:title="更新" /> <item android:id="@+id/menu_settings" android:title="設定" /> </menu>
MainActivity.java (ToolBar + TabLayout + DrawerLayout/NavigationView)
Java側はこんな感じ
public class MainActivity extends AppCompatActivity { Toolbar mToolBar; ViewPager mViewPager; TabLayout mTabLayout; PagerAdapter mPagerAdapter; DrawerLayout mDrawerLayout; ActionBarDrawerToggle mDrawerToggle; NavigationView mNavigationView; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //ToolBarの設定 mToolBar = (Toolbar) findViewById(R.id.toolbar); mToolBar.setTitle("ツールバーのタイトル"); setSupportActionBar(mToolBar); //TabLayoutの設定 mPagerAdapter = new PagerAdapter(getSupportFragmentManager()); mViewPager.setAdapter(mPagerAdapter); mTabLayout.setupWithViewPager(mViewPager); //DrawerLayoutの設定 mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, mToolBar, R.string.app_name, R.string.app_name); mDrawerLayout.setDrawerListener(mDrawerToggle); mDrawerToggle.setDrawerIndicatorEnabled(true); //NavigationViewの設定 mNavigationView.setNavigationItemSelectedListener(menuItem -> { switch (menuItem.getItemId()) { case R.id.menu_search: //・・・ return true; case R.id.menu_reload: //・・・ return true; case R.id.menu_settings: //・・・ return true; default: } return false; }); } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); mDrawerToggle.syncState(); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mDrawerToggle.onConfigurationChanged(newConfig); } //FragmentStatePagerAdapterを継承したアダプタークラス public class PagerAdapter extends FragmentStatePagerAdapter { //・・・ } }
登場人物も多くて結構複雑。。。
DrawerLayoutの設定
ToolBarにある三本線のアイコン(ハンバーガーアイコン)とドロアーを同期させるために いろいろ設定したり、
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, mToolBar, R.string.app_name, R.string.app_name); mDrawerLayout.setDrawerListener(mDrawerToggle); mDrawerToggle.setDrawerIndicatorEnabled(true);
onPostCreate
とonConfigurationChanged
をオーバーライドして、mDrawerToggle
の状態を同期させないといけない
@Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); mDrawerToggle.syncState(); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mDrawerToggle.onConfigurationChanged(newConfig); }
mNavigationViewのイベント
また、ボタンのイベントはmNavigationView.setNavigationItemSelectedListener
を使い、リスナーを設定する必要がある
//NavigationViewの設定 mNavigationView.setNavigationItemSelectedListener(menuItem -> { switch (menuItem.getItemId()) { case R.id.menu_search: //・・・ return true; case R.id.menu_reload: //・・・ return true; case R.id.menu_settings: //・・・ return true; default: } return false; });
バックボタンでドロアーを閉じたい
デフォルトだと、ドロアーが開いている状態でバックキーを押すとアプリが終了してしまう。。。
でも感覚的には、バックキー = 前の状態に戻るなので、ドロワーを閉じてほしい。。。
なので、finish()
をオーバーライドして、そうなるように変更したりしている
@Override public void finish() { //ドロアーが開いてたら閉じる。閉じてたら終了する if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) { mDrawerLayout.closeDrawer(GravityCompat.START); } else { super.finish(); } }
Floating Action Button(FAB)
浮いてるボタンのFloating Action Button(FAB)は簡単!
普通の<Button>
の代わりに<android.support.design.widget.FloatingActionButton>
を使うだけ
あとは、Buttonと同じ感じで、OnClickListenerを設定すればOK!!
layout/fab.xml
<android.support.design.widget.FloatingActionButton android:id="@+id/btn_add" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_marginBottom="@dimen/fragment_fab_margin" android:layout_marginRight="8dp" android:src="@drawable/ic_add_white_24dp" app:backgroundTint="@color/viewpager_textColor" app:borderWidth="0dp" app:fabSize="normal" />
SwipeToRefresh/自動スクロール
引っ張って更新するSwipeToRefreshと
リストの最後までスクロールされたら次のリストItemを読み込む自動スクロール
layout/main.xml
レイアウトXMLはこんな感じ
<ListView>
を<android.support.v4.widget.SwipeRefreshLayout>
で挟んであげる感じ
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipe_refresh" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" /> </android.support.v4.widget.SwipeRefreshLayout> </LinearLayout>
MainActivity.java
Java側はこんな感じ
引っ張った時のイベントはmSwipeRefresh.setOnRefreshListener()
で設定
自動スクロールについてはmListView.setOnScrollListener()
で表示位置を監視して、
末尾に来たら処理を実行する感じ
public class MainActivity extends Activity { SwipeRefreshLayout mSwipeRefresh; ListView mListView; ArrayAdapter<String> mAdapter; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mSwipeRefresh = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh); mListView = (ListView) findViewById(android.R.id.list); mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1); mListView.setAdapter(mAdapter); //Swipe Refresh Layout mSwipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { //リフレッシュ時の読み込み処理 // 処理が終わったら、"mSwipeRefresh.setRefreshing(false);"を呼び出して非表示にする } }); mSwipeRefresh.setColorSchemeResources(R.color.green, R.color.red, R.color.blue, R.color.yellow); //自動スクロール mListView.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (totalItemCount > 0 && mAdapter.getCount() > 0) { if (totalItemCount == firstVisibleItem + visibleItemCount * 2) { // 自動スクロールの読み込み処理 } } } }); } }
以上!!
偉大なる参考にしたサイト様
本家(公式)
- Android Design Support Library | Android Developers Blog
- Color - Style - Google design guidelines
- Material icons - Google Design
カラーパレットやアイコン素材も充実しているので素敵
全体
- Android Support Library v22.2 の Design Support Libraryをひと通り使って罠を踏んだ - Qiita
- Android - Material Design を全力で取り込んだはてなブックマークリーダーを作ってみた - Qiita
- Design Support Library v22.2.0について Part 3 - EDIT MODE
ToolBar
- AndroidのToolBar(新しいActionBar)メモ - Qiita
- Android: Changing the Toolbar’s text color and overflow icon color | Murray's Blog
- MaterialDesignことはじめ ActionBar編 - Qiita
TabLayout
DrawerLayout/NavigationView
- NavigationViewを使ってGoogle Play風のメニューを作る【Android Design Support Library】 - Qiita
- 【Android】NavigationDrawerを右側に表示する - Qiita