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、展示

在这里插入图片描述

发布了180 篇原创文章 · 获赞 16 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41205771/article/details/104422651