目前很常见的状态栏伸缩特效在Android5.0后我们可以通过MaterialDesign库很容易实现,该库的基础就是CoordinatorLayout即协调布局。
所谓的协调布局指的就是内部控件之间彼此存在着动作关联,比如A视图位置发生变化的时候,B视图位置按照一定的规律也进行相应的变化。
首先我们导入CoordinatorLayout库:
或者在Module的build.gradle中直接添加:
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0'
使用的时候我们需要把coordinatorlayout作为布局文件的根布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/cl_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.coordinatorlayout.widget.CoordinatorLayout>
协调布局实现效果类似于相对布局RelativeLayout,如果我们需要指定子视图的位置,可以通过下面几个属性实现:
- android:layout_gravity 指定子视图在coordinatorlayout内部的对其方式
- layout_anchor 指定视图参照物
- layout_anchorGravity 指定本视图相对于参照物的对其方式
看个简单的例子:
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/cl_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/ll_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_toast"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点击显示Toast内容" />
</LinearLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ic_home_black"
app:layout_anchor="@id/ll_main"
android:layout_margin="30dp"
app:layout_anchorGravity="bottom|right" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
然后我们在重写LaunchFragment的onActivityCreated方法,在其中为button绑定事件:
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
btn_toast.setOnClickListener {
Snackbar.make(
cl_main,
"我就想看看floatbutton会怎么变化",
Snackbar.LENGTH_SHORT
).show()
}
}
效果图:
接下来我们在来看看AppBarLayout,该布局继承自线性布局RelativeLayout,除了线性布局的属性外,还拥有下面几个常用的功能:
- 支持相应页面主题的滑动行为,也就是说当我们的页面进行上滑或者下拉操作的时候,该布局可以捕捉到该操作
- 捕获到上述操作后,能够通知toolbar按照指定的规则进行变化
布局文件:
<?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="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
style="@style/ToolbarTheme"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/popTheme" />
</com.google.android.material.appbar.AppBarLayout>
<fragment
android:id="@+id/nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
app:navGraph="@navigation/navigation" />/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_nav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="@color/color_bottom_view"
app:labelVisibilityMode="labeled"
app:menu="@menu/menu_bottom" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
关于scroll flags的源码定义:
<androidx.constraintlayout.widget.ConstraintLayout 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">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/home_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Launch Fragment"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
效果:
接下来我们需要了解一下可折叠工具栏布局CollapsingToolbarLayout,它是专门用来实现子布局内不同元素响应滚动细节的布局。
在app运行的时候,工具栏的高度其实是固定不变的,发生高度变化的布局其实就是CollapsingToolbarLayout。一般情况下我们把CollapsingToolbarLayout和工具栏背景设置为相同的颜色,所以看起来像是统一的工具栏在发生收缩和展开效果 。
和CollapsingToolbarLayout配合使用时我们需要关注toolbar以下的属性值:
- app:layout_collapseMode 折叠属性模式,指定子视图的折叠模式
pin:固定模式,toolbar固定,不受CollapsingToolbarLayout折叠影响
parallax:视差模式,跟随CollapsingToolbarLayout的收缩和展开,toolbar也会跟着收缩与展开。
none:默认值,CollapsingToolbarLayout折叠多少距离,toolbar也会跟着移动多少距离
其中parallax属性可通过app:layout_collapseParallaxMulti指定,该属性指定视差模式的折叠距离系数。当属性值为1.0的时候,折叠效果等同于pin模式。属性值为0.0的时候等同于none模式。
这里我们使用pin模式作为示例:
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="@dimen/appBarSize">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
style="@style/ToolbarTheme"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/popTheme" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
这里我们指定了AppBarLayout的高度,大家可以看到其上面的部分其实就是工具栏的位置,下面的部分就是CollapsingToolbarLayout去出toolbar的部分,通常我们会设置相同背景色。可以直接指定AppBarLayout的背景:
<com.google.android.material.appbar.AppBarLayout
.....
android:background="@color/color_header_bar">
.....
</com.google.android.material.appbar.AppBarLayout>