Material Design实战之卡片式布局

一.MaterialCardView

1.基本介绍

MaterialCardView是用于实现卡片式布局效果的重要控件,它也是一个FrameLayout,只是额外提供了圆角和阴影等效果,看上去会有立体的感觉。我们在其布局中放什么,那么这个东西就会在一张卡片中了。

2.Glide库

一般里面会放图片控件,所以这里要学习一下GlideGlide是一个超级强大的开源图片加载库,它不仅可以用于加载本地图片,还可以加载网络图片,GIF图片甚至是本地视频。最重要的是,Glide用法非常简单,只需要几行代码就能轻松实现复杂的图片加载功能。

在使用之前,需要引入依赖
implementation 'com.github.bumptech.glide:glide:4.9.0'
具体使用示例
Glide.with(context).load(imageId).into(ImageView);

二.RecyclerView的创建

1.在MainActivity的布局文件中添加RecyclerView

2.创建一个实体类:Fruit

public class Fruit {
    String name;
    int imageId;

    public Fruit(String name, int imageId) {
        this.name = name;
        this.imageId = imageId;
    }
}

3.创建item布局

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_margin="5dp"
    app:cardCornerRadius="4dp">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <ImageView
            android:id="@+id/fruitImage"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:scaleType="centerCrop"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/fruitName"
            android:layout_gravity="center_horizontal"
            android:layout_margin="5dp"
            android:textSize="16sp"/>
    </LinearLayout>
</com.google.android.material.card.MaterialCardView>

4.创建适配器

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.MyViewHolder> {
    List<Fruit> fruits = new ArrayList<>();
    Context context;
    FruitAdapter(Context context){
        this.context = context;
        for (int i = 0; i < 30; i++) {
            fruits.add(new Fruit("香蕉",R.mipmap.banana));
        }
    }
    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,parent,false);
        MyViewHolder holder = new MyViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        holder.textView.setText(fruits.get(position).name);
        Glide.with(context).load(fruits.get(position).imageId).into(holder.fruitImage);
    }

    @Override
    public int getItemCount() {
        return fruits.size();
    }
    class MyViewHolder extends RecyclerView.ViewHolder {
        ImageView fruitImage;
        TextView textView;
        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            fruitImage = itemView.findViewById(R.id.fruitImage);
            textView = itemView.findViewById(R.id.fruitName);
        }
    }
}

5.修改MainActivity中的代码

RecyclerView.LayoutManager layoutManager = new GridLayoutManager(this,2);
RecyclerView recyclerView = findViewById(R.id.mRecyclerView);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(new FruitAdapter(this));

使用效果
Material Design实战之卡片式布局

三.AppBarLayout

1.简介

在上面的例子中,为了不让RecyclerViewToolbar给挡住,我们可以把Toolbar嵌套在AppBarLayout里面。它实际上是一个垂直方向的LinearLayout,在内部做了很多滚动事件的封装,并应用了一些Material Design的设计理念。

2.使用

①将Toolbar嵌套到AppBarLayout
②给RecyclerView指定一个布局行为,即@string/appbar_scrolling_view_behavior
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >
        <androidx.appcompat.widget.Toolbar
            android:id="@+id/mToolBar"
            android:layout_width="match_parent"
            android:layout_height="?actionBarSize"
            android:background="#f2652260"
            android:elevation="4dp"
            app:title="我是主标题"
            app:subtitle="我是副标题"
            app:logo="@mipmap/ic_delete"
            app:layout_scrollFlags="scroll|enterAlways|snap"
            app:navigationIcon="@mipmap/ic_delete"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/toolbarMenuStyle">
        </androidx.appcompat.widget.Toolbar>
    </com.google.android.material.appbar.AppBarLayout>
    
        <androidx.recyclerview.widget.RecyclerView
             android:id="@+id/mRecyclerView"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             app:layout_behavior="@string/appbar_scrolling_view_behavior"/
  
</androidx.drawerlayout.widget.DrawerLayout>

3.更好的应用

Material Design实战之卡片式布局
我们在Toolbar中添加了app:layout_scrollFlags属性,scroll表示当RecyclerView向上滚动的时候,Toolbar会跟着一起向上滚动并实现隐藏。enterAlways表示当RecyclerView向下滚动的时候,Toolbar会跟着一起向下滚动并重新显示。snap表示当Toolbar还没有完全隐藏或显示的时候,会根据当前滚动的距离,自动选择是隐藏还是显示
效果
Material Design实战之卡片式布局

四.SwipeRefreshLayout

SwipeRefreshLayout就是下拉刷新,直接用就可以

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
    android:id="@+id/mRefresh"
    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/mRecyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

注意:由于RecyclerView现在变成了SwipeRefreshLayout的子控件,因此之前使用 app:layout_behavior声明的布局行为现在也要移到SwipeRefreshLayout中才行。

2.处理刷新逻辑

SwipeRefreshLayout swipeRefreshLayout = findViewById(R.id.mRefresh);
swipeRefreshLayout.setColorSchemeColors(R.color.black);
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
    @Override
    public void onRefresh() {
        new Thread(){
            @Override
            public void run() {
                super.run();
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.run();
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this, "运行到主线程了", Toast.LENGTH_SHORT).show();
                SwipeRefreshLayout swipeRefreshLayout1 = findViewById(R.id.mRefresh);
                swipeRefreshLayout1.setRefreshing(false);
            }
        });
    }
});

setColorSchemeColorss 是设置下拉进度条的颜色。setOnRefreshListener是设置下拉的监听器

在刷新事件开始时,我们先开启新线程,睡2s,然后调用runOnUiThread切换回主线程,然后调用SwipeRefreshLayoutsetRefreshing方法,传入false表示刷新事件结束,并且隐藏进度条
使用效果
Material Design实战之卡片式布局

ok,卡片式布局到这里就完成了

上一篇:最全的集合笔记(干货)


下一篇:【算法面试宝典】无重复字符的最长子串