开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 23 天,点击查看活动详情
前言
之前在滑动菜单使用的文章中,我们的标题栏是使用Toolbar写的,但与我们基础的ActionBar看不出有什么不一样的地方,除了可以响应RecyclerView的滚动事件来进行隐藏和显示,所以我们可以采用Material Design去设计一个可折叠式标题栏。
正篇
首先我们看看接下来几个要用到的组件是如何使用的。
CollapsingToolbarLayout
这是一个作用于Toolbar基础之上的布局,同样由Material库提供,而它的作用就是使Toolbar效果很丰富。
但要注意的是,这个布局不可以单独使用,我们要让他作为AppBarLayout的直接子布局使用,而AppBarLayout又必须是CoordinatorLayout的子布局,所以我们需要组合来使用:
<?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: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="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
我们布局采用最外层为CoordinatorLayout,然后嵌套一个AppBarLayout,最后往AppBarLayout中再嵌套我们的新布局CollapsingToolbarLayout,而新布局中我们通过android:theme属性去指定了主题,使用app:contentScrim属性设置在该布局趋于折叠状态和折叠之后的背景色,我们的CollapsingToolbarLayout布局其实在折叠之后就呈现出之前我们使用的Toolbar的样式,所以我们给这个背景色再设置为colorPrimary,而app:layout_scrollFlags代表设置滚动方式的,scroll就是随着下面的内容滚动而一起滚动,exitUntilCollapsed则是随着滚动完成折叠之后就保留在界面上,不再移出屏幕。
接下来我们再为CollapsingToolbarLayout定义标题栏的具体内容:
<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="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:id="@+id/fruitImageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax" />
<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>
我们为其加了一个ImageView子布局和Toolbar子布局,这就表示CollapsingToolbarLayout这个更高级的标题栏样式由一张图片与一个普通标题栏组合而成。
这里的属性设置中,app:layout_collapseMode是用于指定当前控件在CollapsingToolbarLayout折叠过程中的折叠模式,pin代表折叠的过程中位置始终保持不变,而parallax则表示会在折叠的过程中产生一定的错位偏移,达到更好的视觉效果。
写好我们的标题栏后,我们在标题栏布局下面添加一个滚动视图以及一个悬浮按钮,这里滚动视图我们使用布局NestedScrollView,它和 ScrollView 布局一样,都只能接受一个直接子布局,如果需要滚动布局内部加很多其他布局组件之类的,通常就会先在滚动布局里面嵌套一个LinearLayout,然后在LinearLayout中写其他的子布局结构(具体内容),布局代码如下:
<?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: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="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:id="@+id/fruitImageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax" />
<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">
<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" />
</com.google.android.material.card.MaterialCardView>
</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属性指定了一个布局行为,我们将MaterialCardView作为其内部的子布局然后为其加上TextView形成一个文字卡片样式布局,我们最后在布局中又增加了一个FloatingActionButton作为悬浮按钮,这样,我们的一套布局就完成了。
完成布局代码构建后,我们需要在Avtivity做出相应调整,代码如下:
package com.example.materialdemo
import android.os.Bundle
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import com.bumptech.glide.Glide
import com.example.materialdemo.databinding.ActivityFruitBinding
class FruitActivity : AppCompatActivity() {
companion object {
const val FRUIT_NAME = "fruit_name"
const val FRUIT_IMAGE_ID = "fruit_image_id"
}
lateinit var binding: ActivityFruitBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityFruitBinding.inflate(layoutInflater)
setContentView(binding.root)
val fruitName = intent.getStringExtra(FRUIT_NAME) ?: ""
val fruitImageId = intent.getIntExtra(FRUIT_IMAGE_ID, 0)
setSupportActionBar(binding.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
binding.collapsingToolbar.title = fruitName
Glide.with(this).load(fruitImageId).into(binding.fruitImageView)
binding.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)
}
不过,如果想启动我们这个新的Activity,首先应该在我们的首页添加跳转的点击事件,在点击事件里使用Intent跳转页面:
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_IMAGE_ID, fruit.imageId)
}
context.startActivity(intent)
最终效果如下:
总结
Material库的东西太多,这只是其中用的比较多的地方,需要我们日积月累,慢慢熟悉它们。