Android6.0-新控制元件(一)
前言
谷歌在2015年I/O大會上釋出了Android M的新版本.在這次的I/O大會上,谷歌對Android並沒有做很大的改變,主要完善之前的Android L版本.不過這次谷歌在繼Material Design風格之後,做了很多風格上的相容,並推出了Android Design Support Library庫,全面支援Material Design設計風格的UI效果.該庫包含了FloatingActionButton,TextInputLayout,Snackbar,TabLayout,NavigationView,CoordinatorLayout,AppBarLayout,CollapsingToolbarLayout八個新控制元件.由於篇幅的原因,我們先來學習一下前四個的使用.後續會繼續完成其餘控制元件的使用.
使用
需要匯入Android Design Support Library庫,該庫支援Android 2.1以上裝置.在build.gradle(moudle:app)中新增依賴:compile 'com.android.support:design:24.2.1'
版本號可自己匹配.
FloatingActionButton
效果圖:
<android.support.design.widget.FloatingActionButton android:id="@+id/fab_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|right" android:src="@drawable/ic_favorite" android:layout_margin="10dp" app:backgroundTint="@color/colorPrimary" app:elevation="4dp" app:pressedTranslationZ="8dp" app:fabSize="normal" app:rippleColor="@color/colorPrimaryDark" app:useCompatPadding="false" />
注意:
設定FloatingActionButton的背景顏色時使用:app:backgroundTint,預設為 Theme 主題中的 “colorAccent”的顏色;如果使用android:backgroundTint執行時,則會報解析Xml異常.
設定FloatingActionButton的大小,通過app:fabSize屬性來設定,有三種格式:auto(基於視窗的大小而自動適應),normal(正常大小的按鈕),mini(迷你大小的按鈕).這裡設定layout_width和layout_height貌似沒有什麼效果,FloatingActionButton的大小由fabSize屬性來決定.可當你把寬和高設定成match_parent時,FloatingActionButton的大小會充滿父窗體,大小雖然改變了,但這樣的設定在開發中貌似沒一點卵用.
app:elevation :設定 FloatingActionButton 陰影的深度,預設有陰影.
app:pressedTranslationZ :設定 FloatingActionButton 點選時陰影的大小.
app:rippleColor :設定 FloatingActionButton 點選時的顏色,也就是設定上面屬性後,陰影的顏色.
app:useCompatPadding :設定是否啟用compat的填充.
src - 設定FAB的圖示,Google建議符合Design設計的該圖示大小為24dp.
app:layout_anchor - 設定FAB的錨點,即以哪個控制元件為參照點設定位置.
app:layout_anchorGravity - 設定FAB相對錨點的位置,值有 bottom、center、right、left、top等.
以上在Xml佈局中設定的屬性,在程式碼中同樣可以設定.
Snackbar
簡介: Snackbar用於展示一條簡短的訊息給使用者,該訊息在很多的時間內會消失.該訊息只是給使用者一個提示,使用者不需要去操作.例如:當我們傳送一條Email時,告訴使用者該Email傳送的狀態.Snackbar和Toast很像,只不過Toast是在螢幕中心彈出,而Snackbar是在螢幕底部彈出.
使用:程式碼中使用
//得到Snackbar物件 final Snackbar snackbar = Snackbar.make(coordinatorLayout, "我是Snackbar...", Snackbar.LENGTH_LONG); //設定Snackbar背景 snackbar.getView().setBackgroundResource(R.color.colorPrimary); snackbar.show(); //顯示帶Action的Snackbar snackbar.setAction("取消", new View.OnClickListener() { @Override public void onClick(View v) { //關閉Snackbar snackbar.dismiss(); } });
常用方法:
- make() 方法,生成Snackbar訊息物件,第一個引數為View物件,Snackbar 會試著尋找一個父 View 來 hold 這個 View。Snackbar 將遍歷整個 View tree 來尋找一個合適的父 View,它可能是一個 coordinatorLayout 也可能是 window decor’s content view,隨便哪一個都行.後面的兩個引數和Toast一致.
- setDuration() 方法:設定顯示持續時間.
- setAction() 方法:設定 Action,第一個引數會作為按鈕(Actiong)的文字,第二個引數是按鈕的點選事件.
- setCallback() 方法:Snackbar 的顯示和消失會回撥 Snackbar.Callback的 onDismissed()和 onShown()方法.
- getView():獲取 Snackbar 的 View,進而可以定製Snackbar.
注意:
- 谷歌其實更建議在CoordinatorLayout(不要著急,後面會細說)佈局中使用Snackbar(make()方法中傳入的View),當用戶滑動螢幕時,可以使Snackbar消失.
- 當然,如果你只是想在底部彈出提示訊息,那麼make()方法中傳入的任意的View即可.
- 還有就是當你點選FloatingActionButton時,想彈出Snackbar,同時又想避免Snackbar遮蓋住FloatingActionButton,這時,你應該使用CoordinatorLayout來協調各個View之間的動畫效果.
效果圖:設定點選FloatingActionButton的點選事件,點選彈出Snackbar.
TextInputLayout
簡介: TextInputLayout的出現是Google為EditText提供的浮動標籤,使其更符合Material Design的風格.TextInputLayout繼承LinearLayout,它只是一個容器,不過該容器下只接收一個元素,子元素就是一個EditText元素.這樣就為EditText提供了一個帶有動畫效果的提示標籤,同時也可以處理錯誤資訊,將錯誤資訊提示在EditText的下方.
使用:
佈局:
<android.support.design.widget.TextInputLayout android:id="@+id/til_username" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:layout_marginRight="30dp" android:layout_marginTop="20dp"> <!--這裡可以直接使用EditText--> <android.support.design.widget.TextInputEditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Username" /> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout android:id="@+id/til_password" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:layout_marginRight="30dp" android:layout_marginTop="10dp"> <android.support.design.widget.TextInputEditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Password" android:inputType="textPassword" /> </android.support.design.widget.TextInputLayout>
程式碼:
//初始化TextInputLayout(程式碼中我使用了ButterKnife註解,這裡就不貼出來了) //得到EditText物件 final EditText userEditText = tilUsername.getEditText(); final EditText pwdEditText = tilPassword.getEditText(); //設定hint提示,也可直接在xml中設定(個人感覺如果在佈局中已經設定了hint,程式碼中就不必在設定了.) //userEditText.setHint("Username"); //pwdEditText.setHint("Password"); //EditText新增文字變化監聽 userEditText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { Log.d(TAG, "beforeTextChanged執行了....s = " + s + "---start = " + start + "---count = " + count + "---after = " + after); } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { Log.d(TAG, "onTextChanged執行了....s = " + s + "---start = " + start + "---count = " + count + "---before = " + before); if (s.length() > 7) { tilUsername.setErrorEnabled(true);//設定是否開啟錯誤提示 tilUsername.setError("使用者名稱長度不能超過8個");//設定錯誤提示的資訊 } else { tilUsername.setErrorEnabled(false); } } @Override public void afterTextChanged(Editable s) { Log.d(TAG, "afterTextChanged執行了....s = " + s); } }); pwdEditText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if (s.length() < 6) { tilPassword.setErrorEnabled(true); tilPassword.setError("密碼長度不能小於6個"); } else { tilPassword.setErrorEnabled(false); } } @Override public void afterTextChanged(Editable s) { } });
注意:程式碼裡註釋已經很詳細了,相信你一看就能明白.這裡提一點:就是浮動標籤字型的顏色預設是你設定主題時的顏色.
設定主題的顏色就是EditText浮動標籤提示資訊的顏色:
<item name="colorAccent">@color/colorAccent</item>
效果圖:這裡模擬登入介面。並對使用者名稱長度是否超過8個,密碼長度是否小於6個做了判斷。
TabLayout
- 簡介: TabLayout提供了一個水平佈局顯示標籤,主要用來做選顯示卡切換這一類效果的控制元件。例如:網易新聞客戶端的Tab。Github上也有很多類似效果的開源控制元件,只是這次谷歌把它官方化了,更方便開發者使用。
簡單TabLayout效果圖:
使用:
xml:
<android.support.design.widget.TabLayout android:id="@+id/tab_layout" android:layout_width="match_parent" android:layout_height="wrap_content" app:tabIndicatorColor="@android:color/holo_blue_bright" //Tab指示器下標的顏色 app:tabSelectedTextColor="@android:color/holo_blue_bright" //Tab被選中字型的顏色 app:tabTextColor="@android:color/black"> //Tab未被選中字型的顏色 </android.support.design.widget.TabLayout>
程式碼:
//新增8個Tab標籤,並設定第一個Tab標籤為選中狀態. tabLayout.addTab(tabLayout.newTab().setText("Tab 1"),true); tabLayout.addTab(tabLayout.newTab().setText("Tab 2")); tabLayout.addTab(tabLayout.newTab().setText("Tab 3")); tabLayout.addTab(tabLayout.newTab().setText("Tab 4")); tabLayout.addTab(tabLayout.newTab().setText("Tab 5")); tabLayout.addTab(tabLayout.newTab().setText("Tab 6")); tabLayout.addTab(tabLayout.newTab().setText("Tab 7")); tabLayout.addTab(tabLayout.newTab().setText("Tab 8")); //設定Tab的模式為可滑動,當tab標籤超過螢幕寬度時,可以滑動. tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
這裡只是簡單使用TabLayout完成Tabs選項卡,一般情況下TabLayout+ViewPager相結合使用,這樣的使用場景會更多一點,也能發揮出TabLayout的優勢。接下來使用TabLayout+ViewPager完成一個小Demo。
效果圖:(自定義TabLayout樣式+ViewPager使用)
使用:首先我們在Style中自定義TabLayout的樣式,在佈局中使用時引入自定義的TabLayout樣式.新增ViewPager,每個頁面是一個Fragment,並且實現聯動效果,下面直接看程式碼:
自定義TabLayout樣式:
<!-- 自定義 TabLayout 樣式 --> <style name="CustomTabLayout" parent="Widget.Design.TabLayout"> <item name="paddingEnd">10dp</item> <item name="paddingStart">10dp</item> <item name="tabBackground">@color/colorPrimary</item> <item name="tabContentStart">10dp</item> <item name="tabGravity">center</item> <item name="tabIndicatorColor">#999900</item> <item name="tabIndicatorHeight">6dp</item> <item name="tabMaxWidth">@dimen/tab_max_width</item> <item name="tabMinWidth">@dimen/tab_min_width</item> <item name="tabMode">scrollable</item> <item name="tabPaddingBottom">2dp</item> <item name="tabPaddingEnd">10dp</item> <item name="tabPaddingStart">10dp</item> <item name="tabPaddingTop">15dp</item> <item name="tabSelectedTextColor">#ffcc00</item> <item name="tabTextAppearance">@style/CustomTabTextAppearance</item> <item name="tabTextColor">#000066</item> </style> <!-- 自定義 TabText 的外觀 --> <style name="CustomTabTextAppearance" parent="TextAppearance.Design.Tab"> <item name="android:textSize">14sp</item> <item name="android:textColor">#006600</item> <item name="textAllCaps">false</item> </style>
頁面佈局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_tab_layout_view_pager" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.listenergao.mytest.activity.TabLayoutViewPagerActivity"> <include layout="@layout/toolbar_layout" /> <android.support.design.widget.TabLayout android:id="@+id/tab_layout" style="@style/CustomTabLayout" android:layout_width="match_parent" android:layout_height="wrap_content"> </android.support.design.widget.TabLayout> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent"> </android.support.v4.view.ViewPager> </LinearLayout>
頁面程式碼:(Activity頁面)
package com.listenergao.mytest.activity; import android.os.Bundle; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v4.view.ViewPager; import android.support.v7.widget.Toolbar; import android.widget.LinearLayout; import com.listenergao.mytest.R; import com.listenergao.mytest.data.TabFragmentAdapter; import com.listenergao.mytest.fragment.TabFragment; import java.util.ArrayList; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; /** * TabLayout+ViewPager示例 * * @author By ListenerGao * create at 2016/10/14 18:52 */ public class TabLayoutViewPagerActivity extends BaseActivity { @BindView(R.id.toolbar) Toolbar toolbar; @BindView(R.id.tab_layout) TabLayout tabLayout; @BindView(R.id.viewpager) ViewPager viewpager; @BindView(R.id.activity_tab_layout_view_pager) LinearLayout activityTabLayoutViewPager; private List<String> mTabList; private List<Fragment> mTabFragments; @Override protected int getLayoutResId() { return R.layout.activity_tab_layout_view_pager; } @Override protected void initView() { ButterKnife.bind(this); toolbar.setTitle("TabLayout+ViewPager"); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); } @Override protected void initData() { mTabList = initTabList(); initTabLayout(mTabList); mTabFragments = initFragments(mTabList); TabFragmentAdapter adapter = new TabFragmentAdapter(getSupportFragmentManager(),mTabFragments,mTabList); viewpager.setAdapter(adapter); //將TabLayout與ViewPager關聯起來(注意:該行程式碼需在ViewPager設定Adapter之後呼叫) tabLayout.setupWithViewPager(viewpager); //為Tabs設定介面卡 tabLayout.setTabsFromPagerAdapter(adapter); } /** * 初始化Tab標籤資料 * * @return */ private List<String> initTabList() { List<String> tabList = new ArrayList<>(); for (int i = 0; i < 8; i++) { tabList.add("TAB " + i); } return tabList; } /** * 初始化TabLayout * * @param list */ private void initTabLayout(List<String> list) { for (int i = 0; i < list.size(); i++) { if (i == 0) tabLayout.addTab(tabLayout.newTab().setText(list.get(i)), true); else tabLayout.addTab(tabLayout.newTab().setText(list.get(i))); } //設定TabLayout的模式為可滑動 tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE); } /** * 初始化Tab標籤對應的Fragment * * @param list 標籤集合資料 * @return */ public List<Fragment> initFragments(List<String> list) { List<Fragment> mTabFragments = new ArrayList<>(); for (int i = 0; i < list.size(); i++) { Fragment tabFragment = new TabFragment(); Bundle bundle = new Bundle(); bundle.putString("Content", list.get(i)); tabFragment.setArguments(bundle); mTabFragments.add(tabFragment); } return mTabFragments; } }
Viewpager介面卡:(這裡繼承的是FragmentStatePagerAdapter,因為可能有很多個Tab標籤頁面(Fragment).這裡不細說,可以自行google.)
package com.listenergao.mytest.data; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; import java.util.List; /** * ViewPager的介面卡 * * @author By ListenerGao * Create at 2016/10/15 16:36 */ public class TabFragmentAdapter extends FragmentStatePagerAdapter { private List<Fragment> mFragments; private List<String> mTabTitles; public TabFragmentAdapter(FragmentManager fm, List<Fragment> fragments,List<String> tabTitles) { super(fm); this.mFragments = fragments; this.mTabTitles = tabTitles; } @Override public Fragment getItem(int position) { return mFragments.get(position); } @Override public int getCount() { return mFragments.size(); } //注意:需要重寫此方法,從標籤集合中獲取到title,否則標籤上的title則不會顯示. @Override public CharSequence getPageTitle(int position) { return mTabTitles.get(position); } }
Tab標籤對應的Fragment頁面:
package com.listenergao.mytest.fragment; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.listenergao.mytest.R; import butterknife.BindView; import butterknife.ButterKnife; /** * Tab標籤對應的頁面 * * @author By ListenerGao * Create at 2016/10/15 16:53 */ public class TabFragment extends Fragment { @BindView(R.id.tv_content) TextView tvContent; private View view; private String content; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { Bundle bundle = getArguments(); content = bundle.getString("Content"); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment view = inflater.inflate(R.layout.fragment_tab, container, false); ButterKnife.bind(this, view); return view; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); tvContent.setText(content); } }
常用方法:
- 1,addTab(TabLayout.Tab tab, int position, boolean setSelected) 增加選項卡到 layout中,這是一個過載方法.第一個引數是Tab物件,通過Tablayout.newTab()建立;第二個引數是插入Tab的位置;最後一個引數是當前Tab是否為選中狀態.
- 2,newTab() 新建個 tab.
- 3,setTabMode(),設定 Mode,有兩種值:TabLayout.MODE_SCROLLABLE和TabLayout.MODE_FIXED分別表示當tab的內容超過螢幕寬度是否支援橫向水平滑動,第一種支援滑動,第二種不支援,預設不支援水平滑動.如果你新增的Tab很少的話,你應該把Tab的mode設定成MODE_FIXED,否則可能會出現Tab標籤不會佔滿螢幕的寬度.
- 4,setOnTabSelectedListener(TabLayout.OnTabSelectedListener onTabSelectedListener) 為每個 tab 增加選擇監聽器.
- 5,setScrollPosition(int position, float positionOffset, boolean updateSelectedText) 設定Tab滾動到的位置.
- 6,setTabGravity(int gravity) 設定 Gravity.
- 7,setTabTextColors(ColorStateList textColor) 設定 tab 中文字的顏色.
- 8,setTabTextColors(int normalColor, int selectedColor) 設定 tab 中文字的顏色 預設 選中的顏色.
- 9,setTabsFromPagerAdapter(PagerAdapter adapter) 將TabLayout與ViewPager關聯,當PageAdapter更新時,TabLayout會自動更新.(注意:該方法已過時)
- 10,setupWithViewPager(ViewPager viewPager) 設定Tablayout和ViewPager實現聯動效果.
- 11,getTabAt(int index) 得到選項卡.
- 12,getTabCount() 得到選項卡的總個數.
- 13,getTabGravity() 得到 tab 的 Gravity.
- 14,getTabMode() 得到 tab 的模式.
- 15,getTabTextColors() 得到 tab 中文字的顏色.
由於篇幅原因,NavigationView,CoordinatorLayout,AppBarLayout,CollapsingToolbarLayout會在下篇文章中介紹.
原始碼地址:(該功能是在我一個練手專案中寫的)