android M新控件有很多,Toolbar,TabLayout,AppBarLayout,NavigationView,CoordinatorLayout,CollapsingToolbarLayout等等。寫出這篇文章純粹因為本人記憶力不行,特意來此記錄,如有不對的地方,還請幫忙糾正!
如果想快速的認識怎麽用以上控件,Google推出的Android Studio已經把整個Material整合成一個Model,大家直接Create New Project就能很直觀的知道怎麽用了~下面這張圖為整個Material的Medel
以下就分模塊來介紹各控件
首先先引入design包:
compile 'com.android.support:design:23.4.0'
AppBarLayout嵌套Toolbar與TabLayout
與 Actionbar 相比, Toolbar 明顯要靈活的多。它不像 Actionbar 一樣,一定要固定在Activity的頂部,而是可以放到界面的任意位置。Google留給了開發者很多可定制修改的余地,這些可定制修改的屬性在API文檔中都有詳細介紹
效果如下:
布局文件如下:
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout 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" android:background="@color/colorAccent" android:fitssystemWindows="true" > <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorAccent" app:layout_scrollFlags="scroll|enterAlways" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /> <android.support.design.widget.TabLayout android:id="@+id/tab" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorAccent" app:tabMode="fixed"/> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white" app:layout_behavior="@string/appbar_scrolling_view_behavior"/> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="end|bottom" android:layout_margin="16dp" android:src=http://blog.csdn.net/q417190240/article/details/"@mipmap/ic_notifications"/> </android.support.design.widget.CoordinatorLayout>
註意以下幾點:
- 為了ToolBar可以滾動,CoordinatorLayout裏面,放一個帶有可滾動的View.如上的例子,放的是ViewPager,而ViewPager裏面是放了RecylerView的,即是可以滾動的View。
- CoordinatorLayout中的
android:fitsSystemWindows="true"
是必寫的,不然你的Toolbar會與狀態欄重疊在一起; - CoordinatorLayout包含的子視圖中帶有滾動屬性的View需要設置app:layout_behavior屬性,如ViewPager控件;
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
這幾句是完全純手打,沒有提示!(對於我這老年人腦袋實在是一個考驗TAT)
為了使得Toolbar有滑動效果,必須做到如下三點:
1. CoordinatorLayout作為布局的父布局容器。
2. 給需要滑動的組件(本身沒有滑動功能)設置 app:layout_scrollFlags=”scroll|enterAlways” 屬性。
3. 給滑動的組件(本身有滑動功能)設置app:layout_behavior屬性
而scrollFlags會有幾個屬性值:
1.scroll: 所有想滾動出屏幕的view都需要設置這個flag, 沒有設置這個flag的view將被固定在屏幕頂部。例如,TabLayout 沒有設置這個值,將會停留在屏幕頂部。
2.snap:當下拉不到一定高度時,Toolbar回彈回去,如果上滑不到一定高度,Toolbar不會收縮。但是上滑時會全隱藏Toolbar
3.enterAlways: 設置這個flag時,向下的滾動都會導致該view變為可見,啟用快速“返回模式”。
4.enterAlwaysCollapsed: 當你的視圖已經設置minHeight屬性又使用此標誌時,你的視圖只能已最小高度進入,只有當滾動視圖到達頂部時才擴大到完整高度。
5.exitUntilCollapsed: 滾動退出屏幕,最後折疊在頂端,向下滑時要等item是第一個時才能滑出Toolbar。
部分代碼如下:
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); supportRequestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_coordinator); mToolbar = (Toolbar) findViewById(R.id.toolbar); //如果你的主題沒有設置NoActionbar且沒有調用supportRequestWindowFeature(Window.FEATURE_NO_TITLE);下面這句話報錯 setSupportActionBar(mToolbar); fab = (FloatingActionButton) findViewById(R.id.fab); mViewPager = (ViewPager) findViewById(R.id.viewpager); mTabLayout = (TabLayout) findViewById(R.id.tab); initData(); } private void initData() { //模擬數據 list = new ArrayList<>(); for (int i = 0; i < 100; i++) { list.add("item" + i); } //如果沒有調用getSupportActionBar().setDisplayShowTitleEnabled(false);主標題會顯示默認的app名稱 if (getSupportActionBar() != null) getSupportActionBar().setDisplayShowTitleEnabled(false); if (fab != null) fab.setOnClickListener(this); mToolbar.setLogo(R.mipmap.ic_launcher);//Logo mToolbar.setSubtitle("副標題");//副標題 mToolbar.setTitle("首頁");//主標題 mToolbar.setSubtitleTextColor(Color.GREEN);//小標題顏色 mToolbar.setTitleTextColor(Color.BLUE);//主標題顏色 mToolbar.setNavigationIcon(R.mipmap.ic_drawer_home);//側邊欄圖標 mViewPager.setAdapter(new MyPagerAadapter()); mTabLayout.setSelectedTabIndicatorColor(Color.BLUE);//tab選定時指示器的顏色 mTabLayout.setupWithViewPager(mViewPager); }
Toolbar點擊事件代碼如下:
@Override public void onClick(View v) { if (v == fab) count();//提醒回收垃圾 Snackbar.make(v, "結束Activity", Snackbar.LENGTH_SHORT) .setAction("Finish", new View.OnClickListener() { @Override public void onClick(View v) { //點擊Action按鈕後的操作 finish(); } }).show(); } @Override public boolean onCreateOptionsMenu(Menu menu) { //在這裏綁定你的menu getMenuInflater().inflate(R.menu.main, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { //這裏是處理menu中選中item的地方 int id = item.getItemId(); if (id == R.id.action_setting) Toast.makeText(this, "點擊了Setting", Toast.LENGTH_SHORT).show(); else if (id == R.id.action_search) Toast.makeText(this, "點擊了Search", Toast.LENGTH_SHORT).show(); else if (id == R.id.action_notification) Toast.makeText(this, "點擊了Notification", Toast.LENGTH_SHORT).show(); return super.onOptionsItemSelected(item); }
這裏再提醒一點,Google官方說Snackbar是個輕量級的控件,比Toast交互性更好一些,但是比Dialog更輕量級,確實也是如此。但是連續點擊按鈕,會不斷生成Snackbar實例,這個時候內存是不斷增加的,以恒定的數量增加。所以自己創建了一個方法提醒回收。
private int TotalCount = 0; private int gcCount = 5; private void count() { TotalCount ++; if (TotalCount >= gcCount) { System.gc(); TotalCount = 0; } }
AppBarLayout嵌套CollapsingToolbarLayout
效果如下:
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout 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" android:fitsSystemWindows="true" > <android.support.design.widget.AppBarLayout android:id="@+id/appbar" android:layout_width="match_parent" android:layout_height="222dp" android:fitsSystemWindows="true" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <!--app:expandedTitleMarginEnd="60dp"標題距離右邊的距離,不設置也行--> <!--app:expandedTitleMarginStart="40dp"標題距離左邊的距離,不設置也行--> <android.support.design.widget.CollapsingToolbarLayout app:expandedTitleMarginEnd="60dp" app:expandedTitleMarginStart="40dp" android:layout_width="match_parent" android:layout_height="match_parent" app:contentScrim="?attr/colorPrimary" app:layout_scrollFlags="scroll|exitUntilCollapsed"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:src=http://blog.csdn.net/q417190240/article/details/"@mipmap/head" app:layout_collapseMode="parallax"/> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin" app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_behavior="@string/appbar_scrolling_view_behavior"> </android.support.v7.widget.RecyclerView> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="@dimen/fab_margin" android:clickable="true" android:src=http://blog.csdn.net/q417190240/article/details/"@mipmap/ic_notifications" app:layout_anchor="@id/appbar" app:layout_anchorGravity="bottom|right|end"/> </android.support.design.widget.CoordinatorLayout>
CollapsingToolbarLayout可實現Toolbar的折疊效果。
CollapsingToolbarLayout 提供以下屬性和方法使用:
1. Collapsing title:ToolBar的標題。你可以調用CollapsingToolbarLayout .setTitle(CharSequence)方法設置title,也可以用Toolbar.setTitle(CharSequence)設置title,CollapsingToolbarLayout 優先級高。
2. Content scrim:ToolBar被折疊到頂部固定時候的背景,你可以調用setContentScrim(Drawable)方法改變背景或者在屬性中使用
app:contentScrim=”?attr/colorPrimary”來改變背景。
3. Status bar scrim:狀態欄的背景,調用方法setStatusBarScrim(Drawable)。不過這個只能在Android5.0以上系統有效果。
4. Parallax scrolling children:CollapsingToolbarLayout滑動時,子視圖的視覺差,可以通過屬性app:layout_collapseParallaxMultiplier=”0.6”改變。值的範圍[0.0,1.0],值越大視察越大。
5. CollapseMode :子視圖的折疊模式,在子視圖設置,有兩種模式,一種是“pin”:固定模式,在折疊的時候最後固定在頂端;“parallax”:視差模式,在折疊的時候會有個視差折疊的效果。我們可以在布局中使用屬性app:layout_collapseMode=”parallax”來改變。
CoordinatorLayout 還提供了一個 layout_anchor 的屬性,連同 layout_anchorGravity 一起,可以用來放置與其他視圖關聯在一起的懸浮視圖(如 FloatingActionButton)。本例中使用FloatingActionButton。
通過下面的參數設置了FloatingActionButton的位置,兩個屬性共同作用使得FAB 浮動按鈕也能折疊消失,展現。
app:layout_anchor="@id/appbar" app:layout_anchorGravity="bottom|right|end"
使用CollapsingToolbarLayout實現折疊效果,需要註意幾點(其實的結合下Toolbar的註意項):
1. AppBarLayout高度要固定的;
2. AppBarLayout要設置
android:fitsSystemWindows="true"屬性,不然收縮後Toolbar與狀態欄重疊;
3. CollapsingToolbarLayout的子視圖設置layout_collapseMode屬性
4. 關聯懸浮視圖設置app:layout_anchor,app:layout_anchorGravity屬性
NavigationView
用於側滑菜單中的menu布局。
效果如下:
布局如下:
<?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" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawer_nav" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:openDrawer="start"> <android.support.design.widget.CoordinatorLayout 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" android:background="@color/colorAccent" android:fitsSystemWindows="true" > <android.support.design.widget.AppBarLayout android:fitsSystemWindows="true" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorAccent" app:layout_scrollFlags="scroll|enterAlways" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager android:background="#FFFFFF" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> </android.support.v4.view.ViewPager> </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" app:headerLayout="@layout/nav_header_main" app:menu="@menu/activity_main_drawer"/> </android.support.v4.widget.DrawerLayout>
其中NavigationView 中的 android:layout_gravity=”start” 屬性來控制抽屜菜單從哪邊滑出,一般“start ”從左邊滑出,“end”從右邊滑出。
這裏最主要的兩個屬性分別是:
1.app:headerLayout: 給NavigationView添加頭部布局
2.app:menu:給NavigationView添加menu菜單布局
app:headerLayout布局如下:
<?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="@dimen/nav_header_height" android:background="@drawable/side_nav_bar" android:gravity="bottom" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:theme="@style/ThemeOverlay.AppCompat.Dark"> <ImageView android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingTop="@dimen/nav_header_vertical_spacing" android:src=http://blog.csdn.net/q417190240/article/details/"@android:drawable/sym_def_app_icon"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingTop="@dimen/nav_header_vertical_spacing" android:text="Android Studio" android:textAppearance="@style/TextAppearance.AppCompat.Body1"/> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="[email protected]"/> </LinearLayout>
app:menu 布局如下:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <group android:checkableBehavior="single"> <item android:id="@+id/nav_camera" android:icon="@drawable/ic_menu_camera" android:title="Import"/> <item android:id="@+id/nav_gallery" android:icon="@drawable/ic_menu_gallery" android:title="Gallery"/> <item android:id="@+id/nav_slideshow" android:icon="@drawable/ic_menu_slideshow" android:title="Slideshow"/> <item android:id="@+id/nav_manage" android:icon="@drawable/ic_menu_manage" android:title="Tools"/> </group> <item android:title="Communicate"> <menu> <item android:id="@+id/nav_share" android:icon="@drawable/ic_menu_share" android:title="Share"/> <item android:id="@+id/nav_send" android:icon="@drawable/ic_menu_send" android:title="Send"/> </menu> </item> </menu>
代碼如下:
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); supportRequestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_navigation); ``` drawer = (DrawerLayout) findViewById(R.id.drawer_nav); NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); //設置側滑菜單選擇監聽事件 navigationView.setNavigationItemSelectedListener(this); //設置側邊欄滑出的按鈕,會有動畫效果 ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, mToolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); drawer.setDrawerListener(toggle); toggle.syncState(); } //返回鍵的監聽 @Override public void onBackPressed() { if (drawer.isDrawerOpen(GravityCompat.START)) { drawer.closeDrawer(GravityCompat.START); } else { super.onBackPressed(); } } @SuppressWarnings("StatementWithEmptyBody") @Override public boolean onNavigationItemSelected(MenuItem item) { // Handle navigation view item clicks here. int id = item.getItemId(); if (id == R.id.nav_camera) { // Handle the camera action Toast.makeText(this, "click camera", Toast.LENGTH_SHORT).show(); } else if (id == R.id.nav_gallery) { Toast.makeText(this, "click gallery", Toast.LENGTH_SHORT).show(); } else if (id == R.id.nav_slideshow) { Toast.makeText(this, "click slideshow", Toast.LENGTH_SHORT).show(); } else if (id == R.id.nav_manage) { Toast.makeText(this, "click manage", Toast.LENGTH_SHORT).show(); } else if (id == R.id.nav_share) { Toast.makeText(this, "click share", Toast.LENGTH_SHORT).show(); } else if (id == R.id.nav_send) { Toast.makeText(this, "click send", Toast.LENGTH_SHORT).show(); } //關閉抽屜側滑菜單 drawer.closeDrawer(GravityCompat.START); return true; }
當然你可以通過如下方法或者屬性來改變這一狀態:
setItemBackgroundResource(int):給menu設置背景資源,對應的屬性app:itemBackground
setItemIconTintList(ColorStateList):給menu的icon設置顏色,對應的屬性app:itemIconTint
setItemTextColor(ColorStateList):給menu的item設置字體顏色,對應的屬性app:itemTextColor
關於NavigationView中item的字體顏色和icon選中狀態顏色是去當前主題theme中的
<--正常狀態下字體顏色和icon顏色--> <item name="android:textColorPrimary">@android:color/darker_gray</item> <--選中狀態icon的顏色和字體顏色--> <item name="colorPrimary">@color/accent_material_light</item>
如果想像圖中狀態欄和Toolbar顏色一樣,可這樣設置:
1. DrawerLayout、CoordinatorLayout、AppBarLayout都要設置android:fitsSystemWindows=”true”屬性;
2. CoordinatorLayout、Toolbar都要設置背景屬性,且顏色要一致;
3. 設置完第二步整個屏幕(CoordinatorLayout)都是同一個顏色,然後在ViewPager中設置背景為純白色。
最後來一張集成所有的:
最後提醒一點:原生的Model中會用到NestedScrollView,我還不了解,只是知道可以幫助item處理touch事件,在這之前,我們知道Android對Touch事件的分發是有自己一套機制的。主要是有是三個函數:
dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent,而NestedScroll有自己的一套touch處理方式。如果不想燒腦,就用我以上的方法吧~即用Viewpager做內容容器,然後用RecyclerView做item容器,RecyclerView本身支持NestedScroll。一朋友說用List會出現滑不動的情況,有興趣的朋友可以試試。
Tags:
文章來源: