移动开发笔记(十四)UI Maaterial Design Git时间版本

Material Design是由Google的设计师开发的一套界面设计语言,包含了视觉,运动,互动效果等特性.
1.Toolbar
任何一个新建项目都默认显示ActionBar的,这是根据项目中指定的主题显示,打开AndroidMainfest.xml

 android:theme="@style/AppTheme"

这个AppTheme在res/values/styles.xml文件力定义的

<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>

现在我们准备使用Toolbar代替ActionBar,因此需要指定一个不带ActionBar的主题,
这里有Theme.AppCompat.NoActionBar和Theme.AppCompat.Light.NoActionBar这两个主题可选.
Theme.AppCompat.NoActionBar表示神色主题,Theme.AppCompat.Light.NoActionBar表示浅色主题
在这里插入图片描述
在这里插入图片描述
修改activity_main.xml中的代码,使用Toolbar来代替actionBar

<LinearLayout 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=".MainActivity"
    android:orientation="vertical">
    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/colorPrimary"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light">

    </androidx.appcompat.widget.Toolbar>

接下来修改MainActivity

 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(toolbar)
        }

xmlns:app指定了一个新的命名空间,这是由于许多Material属性是在新系统中新增的,为了兼容老系统,我们就不能使用android:attribute这样的写法,而是应该用app:attribute。
我们使用了android:theme属性,将Toolbar主题指定成了ThemeOverlay.AppCompat.Dark.ActionBa。为了将弹出菜单项也变成神色主题,这里使用了app:popupTheme属性,单独将弹出的菜单指定成深色主题。
1.修改标题栏上的文字内容

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme"
    android:networkSecurityConfig="@xml/network_config"
    >
    <activity android:name=".MainActivity"
        android:label="Fruit"><!--修改这里-->
       
    </activity>
</application>

*2.在Toolbar上添加action按钮
右键res目录->New->Directory,创建一个menu目录
右键menu文件夹->New->Menu resource file,创建一个toolbar.xml文件

<?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/backup"
        android:icon="@drawable/backup"
        android:title="Backup"
        app:showAsAction="always"
        ></item>
    <item
        android:id="@+id/delete"
        android:icon="@drawable/delete"
        android:title="Delete"
        app:showAsAction="ifRoom"
        ></item>
    <item
        android:id="@+id/settings"
        android:icon="@drawable/settings"
        android:title="Settings"
        app:showAsAction="never"
        ></item>
</menu>

showAsAction主要有以下几种值可以选,always表示永远显示在Woolbar中,如果屏幕空间不够则不显示;ifRoom表示屏幕足够的情况下显示在Toolbar,不够的话就显示在菜单当中;never则表示永远显示在菜单当中。
修改MainaActivity中的代码

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(toolbar)
      
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.toolbar,menu)
        return true
    }

    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.settings ->Toast.makeText(this,"Settings",Toast.LENGTH_SHORT).show()
                    }
        return true
    }
   }

在这里插入图片描述

滑动菜单

1.DrawerLayout
修改activity_main.xml

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

  <FrameLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent">
    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/colorPrimary"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light">

    </androidx.appcompat.widget.Toolbar>

  </FrameLayout>
  <TextView
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:layout_gravity="start"
      android:text="This is menu"
      android:background="#fff"
      ></TextView>
</androidx.drawerlayout.widget.DrawerLayout>

DrawerLayout中放置了两个直接子控件:第一个是FrameLayout,用于作为主屏幕中显示的内容,第二个子控件是一个TextView,用于作为滑动菜单中显示的内容。
第二个子控件有一点需要注意,layout_gravity这个属性是必须指定的,我们需要告诉他滑动菜单时在屏幕的左边还是右边。指定left表示菜单在左边,right表示菜单在右边。start表示会根据系统语言进行判断。
在这里插入图片描述
Material Design建议的做法是在Toolbar的最左边加入一个导航按钮
修改MainActivity中的代码

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(toolbar)
        supportActionBar?.let {
            it.setDisplayHomeAsUpEnabled(true)
            it.setHomeAsUpIndicator(R.drawable.menu)
        }
    }
...

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when(item.itemId){
          android.R.id.home -> drawerLayout.openDrawer(GravityCompat.START)
           ...
        }
        return true
    }
}

Home按钮的id永远都是android.R.id.home。然后调用DrawerLayout的openDrawer()方法将滑动菜单展示出来。openDrawer()方法要求传入一个Gravity参数,为了保证这里的行为和XML中定义的一致。我们传入了GravityCompat.START
2.NavigationView
这个控件时Material库中提供的,需要引入开源项目CircleImageView.
打开app/build.gradle文件,在dependencies闭包中添加如下内容

dependencies {
...
    implementation 'com.google.android.material:material:1.0.0'
    implementation 'de.hdodenhof:circleimageview:3.0.1'
    }

右击menu文件夹->New->Menu resource file,创建一个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:id="@+id/navCall"
            android:icon="@drawable/call"
            android:title="Call"></item>
        <item
            android:id="@+id/navFriends"
            android:icon="@drawable/friends"
            android:title="Friends"></item>
        <item
            android:id="@+id/navLocation"
            android:icon="@drawable/location"
            android:title="Location"></item>
        <item
            android:id="@+id/nav_mail"
            android:icon="@drawable/mail"
            android:title="Mail"></item>
        <item
            android:id="@+id/navTask"
            android:icon="@drawable/task"
            android:title="Task"></item>
    </group>
</menu>

< group>表示一个组,checkableBehavior指定为single表示组中所有菜单只能单选
然后右击layout文件夹->New->Layout resource file创建一个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="@color/colorPrimary"
    >
    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/iconImage"
        android:layout_width="70dp"
        android:layout_height="70dp"
        android:src="@drawable/icon"
        android:layout_centerInParent="true"></de.hdodenhof.circleimageview.CircleImageView>
    <TextView
        android:id="@+id/mailText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:text="q327192368@163.com"
        android:textColor="#fff"
        android:textSize="14sp"
        ></TextView>
    <TextView
        android:id="@+id/userText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@id/mailText"
        android:text="Peter Wang"
        android:textColor="#fff"
        android:textSize="14sp"
        ></TextView>
</RelativeLayout>

在RelativeLayout中CircleImageView是一个用于将图片圆形化的控件
修改activity_main.xml中的代码

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/colorPrimary"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light">

        </androidx.appcompat.widget.Toolbar>

    </FrameLayout>
    <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:menu="@menu/nav_menu"
        app:headerLayout="@layout/nav_header"
        ></com.google.android.material.navigation.NavigationView>


</androidx.drawerlayout.widget.DrawerLayout>

通过app:menu和app:headerLayout属性将我们刚才准备好的menu和headerLayout设置进去
最后修改以下MainActivity中的代码

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(toolbar)
        supportActionBar?.let {
            it.setDisplayHomeAsUpEnabled(true)
            it.setHomeAsUpIndicator(R.drawable.menu)
        }
        navView.setCheckedItem(R.id.navCall)
        navView.setNavigationItemSelectedListener {
            drawerLayout.closeDrawers()
            true
        }
    }
    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.toolbar,menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when(item.itemId){
            android.R.id.home -> 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.settings -> Toast.makeText(this,"Settings", Toast.LENGTH_SHORT).show()
        }
        return true
    }
}

这里先调用了NavigationView的setCheckedItem()方法将Call菜单项设置为默认选中。接着调用setNavigationItemSelectedListener()方法来者之一个菜单项选中时间的监听器,这里调用DrawerLayout的closeDrawers()方法,将滑动菜单关闭,并返回true表示此事件已经被处理。
在这里插入图片描述

悬浮按钮和可交互提示

1.FloatingActionButton
修改activity_main.xml文件

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <FrameLayout
        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/done"
        ></com.google.android.material.floatingactionbutton.FloatingActionButton>
    </FrameLayout>
...

</androidx.drawerlayout.widget.DrawerLayout>

layout_gravity属性指定将这个控件放置在屏幕右下角,其中end的工作原理和之前的start是一样的。
elevation悬浮高度,高度值越大投影范围越大,投影效果越淡。
修改MainActivity中的代码,处理点击事件

 fab.setOnClickListener{
            Toast.makeText(this,"你点击了悬浮按钮",Toast.LENGTH_SHORT).show()
        }

在这里插入图片描述
2.Snackbar
Snackbar并不是Toast的替代品,他们有着不同的应用场景
修改MainActivity中的代码

        fab.setOnClickListener{
            Snackbar.make(it,"删除数据!",Snackbar.LENGTH_SHORT).setAction("Undo"){
                Toast.makeText(this,"数据恢复",Toast.LENGTH_SHORT).show()
            }
                .show()
        }

这里调用了Snackbar的make()方法来创建,第一个参数只需传入一个View,Snackbar会使用这个View找到最外层的布局,用于展示信息。setAction()方法来设置一个动作。

3.CoordinatorLayout
CoordinatorLayout是一个加强版的FrameLayout,由AndroidX库提供,它可以监听所有子控件的各种事件,并自动帮我们做出最为合理的响应。
修改activity_main.xml中的代码

<androidx.drawerlayout.widget.DrawerLayout 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:id="@+id/drawerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
      ...  
    </androidx.coordinatorlayout.widget.CoordinatorLayout>
...
</androidx.drawerlayout.widget.DrawerLayout>

在这里插入图片描述

卡片式布局

1.MaterialCardView
MaterialCardView也是一个FrameLayout,只是额外提供了圆角和阴影等效果,看上去有立体效果。
基本用法:

<com.google.android.material.card.MaterialCardView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:cardCornerRadius="4dp"
            android:elevation="5dp">
            <TextView
                android:id="@+id/infoText"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
                
            </TextView>
        </com.google.android.material.card.MaterialCardView>

app:cardCorneRadius属性指定卡片圆角的弧度。
在app/build.gradle文件中声明库的依赖

  implementation 'androidx.recyclerview::recyclerview:1.0.0'
    implementation 'com.github.bumptech.glide:glide:4.9.0'

修改atcivity_main.xml中的代码

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
       ...新增这里,添加recyclerview
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

        </androidx.recyclerview.widget.RecyclerView>
    <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/done"
        ></com.google.android.material.floatingactionbutton.FloatingActionButton>
    </androidx.coordinatorlayout.widget.CoordinatorLayout>
   ...
</androidx.drawerlayout.widget.DrawerLayout>

创建一个Fruit实体类

class Fruit(val name:String,val imageId:Int) {
}

为Recyclerview指定一个自定义布局,在layout目录创建fruit_item.xml

<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:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <ImageView
            android:id="@+id/fruitImage"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:scaleType="centerCrop"></ImageView>
        <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"
            ></TextView>
    </LinearLayout>
</com.google.android.material.card.MaterialCardView>

ImageView中我们使用了scaleType属性,这个属性可以指定图片的缩放模式,centerCrop模式,它可以让图片保持原有比例填充满ImageView,并将超出屏幕的部分裁掉。
为RecyclerView准备一个适配器,新建FruitAdapter类。

class FruitAdapter(val context:Context,val fruitList: List<Fruit>):
    RecyclerView.Adapter<FruitAdapter.ViewHolder>() {
    inner class ViewHolder(view : View) :RecyclerView.ViewHolder(view){
       val fruitImage:ImageView = view.findViewById(R.id.fruitImage) 
        val fruitName : TextView = view.findViewById(R.id.fruitName) 
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view =LayoutInflater.from(context).inflate(R.layout.fruit_item,parent,false)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val fruit =fruitList[position]
        holder.fruitName.text=fruit.name
        Glide.with(context).load(fruit.imageId).into(holder.fruitImage)
    }

    override fun getItemCount()= fruitList.size
    
}

调用Glide.with()方法帮我们压缩图片避免内存溢出。
最后修改MainActivity中的代码

class MainActivity : AppCompatActivity() {
    val fruits = mutableListOf(Fruit("Banana",R.drawable.banana),Fruit("Apple",R.drawable.apple),
        Fruit("Orange",R.drawable.orange),Fruit("cherry",R.drawable.cherry), Fruit
    ("Pear",R.drawable.pear), Fruit("Pineapple",R.drawable.pineapple)
    )
    val fruitList = ArrayList<Fruit>()
    override fun onCreate(savedInstanceState: Bundle?) {
     ...
        initFruits()
        val layoutManager = GridLayoutManager(this,2)
        recyclerView.layoutManager = layoutManager
        val adapter = FruitAdapter(this,fruitList)
        recyclerView.adapter=adapter
    }
    private fun initFruits(){
        fruitList.clear()
        repeat(50){
            val index = (0 until  fruits.size).random()
            fruitList.add(fruits[index])
        }
    }
  ...
}

GridLayoutManger构造函数接收的参数第一个是Context第二个是列数。
在这里插入图片描述

但是我们的Toolbar被RecyclerView挡住了
2.AppBarLayout
AppBarLayout实际上是一个垂直方向的LinearLayout,内部做了很多滚动事件的封装。
修改activity_main.xml中的代码

<androidx.drawerlayout.widget.DrawerLayout 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:id="@+id/drawerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <com.google.android.material.appbar.AppBarLayout  <----在这儿里增加了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/colorPrimary"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light">

        </androidx.appcompat.widget.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">     <------在这里增加了behavior属性

        </androidx.recyclerview.widget.RecyclerView>
  ...
</androidx.drawerlayout.widget.DrawerLayout>

将Toolbar嵌套在AppBarLayout中,第二部给RecyclerView指定一个布局行为
在这里插入图片描述
这样就不遮挡了,但我们还可以继续优化

     <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/colorPrimary"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
            app:layout_scrollFlags="scroll|enterAlways|snap">         <-------增加属性

scroll表示当RecyclerView向上滑动的时候,Toolbar会向上滑动实现隐藏
enterAlways表示当RecyclerView向下滑动的时候,Toolbar会跟着下滑重现显示
snap表示当Toolbar还没有完全显示或隐藏时候,会根据当前滑动的距离自行选择
3.下拉刷新
SwipeRefreshLayout用于实现下拉刷新功能的核心类,将支持下拉刷新功能的组件放置到SwiperRefreshLayout中,就可以让这个控件支持下拉刷新。
修改actvity_main.xml中的代码

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

        </androidx.recyclerview.widget.RecyclerView>
        </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

修改MainActivity中的代码

class MainActivity : AppCompatActivity() {
    val fruits = mutableListOf(Fruit("Banana",R.drawable.banana),Fruit("Apple",R.drawable.apple),
        Fruit("Orange",R.drawable.orange),Fruit("cherry",R.drawable.cherry), Fruit
    ("Pear",R.drawable.pear), Fruit("Pineapple",R.drawable.pineapple)
    )
    val fruitList = ArrayList<Fruit>()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
       ...
        //下拉刷新功能
        swiperRefresh.setColorSchemeResources(R.color.colorPrimary)
        swiperRefresh.setOnRefreshListener {
            refreshFruits(adapter)
        }

    }
    private fun refreshFruits(adapter: FruitAdapter){
        thread {
            Thread.sleep(2000)
            runOnUiThread {
                initFruits()
                adapter.notifyDataSetChanged()
                swiperRefresh.isRefreshing=false
            }
        }
    }
  ...
}

调用SwiperRefreshLayout的setColorSchemeResource()方法来设置下拉刷新进度条的颜色。
接着调用setOnRefreshListener()方法来设置一个下拉刷新的监听器。
最后调用SwipeRefreshLayout的setRefreshing()发布方法并传入false,表示刷新事件结束,并隐藏进度条

可折叠式标题栏

1.CollapsingToolbarLayout
CollapsingToolbarLayout是不能独立存在的,它在设计的时候被限定只能作为AppBarLayout的直接子布局来使用,它被设计限定只能作为AppBarLayout的直接子布局来使用。而AppBarLayout又必须是coordinatorLayout的子布局。
1).首先使用CoordinatorLayout作为最外层布局1

<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=".MainActivity">
</androidx.coordinatorlayout.widget.CoordinatorLayout>

2).在CoordinatorLayout内嵌套AppBarLayout

<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=".MainActivity">
    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appBar"
        android:layout_width="match_parent"
        android:layout_height="250dp">
        
    </com.google.android.material.appbar.AppBarLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

接下来我们在AppBarLayout中在嵌套一个CollapsingToolbarLayout

<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=".MainActivity">
    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appBar"
        android:layout_width="match_parent"
        android:layout_height="250dp">
        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/collapsingToolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:contentScrim="@color/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"></com.google.android.material.appbar.CollapsingToolbarLayout>
    </com.google.android.material.appbar.AppBarLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

app:contentScrim属性用于指定CollapsingToolbarLayout在折叠状态以及折叠后的背景色/
exitUntilCollapsed表示当CollapsingToolbarLayout随着滚动完成折叠之后就保留在界面上,不移出屏幕。
接下来在CollapsingToolbarLayout中定义标题栏的内容。

 <ImageView
                    android:id="@+id/fruitImageView"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:scaleType="centerCrop"
                    app:layout_collapseMode="parallax">

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

                </androidx.appcompat.widget.Toolbar>

app:layout_collapseMode用于指定控件在CollapsingToolbarLayout折叠模式
pin表示在折叠过程中保持不变
parallax表示在折叠过程中会产生一定的错位偏移。
接着在AppBarLayout下面添加NestedScrollView

<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=".MainActivity">
    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appBar"
        android:layout_width="match_parent"
        android:layout_height="250dp">
       ...
    </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">

    </androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

NestedScrollView在ScrollView基础之上还增加了嵌套响应滚动事件的功能。
由于coordinatorLayout本身就可以响应滚动事件,因此我们在它内部就需要使用NestedScrollView或RecyclerView这样的布局。
不管是ScrollView还是NestedScrollView,他们内部只允许存在一个直接子布局,通常会先嵌套一个LinearLayout。
并在LinearLayout中放置具体内容

...
 <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"
            >
            <com.google.android.material.card.MaterialCardView
                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"></TextView>
            </com.google.android.material.card.MaterialCardView>
        </LinearLayout>
    </androidx.core.widget.NestedScrollView>

最后添加在加入表示评论的悬浮按钮

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

FloatingActionButton中使用app:layout_anchor属性指定一个锚点,设置为AppBarLayout,这样悬浮按钮就会出现在水果标题栏的区域内。
修改FruitActivity中的代码

class FruitActivity : AppCompatActivity() {

    companion object{
        const val FRUIT_NAME = "fruit_name"
        const val FRUIT_ID ="fruit_image_id"
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_fruit)
        val fruitName = intent.getStringExtra(FRUIT_NAME) ?:""
        val fruitImageId = intent.getIntExtra(FRUIT_ID,0)
        setSupportActionBar(toolbar)
        supportActionBar?.setDisplayHomeAsUpEnabled(true)
        collapsingToolbar.title = fruitName
        Glide.with(this).load(fruitImageId).into(fruitImageView)
        fruitContentText.text= generateFruitContent(fruitName)
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when(item.itemId){
            android.R.id.home ->{
                finish()
                return true
            }
        }
        return super.onOptionsItemSelected(item)
    }
    private fun generateFruitContent(fruitName : String) =fruitName.repeat(500)
}

最后修改FruitAdapter中的代码

...
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view =LayoutInflater.from(context).inflate(R.layout.fruit_item,parent,false)
        val holder =ViewHolder(view)
        holder.itemView.setOnClickListener {
            val position = holder.adapterPosition
            val fruit =fruitList[position]
            val intent = Intent(context,FruitActivity::class.java).apply {
                putExtra(FruitActivity.FRUIT_NAME,fruit.name)
                putExtra(FruitActivity.FRUIT_ID,fruit.imageId)
            }
            context.startActivity(intent)
        }
        return holder
    }

在这里插入图片描述
2.充分利用系统状态栏空间
借助android:fitsSystemWindows=“true”,需要将ImageView布局结构中所有父布局都设置上

<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=".MainActivity"
    android:fitsSystemWindows="true"              <-------------------------
    >
    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appBar"
        android:layout_width="match_parent"
        android:layout_height="250dp"
        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/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:contentScrim="@color/colorPrimary"
            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">    <-------------------------

            </ImageView>
   ...
        </com.google.android.material.appbar.CollapsingToolbarLayout>
    </com.google.android.material.appbar.AppBarLayout>
   
...
</androidx.coordinatorlayout.widget.CoordinatorLayout>

我们还必须在程序主题中将状态栏颜色指定成透明色才行,在主题中将android:statusBarColor属性的值指定成@android:color/transparent
打开res/values/stytles.xml文件

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>

    <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />

    <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
    <style name="FruitActivityTheme" parent="AppTheme">                                       <-----
        <item name="android:statusBarColor">@android:color/transparent</item>      <-----新增
    </style>																													<------

</resources>

最后修改AndroidManifest.xml让FruitActivity使用这个主题

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.materialdesign">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".FruitActivity"
            android:label="@string/title_activity_fruit"
            android:theme="@style/FruitActivityTheme"></activity>       <--------
      ...
    </application>

</manifest>

在这里插入图片描述

Kotlin课堂:编写好用的工具方法

1.

fun max(vararg nums : Int) :Int{
	var maxNum = Int.MIN_VALUE
	for(num in nums){
		maxNum = max(maxNum,num)
	}
	return maxNum
}

在max()函数的参数声明中使用了vararg关键字,表示它可以接收任意多个参数。

fun <T : Comparable <T>> max(vararg nums : T) : T{
	if(nums.isEmpty()) throw RuntimeException("Params can not be empty")
	var maxNum = nums[0]
	for(num in nums){
	if(num > maxNum)
		maxNum =num
	}
}
return maxNum
}

Java中规定,所有类型的数字都是可以比较的,因此必须实现Comparable接口。我们借助泛型可以修改成接收任意多个实现Comparable接口的参数
2.简化Toast的用法

fun String.showToast(context : Context,duration: Int =Toast.LENGTH_SHORT) {
	Toast.makeText(context,this,duration).show()
}

这样调用即可

"This is Toast".showToast(context)

3.简化Snackbar的用法

fun View.showSnackbar(text : String,actionText : String? =null,duration : Int = Snackbar.LENGTH_SHORT,
block:(() -> Unit)? = null){	
	val snackbar =Snackbar.make(this,text,duration)
	if(actionText !=null&&block !=null){
		snackbar.setAction(actionText){
			block()
		}
	}
	snackbar.show()
}

这样调用即可

view.showSnackbar("This is Snackbar","Action"){
//处理具体逻辑
}

Git时间:版本控制工具的高级用法

1.分支的用法
创建一个分支

git branch version1.0

输入git branch这个命令检查一下
切换到version1.0这个分支上

git checkout version1.0

完成分支合并代码

git checkout master
git merge version1.0

当我们不需要分支时,将它删除

git branch -D version1.0

2.远程版本库协作
比如现在有一个远程版本库的Git地址时https://github.com/example/test.git,就可以使用以下命令将代码下载到本地

git clone https://github.com/example/test.git

把本地修改的内容同步到远程版本库,借助push命令来完成

git push origin master

origin指定的时远程版本库的git地址,master部分指定的是同步到哪一个分支上。
将远程版本库上修改同步到本地。Git提供两种命令,分别是fetch和pull。

git fetch origin master

执行完之后,远程版本库上修改同步到本地,但并不会合并到任何分支上,而是会村梵高origin/master分支上,这时我们可以通过diff命令来查看远程版本库上到底修改了那些东西

git diff origin/master

之后在调用merge命令将origin/master分支上的修改合并到主分支上即可

git merge origin/master

而pull命令则是相当于将fetch和merge这两个命令放在一起执行,他能从远程版本库上获取最新代码并且合并到本地

git pull origin master
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一天发火两次

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值