Material Design學習(四)——下拉刷新、可摺疊標題欄、融合狀態欄

繼續使用上篇文章的項目,拷貝一份並改名爲day21_SwipeRefresh

一、下拉刷新

SwipeRefresh 是用於刷新功能的核心類,將想要實現刷新功能的控件放置到SwipeRefreshLayout中即可

比如我們要刷新RecycleclerView

        <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        	android:id="@+id/swipe_refresh"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recycler_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
        </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

需要注意,因爲RecyclerView現在是SwipeRefresh的子控件,所以app:layout_behavior也要移到SwipeRefreshLayout
差點忘了添加依賴:

implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'   // 下拉刷新

接着修改主活動,添加刷新邏輯:

    private SwipeRefreshLayout swipeRefreshLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
......

        swipeRefreshLayout = findViewById(R.id.swipe_refresh);
        swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary);
        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                refreshFruits();
            }
        });
    }
    
    private void refreshFruits() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try{
                    Thread.sleep(2000);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        initFruits();
                        adapter.notifyDataSetChanged();
                        swipeRefreshLayout.setRefreshing(false);
                    }
                });
            }
        }).start();
    }

setColorSchemeResources() 設置進度條顏色
setOnRefreshListener()設置下拉刷新監聽器,回調onRefresh()
serRefreshing(false)表示刷新事件結束,並隱藏刷新進度條

運行:
在這裏插入圖片描述

二、可摺疊標題欄

Toolbar和傳統標題欄看起來沒啥兩樣,不過可以響應RecyclerView的滾動事件進行隱藏和顯示。爲了實現一個可摺疊的標題欄,需要藉助CollapsingToolBarLayout

CollapsingToolBarLayout

這個佈局作用於Toolbar,可以讓其效果更豐富,但它被限定只能作爲AppBarLayout子佈局使用,而AppBarLayout又必須是CoordinatorLayout的子佈局。

新建一個額外的FruitActivity來展示水果詳情頁面,其對應佈局:

a. 佈局

activity_fruit.xml的三層套路:

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:id="@+id/appBar">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/collapsing_toolbar"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">
            
        </com.google.android.material.appbar.CollapsingToolbarLayout>

    </com.google.android.material.appbar.AppBarLayout>

app:contentScrim:用於指定CollapsingToolbarLayout在趨於摺疊狀態及摺疊狀態之後的背景色
app:layout_scrollFlags:之前給ToolBar指定的,現在移到外面:

  • scroll表示CollapsingToolbarLayout會隨着水果詳情的滾動一起滾動
  • exitUntilCollapsed表示當CollapsingToolbarLayout隨着滾動完成或摺疊之後就保留在界面上,不再移除屏幕

繼續在CollapsingToolbarLayout中定義標題欄的具體內容:

 <ImageView
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:id="@+id/fruit_image_view"
     android:scaleType="centerCrop"
     app:layout_collapseMode="parallax"/>
 <androidx.appcompat.widget.Toolbar
     android:layout_width="match_parent"
     android:layout_height="?attr/actionBarSize"
     android:id="@+id/toolbar"
     app:layout_collapseMode="pin"/>

app:collapseMode用於指定當前控件在CollapsingToolbarLayout摺疊過程中的摺疊方式:

  • pin :位置不變
  • parallax:摺疊會產生一定的錯位偏移

接着在和<AppBarLayout>平級的下面編寫內容部分:

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

NestedScrollView允許用滾動的方式查看屏幕之外的數據,還增加了嵌套響應事件的功能
接着在NestedScrollView內添加布局:

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
            <androidx.cardview.widget.CardView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="15dp"
                android:layout_marginLeft="15dp"
                android:layout_marginRight="15dp"
                android:layout_marginTop="35dp"
                app:cardCornerRadius="4dp">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_margin="10dp"
                    android:id="@+id/fruit_content"/>
            </androidx.cardview.widget.CardView>
        </LinearLayout>

最後給NestedScrollView同級之下添加懸浮按鈕:

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:src="@drawable/like"
        app:layout_anchor="@id/appBar"
        app:layout_anchorGravity="bottom|end"/>

app:layout_anchor指定錨點,將錨點設置爲AppBarLayout,這樣懸浮按鈕就會出現在水果標題欄的區域內
app:layout_anchorGravity:出現在標題欄的右下角

b. 活動

FruitActivity

public class FruitActivity extends AppCompatActivity {
    public static final String FRUIT_NAME = "fruit_name";
    public static final String FRUIT_IMAGE_ID = "fruit_image_id";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fruit);

        Intent intent = getIntent();
        String fruitName = intent.getStringExtra(FRUIT_NAME);
        int fruitImageId = intent.getIntExtra(FRUIT_IMAGE_ID, 0);
        Toolbar toolbar = findViewById(R.id.toolbar);
        CollapsingToolbarLayout collapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
        ImageView fruitImageView = findViewById(R.id.fruit_image_view);
        TextView fruitContentText = findViewById(R.id.fruit_content);
        setSupportActionBar(toolbar);
        ActionBar actionBar =getSupportActionBar();
        if (actionBar != null){
            actionBar.setDisplayHomeAsUpEnabled(true);
        }
        collapsingToolbarLayout.setTitle(fruitName);
        Glide.with(this).load(fruitImageId).into(fruitImageView);
        String fruitContent = generateFtuitContent(fruitName);
        fruitContentText.setText(fruitContent);
    }

    private String generateFtuitContent(String fruitName) {
        StringBuilder fruitContent = new StringBuilder();
        for (int i = 0; i<500; i++){
            fruitContent.append(fruitName);
        }
        return fruitContent.toString();
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()){
            case android.R.id.home:
                finish();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

actionBar.setDisplayHomeAsUpEnabled(true);顯示標題欄的按鈕【默認是返回按鈕】
CollapsingToolbarLayout.setTitle()設置標題
onOptionsItemSelected()設置了返回按鈕的點擊事件

c. 適配器

FruitAdapter

    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if (mContext == null){
            mContext = parent.getContext();
        }
        View view = LayoutInflater.from(mContext).inflate(R.layout.fruit_item, parent, false);
        final ViewHolder holder = new ViewHolder(view);
        holder.cardView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = holder.getAdapterPosition();
                Fruit fruit = mFruitList.get(position);
                Intent intent = new Intent(mContext, FruitActivity.class);
                intent.putExtra(FruitActivity.FRUIT_NAME, fruit.getName());
                intent.putExtra(FruitActivity.FRUIT_IMAGE_ID, fruit.getImageId());
                mContext.startActivity(intent);
            }
        });
        return holder;
    }

也就是給CardView註冊了一個監聽器~

4. 展示

在這裏插入圖片描述

三、融合狀態欄

狀態欄融合是Android5.0以後才支持的的樣式

1、一個屬性

要想使背景圖和系統狀態欄融合,需藉助android:fitsSystemWindows這個屬性來實現,將本例中的ImageView及其所有父佈局全部設置這個屬性:

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:id="@+id/appBar"
        android:fitsSystemWindows="true">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/collapsing_toolbar"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            android:fitsSystemWindows="true">
            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:id="@+id/fruit_image_view"
                android:scaleType="centerCrop"
                app:layout_collapseMode="parallax"
                android:fitsSystemWindows="true"/>
            <androidx.appcompat.widget.Toolbar
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:id="@+id/toolbar"
                app:layout_collapseMode="pin"/>

        </com.google.android.material.appbar.CollapsingToolbarLayout>

    </com.google.android.material.appbar.AppBarLayout>
    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
            <androidx.cardview.widget.CardView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="15dp"
                android:layout_marginLeft="15dp"
                android:layout_marginRight="15dp"
                android:layout_marginTop="35dp"
                app:cardCornerRadius="4dp">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_margin="10dp"
                    android:id="@+id/fruit_content"/>
            </androidx.cardview.widget.CardView>
        </LinearLayout>

    </androidx.core.widget.NestedScrollView>
    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:src="@drawable/like"
        app:layout_anchor="@id/appBar"
        app:layout_anchorGravity="bottom|end"/>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

2、設置透明

在主題中,將android:statusBarColor指定成@android:color/transparent,但只有Android5.0 之後纔可以這麼設置,所以這裏就要實現系統差異處理了。

res下新建一個values-v21目錄,在裏面建一個values_resource文件styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="FruitActivityTheme" parent="AppTheme">
        <item name="android:statusBarColor">@android:color/transparent</item>
    </style>
</resources>

這裏定義了一個FruitActivityTheme主題,它是專門給FruitActivity使用的,其parent主題是Apptheme,就是說他繼承了AppTheme的所有特性,然後將其狀態欄的顏色指定爲透明色,而values-v21是隻有Android5.0以上的系統纔會讀取,因此這麼聲明沒問題

接着爲5.0之前的系統單獨單的設置values/style.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="FruitActivityTheme" parent="AppTheme" />
</resources>

這裏也定義了一個FruitActivityTheme主題,並且parent主題也是AppTheme,但內部是空的,因爲5.0之前無法指定狀態欄顏色,所以這裏啥都不用做

接着在AndroidManifest.xml中讓FruitActivity使用這個主題:

        <activity android:name=".FruitActivity"
            android:theme="@style/FruitActivityTheme">
        </activity>

3、展示

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章