Android Material Design(一)史上最全的材料設計控制元件大全
主要內容:
本文將要介紹Material design和Support library控制元件,主要包括TextInputLayout、SwitchCompat、SnackBar、FloatingActionButton、Shadows、Ripples、TabLayout、RecyclerView、Card、NavigationView、BottomSheet、Palette控制元件。
先來看下效果吧。
1. TextInputLayout:
TextInputLayout是用來增強EditText的,使用的時候也是在EditText包裹一層佈局,如:
<android.support.design.widget.TextInputLayout
android:id="@+id/til_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
<EditText
android:id="@+id/et_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="UserName"/>
</android.support.design.widget.TextInputLayout>
1>主要功能特色:
①當裡面的EditText獲取焦點後,EditText的hint文字,會移動到EditText的上面做Label,提示使用者。從上面的gif圖就看出了,我就不贅述了。
②具有錯誤提示機制,當用戶輸入的內容不符合要求時,可以提示使用者,以前我們都是用toast的方式,體驗很差。在佈局中設定app:errorEnabled=”true” 在程式碼中呼叫textInputLayout.setError(tip)方法,就可以在EditText的下方顯示錯誤內容。
③具有字數統計功能,很多情況下輸入文字都有文字字數限制,比如輸入反饋、描述等。以前我們都是自己去實現,現在好了,有系統控制元件幫我們實現了。通過下面的配置啟用該功能
app:counterEnabled="true"
app:counterMaxLength="50"
app:errorEnabled="true"
2> 具體的使用詳解
由於篇幅的原因,下面的講解,我就不每個屬性值都去改下,然後貼出圖片,這樣也沒有任何必要,希望需要的同學,自己去試試。程式碼會在後面有github連結。
紙上得來終覺淺,絕知此事要躬行
①如何更改EditText的下方的橫線的顏色。如下圖所示:
這個顏色的控制是在樣式檔案裡設定的,通過
<item name="colorAccent">@color/colorAccent</item>
② 如何更改獲取焦點後,上面Label的顏色/大小等。如下圖所示:
這個顏色大小等屬性修改通過
app:hintTextAppearance="@style/HintAppearance"
本工程裡的樣式是這樣的:
<style name="HintAppearance" parent="TextAppearance.AppCompat">
<item name="android:textSize">14sp</item>
<item name="android:textColor">#8bc34a</item>
</style>
③如何修改錯誤提示的顏色,如下圖所示:
錯誤的樣式通過如下方式修改:
app:errorTextAppearance="@style/ErrorAppearance"
<style name="ErrorAppearance" parent="TextAppearance.AppCompat">
<item name="android:textSize">14sp</item>
<item name="android:textColor">#a2ced1</item>
</style>
需要注意的是,該屬性不止改變的是錯誤文字的顏色、大小,還修改了EditText的的那條橫線的顏色。
如果不想在編寫TextInputLayout佈局的時候都去設定,還可以通過style檔案去統一設定,如:
<item name="textColorError">@color/textColorError</item>
當然,如果你設定了errorTextAppearance同時又設定了textColorError,TextInputLayout會優先使用errorTextAppearance配置的顏色。
④ 字數統計功能,修改錯誤的有顏色和上面是一樣。如何修改統計字數
的樣式。如下圖:
這裡分兩種情況,一種是沒有超過的情況,另一種是超過字數的情況。
//沒有超過最大字數
app:counterTextAppearance="@style/CounterAppearance"
//超過最大字數
app:counterOverflowTextAppearance="@style/CounterOverflowAppearance"
使用TextInputLayout遇到的一些坑:
① 如果加上字數統計需要在style里加上textErrorColor,否則超過字數會後會閃退。
② 如果不需要字數統計,且啟用錯誤機制(setErrorEnabled(true)), 不需要加上textErrorColor(不會閃退)系統會提供一個預設的error color。
當然可以通過textErrorColor來自定義錯誤顏色(error color).
可以使用更為強大的errorTextAppearance來定義錯誤顏色,字型大小等屬性。如果TextInputLayout 同時 設定了textErrorColor和errorTextAppearance ,只有errorTextAppearance生效.
③ 如果加上字數統計,且同時設定了textErrorColor和errorTextAppearance。
這個時候回出現奇怪的效果,Label
和統計
的顏色為textErrorColor的顏色。
EditText的橫線
和 錯誤文字提示
為errorTextAppearance設定的效果。所以為什麼不加上textErrorColor會閃退,因為超過字數後TextInputLayout需要textErrorColor屬性設定的顏色。
2 SwitchCompat
效果圖我就不上了,文章開頭就已經有了。 這個控制元件使用也非常簡單。下面就說一下其他相關用法:
//SwitchCompat被豎線隔開
switchCompat.setSplitTrack(false);
//SwitchCompat右邊會出現錯誤提示
switchCompat.setError("error");
//是否顯示文字[預設為 開啟/關閉](當然也可以自定義文字)
switchCompat.setShowText(true);
//自定義文字
switchCompat.setTextOff("Off");
switchCompat.setTextOn("On");
//設定左邊文字和右邊按鈕的距離
switchCompat.setSwitchPadding(20);
//設定關閉和開啟
switchCompat.setChecked(true/false);
//監聽switchCompat開啟和關閉變化
switchCompat.setOnCheckedChangeListener();
//設定Track圖示
switchCompat.setTrackResource(R.mipmap.ic_back_gray);
//switchCompat設定指示圖示[但是開啟和關閉都是一個圖示,可以在setOnCheckedChangeListener裡動態設定]
switchCompat.setThumbResource(R.mipmap.ic_back_gray);
希望有需要的同學,把github上面的工程下載下來,然後開啟這些方法,執行看看效果。在這裡我就不貼圖了。
3. SnackBar、FloatingActionButton、Shadows、Ripples
因為這些都比較簡單,我就放在一起說了。
1> SnackBar 使用方法很簡單[和Toast差不多],如下所示:
//帶按鈕的
Snackbar.make(container, "Snackbar with action", Snackbar.LENGTH_SHORT)
.setAction("Action", new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(v.getContext(), "Snackbar Action pressed",Toast.LENGTH_SHORT).show();
}
}).show();
//純文字的
Snackbar.make(container, "This is Snackbar", Snackbar.LENGTH_SHORT).show();
2> FloatingActionButton
使用方法:
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:clickable="true"
android:src="@null"
app:backgroundTint="#0091eb"
app:fabSize="normal"/>
通過android:src修改圖片
通過app:backgroundTint修改背景顏色
通過app:fabSize設定大小,只有兩個選項normal和mini
3> Shadows
在佈局中設定陰影
android:elevation="2dp"
app:elevation="2dp" //如果在Toolbar等控制元件,一定要加上這句,否則設定無效
4> Ripple效果
在res目錄下新建drawable-v21. 然後建一個資原始檔 如下所示:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#dcdcdc"> //android:color 按下去的效果
<item> //預設效果
<shape>
<solid android:color="#0091eb" />
<corners android:radius="2dp" />
</shape>
</item>
</ripple>
需要注意的是,需要在drawable目錄下新建同樣名稱的資原始檔,否則在低版本上執行去閃退,因為找不到該檔案,drawable-v21只在android5.0或以上系統有效。
4 Toolbar+TabLayout+RecyclerView+Card
1> Toolbar的使用
在佈局中:
<android.support.v7.widget.Toolbar
android:id="@+id/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="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:title="@string/app_name"/>
在Java程式碼中設定Toolbar相關屬性
Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar);
if (toolbar != null) {
toolbar.setNavigationIcon(R.mipmap.ic_back_white);//設定返回按鈕的icon
if (title != null) {
toolbar.setTitle(title);//設定title
}
AppCompatActivity activity = (AppCompatActivity) getActivity();
activity.setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(new View.OnClickListener() { //返回按鈕的點選事件
@Override
public void onClick(View v) {
finish();
}
});
activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);//顯示返回按鈕
}
如何設定Toolbar按鈕
首先在menu資料夾下新建選單檔案人,如:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/fixed"
android:title="Fixed"/>
<item
android:id="@+id/scroll"
android:title="Scrollable"/>
</menu>
//設定選單
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.tab_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
//處理選單的點選事件
@Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.fixed:
tabLayout.setTabMode(TabLayout.MODE_FIXED);
break;
case R.id.scroll:
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
break;
}
return super.onOptionsItemSelected(menuItem);
}
如果是在fragment使用menu,需要在onCreate方法裡呼叫 setHasOptionsMenu(true);
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
2> TabLayout
TabLayout屬於design支援包下,所以需要在gradle載入相關配置:
compile 'com.android.support:design:23.4.0'
TabLayout一般和ViewPager一起結合使用:
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
style="@style/TabLayoutStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
app:tabContentStart="50dp"
app:tabMode="scrollable"/>
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
使用其實非常簡單,關鍵就一個方法:
tabLayout.setupWithViewPager(viewPager);
完整程式碼如下所示:
viewPager.setAdapter(new ViewPagerAdapter(
Arrays.asList("Tab1", "Tab2", "Tab3", "Tab4", "Tab5", "Tab6"),
Arrays.asList(new RecyclerViewFragment(), new RecyclerViewFragment(),
new RecyclerViewFragment(), new RecyclerViewFragment(),
new RecyclerViewFragment(), new RecyclerViewFragment()
)));
tabLayout.setupWithViewPager(viewPager);
TabLayout還可以設定滾動和螢幕填充。
通過以下兩個方法設定即可:
tabLayout.setTabMode(TabLayout.MODE_FIXED);
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
效果圖我就不貼出來了。
在TabLayout.MODE_SCROLLABLE模式下還可以設定左邊的padding:
app:tabContentStart=”50dp”
下面是Adapter
程式碼
class ViewPagerAdapter extends FragmentStatePagerAdapter {
private List<String> list;
private List<? extends Fragment> fs;
public ViewPagerAdapter(List<String> list, List<? extends Fragment> fs) {
super(getChildFragmentManager());
this.list = list;
this.fs = fs;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Fragment getItem(int position) {
return fs.get(position);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
return super.instantiateItem(container, position);
}
@Override
public CharSequence getPageTitle(int position) {
return list.get(position);
}
}
3> RecyclerView
RecyclerView 是ListView的替代者,使用方法也相似,只不過方法名都替我們規範好了。
RecyclerView功能方面比ListView更加強大。比如動畫、橫向滾動、瀑布流等。
從使用角度上講,RecyclerView不僅要設定adapter,還要設定layoutManager,layoutManager也就是相對於listView強大的地方。
系統內建的LayoutManager有:
LinearLayoutManager
、GridLayoutManager
、StaggeredGridLayoutManager
下面具體說下用法:
recyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(recyclerView.getContext());
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(new RecyclerAdapter(list));
下面是 adapter
public class RecyclerAdapter extends RecyclerView.Adapter {
private List<String> list;
public RecyclerAdapter(List<String> list) {
this.list = list;
}
//建立Holder和ListView中一樣。
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ItemViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_card_view, parent, false));
}
//繫結資料
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
ItemViewHolder itemViewHolder = (ItemViewHolder) holder;
itemViewHolder.tvTitle.setText(list.get(position));
itemViewHolder.tvDesc.setText(list.get(position) + " this is description");
}
@Override
public int getItemCount() {
return list.size();
}
static class ItemViewHolder extends RecyclerView.ViewHolder {
TextView tvTitle, tvDesc;
public ItemViewHolder(View itemView) {
super(itemView);
tvTitle = (TextView) itemView.findViewById(R.id.tv_vibrant);
tvDesc = (TextView) itemView.findViewById(R.id.title_desc);
}
}
}
需要說明的地方已經註釋了,就不贅述了!
4> CardView
CardView屬於V7包下,所以需要加入如下配置:
compile 'com.android.support:cardview-v7:23.4.0'
CardView使用非常簡單,配置下就可以了:
<android.support.v7.widget.CardView
android:id="@+id/card_view"
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"
android:background="#ffffff"
app:cardCornerRadius="2dp"
app:cardElevation="3dp"/>
兩個重要的屬性:
app:cardCornerRadius=”2dp” 設定圓角
app:cardElevation=”3dp” 設定陰影
5 NavigationView
NavigationView主要是結合DrawerLayout來使用的。
下來看下佈局:
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawer_layout"
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">
<include layout="@layout/navigation_container_view"/>
<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/app_header"
app:insetForeground="@color/colorPrimaryDark"
app:menu="@menu/navigation_menu"/>
</android.support.v4.widget.DrawerLayout>
從上面的佈局可以看出NavigationView 分兩部分,一個是header,一個是menu。
① 如何修改icon和text的顏色
從文章開頭的GIF可以看到,背景是藍色的,menu的按鈕和文字是黑色的,怎麼修改呢?
可以通過如下配置修改:
app:itemIconTint="#2196f3" 給icon著色
app:itemTextColor="#009688" menu文字顏色
app:itemBackground="@drawable/my_ripple" 設定menu item的背景
效果如下:
②如何修改 Toolbar 左邊漢堡圖示
的顏色
通過開頭的那個GIF圖可以看到 ,Toolbar左邊的icon是黑色的,這個icon網上也叫 hamburger icon
,形似漢堡,所以網上很多人叫做hamburger icon。
通過一個樣式就可以修改了:
<style name="DrawerArrowStyle" parent="@style/Widget.AppCompat.DrawerArrowToggle">
<item name="spinBars">true</item>
<item name="color">@android:color/white</item> //custom color
</style>
//然後在style中加上就可以了
<item name="drawerArrowStyle">@style/DrawerArrowStyle</item>
下面是完整的menu佈局:
<group android:checkableBehavior="single">
<item
android:id="@+id/nav_search1"
android:checked="true"
android:icon="@mipmap/ic_search_black"
android:title="Search1"/>
<item
android:id="@+id/nav_search2"
android:checked="true"
android:icon="@mipmap/ic_search_black"
android:title="Search2"/>
<item
android:id="@+id/nav_search3"
android:icon="@mipmap/ic_search_black"
android:title="Search3"
app:actionLayout="@layout/menu_action_layout"/>
<item
android:id="@+id/nav_search4"
android:icon="@mipmap/ic_search_black"
android:title="Search4"/>
<item
android:id="@+id/nav_search5"
android:icon="@mipmap/ic_search_black"
android:title="Search5"
android:visible="false"/>
</group>
<item
android:id="@+id/navigation_subheader"
android:title="SubHeader">
<menu>
<item
android:id="@+id/nav_search6"
android:checked="true"
android:icon="@mipmap/ic_search_black"
android:title="Search6"/>
<item
android:id="@+id/nav_search7"
android:checked="true"
android:icon="@mipmap/ic_search_black"
android:title="Search7"/>
</menu>
</item>
<group android:id="@+id/aligned_items">
<item
android:id="@+id/nav_search8"
android:icon="@mipmap/ic_search_black"
android:title="Search8"/>
<item
android:id="@+id/nav_search9"
android:icon="@mipmap/ic_search_black"
android:title="Search9"/>
</group>
</menu>
效果如下:
③ 修改menu裡的 SubHeader 顏色
從上面的圖我們發現SubHeader是黑色的,怎麼修改顏色, 加上下面的配置即可:
<item name="android:textColorSecondary">#ffffff</item>
BottomSheet
BottomSheet 其實就是個Behavior,並且這個Behavior內建的,無需自己定義,使用非常簡單,只需要在佈局的時候配置behavior即可,從這裡可以看出,behavior的強大了吧,後面有時間研究下自定behavior,然後再來和大家一起討論、分享。
Palette
Palette 中文意思問,調色器。就是你給它一張圖片,通過palette可以獲取各種顏色。
其實Google官方已經給出了,很好的例子,在google demo裡面做出了非常詳解的使用示例,我這裡只做拋磚引玉的作用,需要的同學可以去github上去下載google demo。我這裡給下google的效果圖: