由谷歌的設計師基於傳統優秀設計原則,結合豐富的創意和科學技術所發明的一套全新的界面設計語言java
包含了視覺、運行、互動等效果android
Material Design的出現使得Android首次再UI方面全面超越了IOS網絡
此時就能解決不一樣操做系統之間的統一界面app
谷歌從5.0系統開始就將全部內置應用都使用Material Design風格來設計ide
主要是面向UI設計人員並非開發者。工具
以前的標題欄佈局
把系統的ActionBar隱藏測試
每一個活動頂部的標題欄就是ActionBar優化
ActionBar因爲設計緣由只能用於活動的頂部動畫
不能實現一些Material Design的效果
所以官方不建議使用ActionBar
Toolbar的槍法之處在於不只繼承了ActionBar的全部功能
並且靈活性高
能夠配合其餘控件完成一些Material Design的效果
任何一個項目默認都會顯示ActionBar的
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme">
打開res/values/styles.xml文件
<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style> </resources>
定義了一個AppTheme主題
而後指定它的parent主題
這裏的DarkActionBar是一個深色的Actionbar主題
以前的實踐中自帶的ActionBar就是指定了這個主題纔出現的
此時使用Toolbar來代替ActionBar
所以須要指定一個不帶ActionBar的主題
一般用:
前者:深色主題,會將界面的主題顏色設計成深色,襯托的顏色設計成淡色
後者:淡色主題,會將界面的主題顏色設計成淡色,襯托的顏色設計成深色
<?xml version="1.0" encoding="utf-8"?> <FrameLayout 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.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:layout_height="?attr/actionBarSize" app:popupTheme="@style/Theme.AppCompat.Light" /> </FrameLayout>
這裏首先引入app的約束
5.0系統以後纔可使用,以前的使用android:xx
因此須要引入新的約束
ToolBer控件由appcompat-v7庫提供的
此時指定id、寬度設置爲match_parent
高科設置爲actionBar的高度
背景色設置爲colorPrimary
再style.xml文件中將程序的主題指定成淡色主題
此時ToolBar的各類元素就會自動使用深色
目的是爲了和主題顏色進行區分
這裏可使用android:theme屬性,將主題指定爲指定的主題
這裏使用app:popupTheme將屬性將菜單選項指定成淡色主題,5.0以後新增的
使用app:popupTheme能夠兼容5.0以前的系統
MainActivity
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.action_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); } }
此時的效果
上述圖片中的文字是在:AndroidManifest.xml文件中
使用android:label進行設置顯示的內容
添菜單:
<?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/Back" android:title="返回" android:icon="@mipmap/ic_launcher" app:showAsAction="always"/> <item android:id="@+id/delete" android:title="刪除" android:icon="@mipmap/ic_launcher" app:showAsAction="ifRoom"/> <item android:id="@+id/setting" android:title="設置" android:icon="@mipmap/ic_launcher" app:showAsAction="never"/> </menu>
使用<item>標籤來定義action按鈕
app:showAsAction用於指定按鈕的顯位置可選值:
一、always:表示永遠如今再Toolbar中,屏幕不夠則不顯式
二、ifRoom:表示再屏幕控件足夠的狀況下再Toolbar中顯示,不夠的話顯示再菜單單中
三、never:永遠顯示再菜單選項當中
Toolbar中的action值會顯示圖標,菜單中只顯示文件
MainActivity
@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.toolbar,menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()){ case R.id.Back: Toast.makeText(this,"Back",Toast.LENGTH_LONG).show(); break; case R.id.delete: Toast.makeText(this,"delete",Toast.LENGTH_LONG).show(); break; case R.id.setting: Toast.makeText(this,"setting",Toast.LENGTH_LONG).show(); break; default: break; } return true; }
效果:
是MaterialDesign中常見效果之一
DrawerLayout是一個佈局
再佈局中容許放入兩個直接控件
第一個控件就是主屏幕顯示的內容
第二個控件就是滑動菜單中顯示的內容
<?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/drawe_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:layout_height="?attr/actionBarSize"
app:popupTheme="@style/Theme.AppCompat.Light"
/>
</FrameLayout>
<LinearLayout
android:id="@+id/left_drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#FFFFFF">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="This is menu"
android:textSize="25sp"
android:textColor="#dd033d"/>
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
DrawerLayout由support-v4庫提供
第一個子控件式FrameLayout,用於再主屏幕顯示內容
第二個子控件是LinearLayout,用於做爲滑動顯示內容
第二個控件注意:
layout_gravity這個屬性是必須指定的
由於須要告訴DrawerLayout滑動菜單是在屏幕的左邊仍是右邊
指定right再右邊,指定start,系統會進行判斷,系統語言是從左往右(英語,漢語等)滑動菜單再左邊
系統語言是從右往左的(阿拉伯)滑動菜單就在右邊
而後向左滑動菜單
或者點擊一個菜單以外的區域,滑動菜單就會關閉
從而回到主界面
不管隱藏菜單仍是滑動菜單都有很流暢的動畫過分
如今只有在屏幕的左側邊緣向右滑動才能顯示滑動菜單
在沒有提示的狀況下,用戶很難知道這個功能是如何實現的
Material Design建議在Toolbar的最左邊介入一個導航按鈕
點擊了按鈕也將會滑動菜單的內容顯示出來
這樣等於提供兩種方式給用戶
public class MainActivity extends AppCompatActivity { private DrawerLayout mdrawerLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.action_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar ); mdrawerLayout = (DrawerLayout) findViewById(R.id.drawe_layout); ActionBar actionBar = getSupportActionBar(); if (actionBar != null){ actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setHomeAsUpIndicator(R.mipmap.ic_launcher); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.toolbar,menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()){ case android.R.id.home: mdrawerLayout.openDrawer(GravityCompat.START); break; .... } return true; } }
首先獲得了DrawerLayout的實例
而後調用getSupportActionBar()方法獲得ActionBar的實例
雖然只能個ActionBar具的實現由Toolbar來完成
而後調用ActionBar的serDisplayHomeAsUpEnabled()方法來讓導航按鈕顯示出來
調用setHomeAsUpIndicator()方法來設置一個導航按鈕圖標
實際上,Toolbar最左側的這個按鈕叫作HomeAsUp按鈕,默認圖標是一個箭頭
含義是返回上一個圖標
最後在onOptionsItemSelected()方法中對HomeAsUp按鈕點擊事件進行處理
HomeAsUp按鈕的id永遠都是android.R.id.home
在調用DrawerLayout的openDrawer()方法將滑動菜單顯示出來
此時傳入一個Gravity參數
保持和XNL中的數據一直傳入GravityCompat.START
首先:
控件由Design Support庫提供
須要引入庫
第一行是Design Supprot庫
第二行是一個開源項目CircleImageView,能夠輕鬆實現圖片圓形化的功能
工程準備:menu、headerLayout
menu是在NavigationView中顯示的具體菜單
headerLayout用來在NavigationLayout中顯示頭部佈局的
nav_menu.xml
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <group android:checkableBehavior="single"> <item android:title="call" android:id="@+id/nav_call" android:icon="@mipmap/ic_launcher"/> <item android:title="friends" android:id="@+id/nav_friends" android:icon="@mipmap/ic_launcher"/> <item android:title="location" android:id="@+id/nav_location" android:icon="@mipmap/ic_launcher"/> <item android:title="mail" android:id="@+id/nav_mail" android:icon="@mipmap/ic_launcher"/> <item android:title="task" android:id="@+id/nav_task" android:icon="@mipmap/ic_launcher"/> </group> </menu>
使用<group>biaoqian
將group的checkableBehavior屬性指定爲single
標籤表示一個組
single表示全部菜單的選項只能單選
nav_header.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="180dp" android:padding="10dp" android:background="?attr/colorPrimary"> <de.hdodenhof.circleimageview.CircleImageView android:layout_width="70dp" android:layout_height="70dp" android:id="@+id/icon_image" android:src="@mipmap/ic_launcher" android:layout_centerInParent="true" /> <TextView android:layout_alignParentBottom="true" android:id="@+id/username" android:textSize="14sp" android:textColor="#fff" android:text="MrChengs" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:layout_above="@+id/username" android:id="@+id/mail" android:textSize="14sp" android:textColor="#fff" android:text="mrchengs666@163.com" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
實現頭像、用戶名、郵箱的顯示
最外面使用RelativeLayout
將寬度設置爲match_parent
高度設置爲180dp
這是一個NavifationView適合的高度
而後指定背景色
CircleImageView是一個用於圓形化的控件
用法很是簡單
和ImageView使用是徹底同樣的
指定一張圖片做爲頭像
而後劇中顯示
兩個TextView分別用於顯示用戶名和郵箱地址
修改主界面的佈局代碼:
<?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/drawe_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:layout_height="?attr/actionBarSize" app:popupTheme="@style/Theme.AppCompat.Light" /> </FrameLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="start"> <android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_width="match_parent" android:layout_height="match_parent" app:menu="@menu/nav_menu" app:headerLayout="@layout/nav_header" > </android.support.design.widget.NavigationView> </LinearLayout> </android.support.v4.widget.DrawerLayout>
這裏使用NavigationView
這樣滑動菜單就變成了NavigationView
經過app:menu、app:headerLayout屬性將menu和headerLayout設置進入
此時的NavigationView就定義完成
在MainActivity
在onCreate()方法中
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); navigationView.setCheckedItem(R.id.nav_call); navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { mdrawerLayout.closeDrawers(); return true; } });
setCheckedItem()將call菜單項設置爲默認選中
setNavigationItemSelectedListener()方法設置一個菜單選中事件的監聽器
當用戶點擊菜單項中的監聽器,就會回調onNavigationItemSelected()方法
此時掉喲給DrawerLayout的closeDrowers()方法將滑動菜單關閉
是Design Support庫提供的一個控件
能夠幫助咱們輕鬆的實現按鈕懸浮效果
<?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/drawe_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:layout_height="?attr/actionBarSize" app:popupTheme="@style/Theme.AppCompat.Light" /> <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:src="@mipmap/ic_launcher" android:id="@+id/fab" /> </FrameLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="start"> <android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_width="match_parent" android:layout_height="match_parent" app:menu="@menu/nav_menu" app:headerLayout="@layout/nav_header" > </android.support.design.widget.NavigationView> </LinearLayout> </android.support.v4.widget.DrawerLayout>
懸浮球下方會有一點陰影
FloatingActionButton是在當前頁面之上的
因此會有投影
使用app:elevation="8dp"指定懸浮高度
指定一個高度值,值越大投影範圍越大,投影效果越淡
翻譯亦然。
點擊事件:
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this,"fab",Toast.LENGTH_LONG).show(); mdrawerLayout.openDrawer(GravityCompat.START); } });
和普通按鈕的使用方法一致
Snackbar不是Toast的替代品
二者之間有者不一樣的應用場景
Toast用於告訴用戶如今發生了什麼事情,同時用戶只能被動接收這個事情,用戶沒辦法進行選擇
Snackbar容許在提示中加一個按鈕,當用戶點擊的適合能夠進行一些額外的操做
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mdrawerLayout.openDrawer(GravityCompat.START); Snackbar.make(v,"Data delete ",Snackbar.LENGTH_SHORT) .setAction("Undo", new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this,"數據恢復",Toast.LENGTH_LONG).show(); } }).show(); } });
調用Snackerbar的make()方法來建立一個Snackbar對象
make()方法:
第一個參數是一個View,只須要當前頁面佈局的任意的一個View均可以
第二個參數是Snackbar中顯示的內容
第三個參數是Snackbar的顯示時長
setAction()方法來設置一個動做
讓Snackbar不只僅是一個提示,用於和用戶進行交互
在點擊事件中裏面彈出一個Toast提示
最後調用show()方法讓Snackbar顯示出來
是一個增強版的FrameLayout
這個佈局Design Support庫提供的
廣泛狀況下與FrameLayout保持一致
還有一些其餘的使用
CoordinatorLayout能夠監聽其全部子控件的各類事件
而後自動幫助咱們作出最爲合理的響應
實例:
Snackbar提示將懸浮窗按鈕遮擋住了
若是能讓CoordinatorLayout監聽Snackbar的事件
那麼它會自動將內部的FloatingActionButton向上偏移
從而保證不會被Snackbar遮擋住
<?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/drawe_layout" 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.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:layout_height="?attr/actionBarSize" app:popupTheme="@style/Theme.AppCompat.Light" /> <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:src="@mipmap/ic_launcher" android:id="@+id/fab" /> </android.support.design.widget.CoordinatorLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="start"> <android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_width="match_parent" android:layout_height="match_parent" app:menu="@menu/nav_menu" app:headerLayout="@layout/nav_header" > </android.support.design.widget.NavigationView> </LinearLayout> </android.support.v4.widget.DrawerLayout>
此時的效果已經 比以前的實現更有顯著的效果
此時頁面上還有一塊空白區域
一般用來防止應用的主題內容
可使用一些圖片來填充這部分區域
CradView用於實現卡片式佈局效果的重要控件
由appcompat-v7提供
實際上也是FrameLayout,只是提供了圓角和陰影的等效果,看上去會有立體感
基本使用
在CradView佈局中放置一個TextView,這個TextView就會顯示在一張卡片之中了
須要引入依賴:
添加了一個Glide庫依賴
是一個超級強大的 圖片加載庫
不只能夠用於加載本地圖片還能加載網絡圖片、GIF甚至是本地時評等
用法很是簡單
首先修改:
<?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/drawe_layout" 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.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:layout_height="?attr/actionBarSize" app:popupTheme="@style/Theme.AppCompat.Light" /> //中間的空白頁面 <android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/recycler_view" > </android.support.v7.widget.RecyclerView> <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:src="@mipmap/ic_launcher" android:id="@+id/fab" /> </android.support.design.widget.CoordinatorLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="start"> <android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_width="match_parent" android:layout_height="match_parent" app:menu="@menu/nav_menu" app:headerLayout="@layout/nav_header" > </android.support.design.widget.NavigationView> </LinearLayout> </android.support.v4.widget.DrawerLayout>
添加一個RecyclerView
而且制定一個id
新建一個顯示圖片的實體類:
public class Images { private String name; private int imageId; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getImageId() { return imageId; } public void setImageId(int imageId) { this.imageId = imageId; } }
兩個字段
name表示名字
id表示對應的圖片id
新建一個佈局文件用於顯示Images
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView 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:layout_margin="5dp" app:cardCornerRadius="4dp"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:layout_width="wrap_content" android:layout_height="100dp" android:id="@+id/images_id" android:scaleType="centerCrop" /> <TextView android:id="@+id/images_text" android:layout_gravity="center_horizontal" android:textSize="16sp" android:layout_margin="5dp" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> </android.support.v7.widget.CardView>
是哦用CradView來做爲最外層佈局
使得RecyclerView中的每一個元素都是在卡片當中的
CardView因爲是一個FrameLayout
所以沒有什麼方便的定位方式
這裏在進行潛入一個LinearLayout中放置具體的內容
具體內容:
一、放置圖片的ImageView
二、TextView用於放置是圖片名字
新建一個適配器:
public class ImagesAdapter extends RecyclerView.Adapter<ImagesAdapter.ViewHolder> { private Context mContext; private List<Images> mImagesList; public ImagesAdapter(List<Images> imagesList){ mImagesList=imagesList; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (mContext == null){ mContext=parent.getContext(); } View view = LayoutInflater.from(mContext).inflate(R.layout.images_item,parent,false); return new ViewHolder(view); } @Override public void onBindViewHolder(ViewHolder holder, int position) { Images images = mImagesList.get(position); holder.textView.setText(images.getName()); Glide.with(mContext).load(images.getImageId()).into(holder.imageView); } @Override public int getItemCount() { return mImagesList.size(); } //內部類 class ViewHolder extends RecyclerView.ViewHolder{ CardView cardView; ImageView imageView; TextView textView; public ViewHolder(View itemView) { super(itemView); cardView = (CardView) itemView; imageView = (ImageView) itemView.findViewById(R.id.images_id); textView = (TextView) itemView.findViewById(R.id.images_text); } } }
在MainActivity
package com.example.ccrr.material; import android.support.annotation.NonNull; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.NavigationView; import android.support.design.widget.Snackbar; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Toast; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private DrawerLayout mdrawerLayout; private List<Images> imagesList = new ArrayList<>(); private ImagesAdapter imagesAdapter; private void init(){ for (int i=0;i<=10;i++){ Images images = new Images(); images.setName("圖片" + i); images.setImageId(R.drawable.image); imagesList.add(images); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.action_main); ...//卡片佈局 init(); RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); GridLayoutManager layoutManager = new GridLayoutManager(this,2); recyclerView.setLayoutManager(layoutManager); imagesAdapter = new ImagesAdapter(imagesList); recyclerView.setAdapter(imagesAdapter); }
...... }
此時有一個很嚴重的問題:
以前設置的Toolbar不見了
其實式被RecylerView遮擋住了
上述的測試中能夠發現RecyclerLayout會把Toolbar遮擋住
解決方法:
使用位偏移是惟一的解決方法
即讓RecylerView向下便宜一個Toolbar的高度
從而不會遮擋住Toolbar
項目中使用的不是簡單的LinearLayout,使用的是CoordinatorLayout,會有更加簡單的方法進行操縱
這裏使用Design Support庫中的另一個工具---AppBarLayout
其實是一個垂直方向上的LinearLayout
內部作了不少組件的封裝
而且使用了一些Material Design的設計理念
<?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/drawe_layout" 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/toolbar" android:layout_width="match_parent" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:layout_height="?attr/actionBarSize" app:popupTheme="@style/Theme.AppCompat.Light" /> </android.support.design.widget.AppBarLayout> //中間的空白頁面 <android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/recycler_view" app:layout_behavior="@string/appbar_scrolling_view_behavior" > </android.support.v7.widget.RecyclerView> <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:src="@mipmap/ic_launcher" android:id="@+id/fab" /> </android.support.design.widget.CoordinatorLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="start"> <android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_width="match_parent" android:layout_height="match_parent" app:menu="@menu/nav_menu" app:headerLayout="@layout/nav_header" > </android.support.design.widget.NavigationView> </LinearLayout> </android.support.v4.widget.DrawerLayout>
首先定義一個AppBarLayout,而且將Toolbar放在在其中
而後再RecylerLayout中使用app:layout_beehavior屬性
指定了一個佈局的行爲
其中appbar_scrolling_view_behavior這個字符串由Design support庫支持的
此時無缺的解決了遮擋問題
可是Material Design的設計裏面並無體現出來
實際上當RecylerView滾動的時候將事件通知給AppBarLayout
只是咱們還沒進行小狐狸
進一步優化
實現AppBarLayout的效果:
當AppBarLayout接收到滾動事件的時候
它內部的子控件實際上是能夠指定如何去影響這些事件的
經過app:layout_scrollFlags屬性就能實現
<?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/drawe_layout" 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/toolbar" android:layout_width="match_parent" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:layout_height="?attr/actionBarSize" app:popupTheme="@style/Theme.AppCompat.Light" app:layout_scrollFlags="scroll|enterAlways|snap" /> </android.support.design.widget.AppBarLayout> //中間的空白頁面 <android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/recycler_view" app:layout_behavior="@string/appbar_scrolling_view_behavior" > </android.support.v7.widget.RecyclerView> <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:src="@mipmap/ic_launcher" android:id="@+id/fab" /> </android.support.design.widget.CoordinatorLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="start"> <android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_width="match_parent" android:layout_height="match_parent" app:menu="@menu/nav_menu" app:headerLayout="@layout/nav_header" > </android.support.design.widget.NavigationView> </LinearLayout> </android.support.v4.widget.DrawerLayout>
這裏爲Toolbbar添加一個app:layout_scrollFlags屬性
而且指定了三個屬性值
scroll:表示當RecylerView向上滾動的時候,Toolbar會跟着一塊兒向上滾動實現隱藏
enterAlways:表示當RecylerView向下滾動的時候,Toolbar會跟着一塊兒向下滾動的時候重現顯示
snap:表示噹噹Toolbar尚未徹底隱藏的時候或者還顯示的時候,會根據當前滾動的距離,自動選擇隱藏仍是顯示
隨着RecylerView向上滾動,Toolbar會隨着其一塊兒滾動消失
隨着RecyleView向下滾動,Toolbar又會從新出現
這事Material Design中的一個重要的設計思想
由於用戶向上滾動的時候,其注意力確定再RecyleView的內容上
這個時候若是Toolbar還佔據着屏幕控件,就會在必定程度上影響用戶的體驗
將Toolbar隱藏可讓閱讀體現出現
下來刷新已是一種常見的使用方式了
好比淘寶、快手等軟件均可以實現下來進行刷新
谷歌爲了讓Android的下拉設計風範有一個統一的標準
因而再Material Design中規定了一個官方的設計規範
此時是拿來即用。
SwipeRefreshLayout就是實現用於下拉刷新的核心類
由support-v4提供的
將實現下來刷新的功能控件放置再SwipeRefershLayout中
就能夠迅速讓這個控件支持下來刷新
再xml文件中引入:
//下拉刷新 <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipe_layout" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" > //中間的空白頁面 <android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/recycler_view" app:layout_behavior="@string/appbar_scrolling_view_behavior" > </android.support.v7.widget.RecyclerView> </android.support.v4.widget.SwipeRefreshLayout>
再RecylerView的外面嵌套了一層SwipeRefreshLayout
此時的Recyleriew
就擁有了下拉自動刷新的功能
因爲RecylerView已經變成了SwipeRefreshLayout的子控件
所以可使用app:layout_behavior聲明佈局行爲如今也要移到SwipeRefreshLayout中
MainActivity
public class MainActivity extends AppCompatActivity { private DrawerLayout mdrawerLayout; private List<Images> imagesList = new ArrayList<>(); private ImagesAdapter imagesAdapter; //下來刷新 private SwipeRefreshLayout swipeRefreshLayout; private void init(){ for (int i=0;i<=10;i++){ Images images = new Images(); images.setName("圖片" + i); images.setImageId(R.drawable.image); imagesList.add(images); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.action_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar ); mdrawerLayout = (DrawerLayout) findViewById(R.id.drawe_layout); ActionBar actionBar = getSupportActionBar(); if (actionBar != null){ actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setHomeAsUpIndicator(R.mipmap.ic_launcher); } NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); navigationView.setCheckedItem(R.id.nav_call); navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { mdrawerLayout.closeDrawers(); return true; } }); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //Toast.makeText(MainActivity.this,"fab",Toast.LENGTH_LONG).show(); mdrawerLayout.openDrawer(GravityCompat.START); Snackbar.make(v,"Data delete ",Snackbar.LENGTH_SHORT) .setAction("Undo", new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this,"數據恢復",Toast.LENGTH_LONG).show(); } }).show(); } }); //卡片佈局 init(); RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); GridLayoutManager layoutManager = new GridLayoutManager(this,2); recyclerView.setLayoutManager(layoutManager); imagesAdapter = new ImagesAdapter(imagesList); recyclerView.setAdapter(imagesAdapter); //下拉刷新 swipeRefreshLayout= (SwipeRefreshLayout) findViewById(R.id.swipe_layout); swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary); swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { refreshImages(); } }); } private void refreshImages(){ new Thread(new Runnable() { @Override public void run() { try{ Thread.sleep(1000); }catch (Exception e){ e.printStackTrace(); } runOnUiThread(new Runnable() { @Override public void run() { for (int i=11;i<=25;i++){ Images images = new Images(); images.setName("圖片" + i); images.setImageId(R.drawable.image); imagesList.add(images); } imagesAdapter.notifyDataSetChanged();; swipeRefreshLayout.setRefreshing(false); } }); } }).start(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.toolbar,menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()){ case android.R.id.home: Toast.makeText(this,"home",Toast.LENGTH_LONG).show(); mdrawerLayout.openDrawer(GravityCompat.START); break; case R.id.Back: Toast.makeText(this,"Back",Toast.LENGTH_LONG).show(); break; case R.id.delete: Toast.makeText(this,"delete",Toast.LENGTH_LONG).show(); break; case R.id.setting: Toast.makeText(this,"setting",Toast.LENGTH_LONG).show(); break; default: break; } return true; } }
首先經過findViewById()方法拿到SwipeRefreshLayout的實例
調用setColorSchemeResources()方法來設置下拉進度條的顏色,這裏使用主題中的colorPrimary做爲進度條的顏色
在調用setOnRefreshListener()方法設置一個下來刷新器
當觸發下拉操做就會回調這個監聽器的onRefresh()方法,在這裏處理具體的邏輯
一般狀況下onRefresh()方法中應該是去網絡上請求最新的數據
而後將這些數據展現出來
此時使用refreshImages()方法進行添加新的數據進行顯示
首先開啓開啓一個線程,讓線程沉睡兩秒鐘
由於刷新操做的速度很是快
沉睡以後
使用runOnUiThread()方法將線程切換到主線程
從而看不到刷新的過程
而後再產生的新的數據
接着調用ImagesAdapter方法的notifyDataSetChanged()方法通知數據發生了變化
最後調用SwipeRefreshLayout的setRefreshing()方法傳入false,表示刷新事件結束,而且隱藏進度條
標題欄是使用Toolbar來編寫的
看上去和傳統的ActionBar其實沒什麼區別
只不過能夠響應RecycleView的滾動事件進行隱藏和顯示
而Material Design中並無限定標題欄必須是什麼樣子的
事實上,能夠根據本身的喜愛隨意定製標題欄的樣式
須要藉助CollapsingToolbarLayout這個工具
CollapsingToolbarLayout是一個做用於Toolbar基礎之上的佈局
由Design Support庫提供的
CollaspingToolbarLayout可讓Toolbar的效果變得更加豐富
不只僅展現一個標題欄,而是可以實現很是華麗的效果
不過CollaspingLayout是不能獨立存在的
他在設計的時候就被限定只能做爲AppBatLayout的直接子佈局來使用
而AppBarLayout又必須是CorrdinatorLayout的子佈局
.................................