Android Material Design
- 今天就来谈谈 android 给我们提供的 Material 库的好用又好看的组件
 
ToolBar
-  
ToolBar这个是来替代ActionBar的
具体的做法很简单:
-  
将主题的ActionBar设置为没有
 -  
然后在需要ToolBar的地方 放在他的布局文件里 在他的创建视图的时候 调用 **setSupportActionBar(binding.toolbar) **这个方法就可以了
传入的就是在布局文件里定义的ToolBar
 
看代码
 -  
 

- 圈出来的地方就是要改变的地方
 
然后在代码中设置
setSupportActionBar(binding.toolbar) // 将ToolBar 用作 ActionBar
 
- 由于ActionBar只有Activity才有 所以这个方法也只有Activity才有=
 
<androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="@color/design_default_color_primary"
                android:theme="@style/Theme.AppCompat.DayNight.DarkActionBar" //指定顶部栏是暗色主题
                app:popupTheme="@style/Theme.AppCompat.Light"/> //指定弹出来的菜单是浅色主题
 
- 既然ActionBar有Action按键 那么ToolBar在Activity中也有 调用的方法还是一样的
 
//这个方法是将菜单布局加载到ToolBar上
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.toobal,menu)
        return true //返回TRUE表示加载完成
    }
//在Activity中重写这个方法,就可以实现ToolBar上有action按键的点击事件了
override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when(item.itemId){
            R.id.backup -> Toast.makeText(this,"backup",Toast.LENGTH_SHORT).show()
            R.id.delete -> Toast.makeText(this,"delete",Toast.LENGTH_SHORT).show()
            R.id.setting -> Toast.makeText(this,"setting",Toast.LENGTH_SHORT).show()
        }
        return true//表示事件点击处理了
    }
 
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/backup"//这里
        android:icon="@drawable/ic_backup"
        android:title="BackUp"
        app:showAsAction="always"/> <!--表示永远显示到ToolBar上 但是空间不够就不显示-->
    <item
        android:id="@+id/delete"///这里
        android:icon="@drawable/ic_delete"
        android:title="Delete"
        app:showAsAction="ifRoom"/> <!--表示 如果空间足够才显示,空间不够就不显示-->
    <item
        android:id="@+id/setting"//这里
        android:icon="@drawable/ic_settings"
        android:title="Delete"
        app:showAsAction="never"/> <!--不在ToolBar上显示-->
</menu>
 
- ToolBar设置一个homeAction按键 默认的图标是一个返回键
 - 但是我们可以自定义修改
 
supportActionBar?.let{
            it.setDisplayHomeAsUpEnabled(true) //这个表示显示Home Action按键
            it.setHomeAsUpIndicator(R.drawable.align) //这个重新设置Home Action的图标
        }
 
- 然后就是设置这个按键的点击事件了
 
override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when(item.itemId){
            android.R.id.home -> binding.drawerLayout.openDrawer(GravityCompat.START) //看这里
            R.id.backup -> Toast.makeText(this,"backup",Toast.LENGTH_SHORT).show()
            R.id.delete -> Toast.makeText(this,"delete",Toast.LENGTH_SHORT).show()
            R.id.setting -> Toast.makeText(this,"setting",Toast.LENGTH_SHORT).show()
        }
        return true
    }
 
- 只要他还是个ToolBar 那么他的点击事件的响应就要在 onOptionsItemSelected 这个方法进行处理
 - 注意 : home的id 是系统指定的 : android.R.id.home
 
滑动菜单 — DrawerLayout
-  
就是将菜单选项隐藏起来,不放置在主屏幕上,通过滑动的方式来显示
 -  
DrawerLayout 只允许有两个直接子控件 第一个控件 : 在主屏幕中显示内容,第二个子控件显示滑动菜单中的内容
 -  
唯一值得注意的是 必须指定 第二个控件的layout_gravity 并且只能是一个方向
 
NavigationView
- 这里先说明一些 无关的东西
 - NavigationView 是 Material库中的所以的添加依赖
 
dependencies {
    implementation 'com.google.android.material:material:1.5.0'
}
 
- 因为使用了NavigationView 使用到了Material库中的东西 就得将应用的主题换成 Material的
 - 具体就是
 

- 这个就是整个应用的主体
 

-  
改成 Theme.MaterialComponents.DayNight.DarkActionBar
 -  
现在继续来介绍 NavigationView
他主要分为两个部分 一个 headerlayout 一个是 menu
通过名字可以发现 : headerlayout 是一个布局 menu是一个菜单
看代码
<com.google.android.material.navigation.NavigationView android:id="@+id/navView" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="start" <!--注意是app的命名空间--> app:menu="@menu/nav_menu" //引用了一个menu app:headerLayout="@layout/nav_header"/> <!-- 引用了一个布局-->//nav_menu <menu xmlns:android="http://schemas.android.com/apk/res/android"> <group android:checkableBehavior="single"> //这里的single的意思是里面的选项只能单选 <item android:id="@+id/navCall" android:icon="@drawable/nav_call" android:title="Call"/> <item android:id="@+id/navFriends" android:icon="@drawable/nav_friends" android:title="Friends"/> <item android:id="@+id/navLocation" android:icon="@drawable/nav_location" android:title="Location"/> <item android:id="@+id/navMail" android:icon="@drawable/nav_mail" android:title="Mail"/> <item android:id="@+id/navTask" android:icon="@drawable/nav_task" android:title="Task"/> </group> </menu> //nav_header <?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:background="@color/design_default_color_primary"> <de.hdodenhof.circleimageview.CircleImageView android:id="@+id/iconImage" android:layout_width="70dp" android:layout_height="70dp" android:src="@drawable/nav_icon" android:layout_centerInParent="true"/> <TextView android:id="@+id/mailText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:text="tonygreendev@gmail.com" android:textColor="#FFF" android:textSize="14sp"/> <TextView android:id="@+id/userText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@id/mailText" android:text="Tony Green" android:textColor="#FFF" android:textSize="14sp"/> </RelativeLayout>- 然后为菜单选项键设置监听事件
 
binding.navView.setCheckedItem(R.id.navCall) //这个来设置默认的选择 binding.navView.setNavigationItemSelectedListener { //设置监听事件的 when(it.itemId){ R.id.navCall -> Toast.makeText(this,"电话",Toast.LENGTH_SHORT).show() R.id.navFriends -> Toast.makeText(this,"朋友",Toast.LENGTH_SHORT).show() R.id.navLocation -> Toast.makeText(this,"地址",Toast.LENGTH_SHORT).show() R.id.navMail -> Toast.makeText(this,"邮箱",Toast.LENGTH_SHORT).show() } binding.drawerLayout.closeDrawers()//关闭滑动菜单 true//表示事件已经处理 } 
悬浮式按键 — FloatingActionButton
-  
这个可以做一种悬浮的效果 而且还有阴影
 -  
这个按键没有什么特别的 还是一个按键 有这样几个属性值得关注
 -  
layout_gravity : 可以指定这个按键位于他父控件的那个位置 前提是他的父容器支持
 
<com.google.android.material.floatingactionbutton.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:src="@drawable/ic_comment"//指定按键的图标
        app:layout_anchor="@id/appBar" //指定锚点
        app:layout_anchorGravity="bottom|end"/>//位于锚点的位置
 
他的点击事件的监听很简单和按键基本没啥区别
binding.fab.setOnClickListener { view ->
           /*这个等下介绍*/ Snackbar.make(view,"Data Deleted",Snackbar.LENGTH_SHORT).setAction("Undo"){
                Toast.makeText(this,"Data restored",Toast.LENGTH_SHORT).show()
            }.show()
        }
 
Snackbar — 可以交互的Toast
- 众所周知Toast只能显示通知不能和用户交互 而SnackBar就是既可以和用户交互又可以显示同时显示通知
 
Snackbar.make(view,"Data Deleted",Snackbar.LENGTH_SHORT)/*这一部分就是和Toast很类似 Data Deleted 是显示的内容 Snackbar.LENGTH_SHORT显示的时长view: 这个注意一下*/.setAction("Undo"){
    //这一部分就是设置的一个按键 (Undo是名字)
    //lambda是点击的响应逻辑
    Toast.makeText(this,"Data restored",Toast.LENGTH_SHORT).show()
            }.show()
 
- view : 是将一个视图传给他 他会自动去找根视图的,来展示信息 这个view是用来指定 Snackbar是基于谁触发的
 
CoordinatorLayout
- 这个就是一个加强版的FrameLayout 他可以监听子控件的各种事件并将我们作出合理的响应
 
<androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
		<!--这个布局的作用是 悬浮按键-->
        <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|end"
            android:layout_margin="16dp"
            android:src="@drawable/ic_done"
            android:elevation="8dp"/>
    </androidx.coordinatorlayout.widget.CoordinatorLayout>
 
-  
这样就可以监听了悬浮按键的点击事件
在上面的代码中我们点击按键会弹出一个通知 那么这个时候就会自动然悬浮按键上移 流出一个通知的位置
 
卡片式布局 — MaterialCardView
- 这个布局的实质也还是FrameLayout 只是提供了阴影和圆角的效果
 
<androidx.cardview.widget.CardView 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:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <ImageView
            android:id="@+id/fruitImage"
            android:layout_width="wrap_content"
            android:layout_height="100dp"
            android:scaleType="centerCrop"/>
        <TextView
            android:id="@+id/fruitName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_margin="5dp"
            android:textSize="16sp"/>
    </LinearLayout>
</androidx.cardview.widget.CardView>
 
AppBarLayout
- 实际上是一个垂直方向上的LinearLayout 内部做了很多滚动事件的封装
 - 滚动事件的处理要用到两个布局
 
<com.google.android.material.appbar.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="@color/design_default_color_primary"
                android:theme="@style/Theme.AppCompat.DayNight.DarkActionBar"
                app:popupTheme="@style/Theme.AppCompat.Light"
                app:layout_scrollFlags="scroll|enterAlways|snap" //这个就是用来指定滚动时ToolBar的显示 />
 </com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
 android:id="@+id/recyclerView"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
 
- 在要监听的滚动事件的组件上加上 app:layout_behavior="@string/appbar_scrolling_view_behavior" 就可以了 那么当RecyclerView 滚动的时候 APPBar会作出相应的响应
 - scroll — 滚动是消失
 - enterAlways — 向上移动时显示
 - snap — 隐藏或显示一部分时 自动判断是显示还是隐藏
 
SwipeRefershLayout —下拉刷新的布局
-  
想要实现下拉刷新的效果只需要在需要的布局外套一个 SwipeRefershLayout 这个布局就可以
 -  
注意 : 必须添加依赖 :
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' -  
具体的刷新逻辑得靠我们自己来实现
 
private fun refreshFruits(adapter:FruitAdapter){
        thread{
            Thread.sleep(2000)
            runOnUiThread {
                initFruit()
                adapter.notifyDataSetChanged() //这个就是让列表项全部刷新
                binding.swipeRefresh.isRefreshing = false //这个的意思是刷新完成后 隐藏刷新的那个图标
            }
        }
    }
//设置刷新的处理时间
binding.swipeRefresh.setOnRefreshListener {
            refreshFruits(binding.recyclerView.adapter as FruitAdapter)
        }
 
可折叠的标题栏 — CollapsingToolbarLayout
- 是一个作用域Toolbar基础之上的布局 它不仅仅是展示一个标题了还可以有很多的效果
 - 但是 : 他不能单独存在 他只能是AppbarLayout的直接子布局 而 APPBarLayout又只能是CoordinatorLayout的直接子布局
 
<androidx.coordinatorlayout.widget.CoordinatorLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".FruitActivity">
    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appBar"
        android:layout_width="match_parent"
        android:layout_height="150dp" // 这个可以随便指定
        android:fitsSystemWindows="true">
        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/collapsingToolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:theme="@style/Theme.AppCompat.DayNight.DarkActionBar"
            app:contentScrim="@color/design_default_color_primary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            android:fitsSystemWindows="true">
        <ImageView
            android:id="@+id/fruitImageView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            app:layout_collapseMode="parallax" //这里
            android:fitsSystemWindows="true"/>
            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"/> //这里
        </com.google.android.material.appbar.CollapsingToolbarLayout>
    </com.google.android.material.appbar.AppBarLayout>
 
- app:layout_collapseMode=“parallax” 这个属性是来指定折叠时的动画效果 parallax 产生一定的错位偏移 pin 就是位置保持不变
 - app:contentScrim="@color/design_default_color_primary" : 用来指定趋于折叠状态时 和 折叠时的状态的背景色
 - app:layout_scrollFlags=“scroll|exitUntilCollapsed” 因为 CollapsingToolbarLayout 是APPBarLayout的子布局 所以他会根据APPBarLayout 监听到滚动事件来对子布局产出一定的响应 exitUntilCollapsed 这个就是折叠完成后就不在移出屏幕
 
NestedScrollView
- 这个视图只是在ScrollView的基础上可以嵌套在一个可以响应滚动事件的的功能
 
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".FruitActivity">
    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appBar"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:fitsSystemWindows="true">
        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/collapsingToolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:theme="@style/Theme.AppCompat.DayNight.DarkActionBar"
            app:contentScrim="@color/design_default_color_primary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            android:fitsSystemWindows="true">
        <ImageView
            android:id="@+id/fruitImageView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            app:layout_collapseMode="parallax"
            android:fitsSystemWindows="true"/>
            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                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:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <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:id="@+id/fruitContentText"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_margin="10dp"/>
            </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/ic_comment"
        app:layout_anchor="@id/appBar"
        app:layout_anchorGravity="bottom|end"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
 
- **app:layout_behavior="@string/appbar_scrolling_view_behavior" ** 这个滚动的事件会被APPBarLayout监听到 然后他的子控件对这个滚动的事件能作出响应
 
- 重复利用状态栏的空间 : 可以设置属性 : android:fitsSystemWindows=“true” 来让控件出现在状态栏中 如果你想让一个控件在状态栏中显示 那么你就得让他的全部父控件都添加这个属性
 










