九、Android---UI---Material Design

 

9.一、什麼是Material Design

由谷歌的設計師基於傳統優秀設計原則,結合豐富的創意和科學技術所發明的一套全新的界面設計語言java

包含了視覺、運行、互動等效果android

 

Material Design的出現使得Android首次再UI方面全面超越了IOS網絡

此時就能解決不一樣操做系統之間的統一界面app

 

谷歌從5.0系統開始就將全部內置應用都使用Material Design風格來設計ide

 

主要是面向UI設計人員並非開發者。工具

 

9.二、Toolbar

以前的標題欄佈局

把系統的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;
    }

效果:

 

9.三、滑動菜單

是MaterialDesign中常見效果之一

9.3.一、DraweLayout

 

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

 

9.3.二、NavigationView

 

首先:

控件由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()方法將滑動菜單關閉

 

 

9.四、懸浮按鈕和可交互提示

 

9.4.一、FloatingActionButton

是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);
            }
        });

 

 和普通按鈕的使用方法一致

 

 9.4.二、Snackbar

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顯示出來

 

 

 9.4.三、CoordinatorLayout

是一個增強版的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>

 

 

9.五、卡片式佈局

此時的效果已經 比以前的實現更有顯著的效果

此時頁面上還有一塊空白區域

一般用來防止應用的主題內容

可使用一些圖片來填充這部分區域

 

9.5.一、CradView

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遮擋住了

 

9.5.二、AppBarLayout

上述的測試中能夠發現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隱藏可讓閱讀體現出現

 

9.五、下拉刷新

下來刷新已是一種常見的使用方式了

好比淘寶、快手等軟件均可以實現下來進行刷新

 谷歌爲了讓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,表示刷新事件結束,而且隱藏進度條

 

 

9.七、可摺疊式標題欄

標題欄是使用Toolbar來編寫的

看上去和傳統的ActionBar其實沒什麼區別

只不過能夠響應RecycleView的滾動事件進行隱藏和顯示

 

而Material Design中並無限定標題欄必須是什麼樣子的

事實上,能夠根據本身的喜愛隨意定製標題欄的樣式

須要藉助CollapsingToolbarLayout這個工具

 

9.7.一、CoolapsingToolbarLayout

CollapsingToolbarLayout是一個做用於Toolbar基礎之上的佈局

由Design Support庫提供的

CollaspingToolbarLayout可讓Toolbar的效果變得更加豐富

不只僅展現一個標題欄,而是可以實現很是華麗的效果

 

不過CollaspingLayout是不能獨立存在的

他在設計的時候就被限定只能做爲AppBatLayout的直接子佈局來使用

而AppBarLayout又必須是CorrdinatorLayout的子佈局

 

 

.................................

相關文章
相關標籤/搜索