Android折叠工具栏/AppBarLayout在状态栏行为顶部填充后滚动
我想使用Android折叠工具栏/AppBarLayout在状态栏行为顶部填充后滚动,android,material-design,android-coordinatorlayout,android-appbarlayout,android-nestedscrollview,Android,Material Design,Android Coordinatorlayout,Android Appbarlayout,Android Nestedscrollview,我想使用CoordinatoryLayout、AppBarLayout和CollasingToolbarLayout创建一个类似于Google Calendar中以下示例的布局 我试图复制的关键内容是: 滚动状态栏后面的内容 滚动容器顶部的圆角 屏幕顶部有足够的空间使标题看起来不会被压扁 问题 随着用户的滚动,谷歌日历似乎在增加滚动容器。我将如何着手做这件事或类似的事情来达到我想要的外观 我总结了一个我正在尝试构建的快速示例: 活动\u scrolling.xml <androidx
CoordinatoryLayout
、AppBarLayout
和CollasingToolbarLayout
创建一个类似于Google Calendar中以下示例的布局
我试图复制的关键内容是:
- 滚动状态栏后面的内容
- 滚动容器顶部的圆角
- 屏幕顶部有足够的空间使标题看起来不会被压扁
<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"
android:animateLayoutChanges="true"
tools:context="uk.co.exampleapplication.ScrollingActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<include
android:id="@+id/lay_header"
layout="@layout/layout_header" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/scroll_header_background"
android:elevation="16dp"
android:paddingBottom="12dp">
<TextView
android:id="@+id/sectionTitleText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="32dp"
android:text="Title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/filter_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="22dp"
android:layout_marginEnd="16dp"
android:text="Button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</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"
tools:context=".ScrollingActivity"
tools:showIn="@layout/activity_scrolling">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:text="@string/large_text" />
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingHorizontal="16dp"
android:paddingTop="60dp"
android:paddingBottom="40dp"
app:layout_collapseMode="parallax"
tools:ignore="HardcodedText">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="24dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:text="Title"
android:textColor="#FFF"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Subtitle"
android:textColor="#FFF"
android:textSize="16sp"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title" />
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:bottomLeftRadius="0dp"
android:bottomRightRadius="0dp"
android:topLeftRadius="20dp"
android:topRightRadius="20dp" />
<solid android:color="#FFFFFF" />
<size
android:width="64dp"
android:height="64dp" />
</shape>
实现一个将调整包含TextView和按钮的ConstraintLayout上的顶部填充。(将此视图称为“viewToGrow”。)您还可以在侦听器中执行其他操作,如在appbar滚动时更改可绘制图形的角半径
下面的示例调整顶部填充以给页眉更多空间。此填充随着appbar向上滚动而增加,随着appbar向下滚动而减少。在appbar滚动的最后15%期间,演示应用程序还删除了可绘制的角半径
滚动活动
class ScrollingActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_scrolling)
val viewToGrow: View = findViewById(R.id.viewToGrow)
val baseTopPadding = viewToGrow.paddingTop
// Determine how much top padding has to grow while the app bar scrolls.
var maxDeltaPadding = 0
val contentView = findViewById<View>(android.R.id.content)
ViewCompat.setOnApplyWindowInsetsListener(contentView) { _, insets ->
maxDeltaPadding = insets.systemWindowInsetTop
insets
}
// Get key metrics for corner radius shrikage.
var backgroundRadii: FloatArray? = null
var maxRadius: FloatArray? = null
val backgroundDrawable = (viewToGrow.background as GradientDrawable?)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && backgroundDrawable != null) {
backgroundRadii = backgroundDrawable.cornerRadii
maxRadius = floatArrayOf(backgroundRadii!![0], backgroundRadii[1])
}
// Set up the app bar and the offset change listener.
val appBar: AppBarLayout = findViewById(R.id.app_bar_layout)
val appBarTotalScrollRange: Float by lazy {
appBar.totalScrollRange.toFloat()
}
appBar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { _, verticalOffset ->
// Add/remove padding gradually as the appbar scrolls.
val percentOfScrollRange = (-verticalOffset / appBarTotalScrollRange)
val deltaPadding = maxDeltaPadding * percentOfScrollRange
val newTopPadding = baseTopPadding + deltaPadding.toInt()
if (newTopPadding != viewToGrow.paddingTop) {
viewToGrow.setPadding(
viewToGrow.paddingLeft,
newTopPadding,
viewToGrow.paddingRight,
viewToGrow.paddingBottom
)
// Change the drawable radius as the appbar scrolls.
if (backgroundRadii != null && maxRadius != null) {
val radiusShrinkage = if (percentOfScrollRange > (1.0f - CORNER_SHRINK_RANGE)) {
(1.0f - percentOfScrollRange) / CORNER_SHRINK_RANGE
} else {
1.0f
}
backgroundRadii[0] = maxRadius[0] * radiusShrinkage
backgroundRadii[1] = maxRadius[1] * radiusShrinkage
backgroundRadii[2] = maxRadius[0] * radiusShrinkage
backgroundRadii[3] = maxRadius[1] * radiusShrinkage
backgroundDrawable!!.cornerRadii = backgroundRadii
}
}
})
}
companion object {
const val CORNER_SHRINK_RANGE = 0.15f
}
}
class ScrollingActivity:AppCompatActivity(){
重写创建时的乐趣(savedInstanceState:Bundle?){
super.onCreate(savedInstanceState)
setContentView(R.layout.activity\u滚动)
val viewToGrow:View=findViewById(R.id.viewToGrow)
val baseTopPadding=viewToGrow.paddingTop
//确定应用程序栏滚动时顶部填充的增长量。
var maxDeltaPadding=0
val contentView=findviewbyd(android.R.id.content)
ViewCompat.setOnApplyWindowInsetsListener(contentView){},insets->
maxDeltaPadding=insets.systemWindowInsetTop
插图
}
//获取角半径收缩的关键指标。
变量背景半径:FloatArray?=null
var maxRadius:FloatArray?=null
val backgroundDrawable=(viewToGrow.background是否为GradientDrawable?)
if(Build.VERSION.SDK\u INT>=Build.VERSION\u code.N&&backgroundDrawable!=null){
背景半径=背景可拉伸半径
maxRadius=floatArrayOf(背景半径!![0],背景半径[1])
}
//设置应用程序栏和偏移量更改侦听器。
val appBar:AppBarLayout=findViewById(R.id.app\u bar\u布局)
val appBarTotalScrollRange:按惰性浮动{
appBar.totalScrollRange.toFloat()文件
}
appBar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener{},垂直偏移->
//随着appbar滚动,逐渐添加/删除填充。
瓦尔百分比CrollRange=(-verticalOffset/AppBarTotalCrollRange)
val deltaPadding=maxDeltaPadding*CrollRange百分比
val newTopPadding=baseTopPadding+deltappadding.toInt()
if(newTopPadding!=viewToGrow.paddingTop){
viewToGrow.setPadding(
viewToGrow.paddingLeft,
牛顿补充说,
viewToGrow.paddingRight,
viewToGrow.paddingBottom
)
//在appbar滚动时更改可绘制半径。
if(backgroundRadii!=null&&maxRadius!=null){
val radiusShrinkage=if(CrollRange的百分比>(1.0f-角部收缩范围)){
(1.0f-收缩范围百分比)/拐角收缩范围
}否则{
1.0f
}
背景半径[0]=最大半径[0]*半径收缩
背景半径[1]=最大半径[1]*半径收缩
背景半径[2]=最大半径[0]*半径收缩
背景半径[3]=最大半径[1]*半径收缩
背景可绘制!!.cornerRadii=背景半径
}
}
})
}
伴星{
const val拐角收缩范围=0.15f
}
}
实现一个将调整包含TextView和按钮的ConstraintLayout顶部填充的。(将此视图称为“viewToGrow”。)您还可以在侦听器中执行其他操作,如在appbar滚动时更改可绘制图形的角半径
下面的示例调整顶部填充以给页眉更多空间。此填充随着appbar向上滚动而增加,随着appbar向下滚动而减少。在appbar滚动的最后15%期间,演示应用程序还删除了可绘制的角半径
滚动活动
class ScrollingActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_scrolling)
val viewToGrow: View = findViewById(R.id.viewToGrow)
val baseTopPadding = viewToGrow.paddingTop
// Determine how much top padding has to grow while the app bar scrolls.
var maxDeltaPadding = 0
val contentView = findViewById<View>(android.R.id.content)
ViewCompat.setOnApplyWindowInsetsListener(contentView) { _, insets ->
maxDeltaPadding = insets.systemWindowInsetTop
insets
}
// Get key metrics for corner radius shrikage.
var backgroundRadii: FloatArray? = null
var maxRadius: FloatArray? = null
val backgroundDrawable = (viewToGrow.background as GradientDrawable?)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && backgroundDrawable != null) {
backgroundRadii = backgroundDrawable.cornerRadii
maxRadius = floatArrayOf(backgroundRadii!![0], backgroundRadii[1])
}
// Set up the app bar and the offset change listener.
val appBar: AppBarLayout = findViewById(R.id.app_bar_layout)
val appBarTotalScrollRange: Float by lazy {
appBar.totalScrollRange.toFloat()
}
appBar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { _, verticalOffset ->
// Add/remove padding gradually as the appbar scrolls.
val percentOfScrollRange = (-verticalOffset / appBarTotalScrollRange)
val deltaPadding = maxDeltaPadding * percentOfScrollRange
val newTopPadding = baseTopPadding + deltaPadding.toInt()
if (newTopPadding != viewToGrow.paddingTop) {
viewToGrow.setPadding(
viewToGrow.paddingLeft,
newTopPadding,
viewToGrow.paddingRight,
viewToGrow.paddingBottom
)
// Change the drawable radius as the appbar scrolls.
if (backgroundRadii != null && maxRadius != null) {
val radiusShrinkage = if (percentOfScrollRange > (1.0f - CORNER_SHRINK_RANGE)) {
(1.0f - percentOfScrollRange) / CORNER_SHRINK_RANGE
} else {
1.0f
}
backgroundRadii[0] = maxRadius[0] * radiusShrinkage
backgroundRadii[1] = maxRadius[1] * radiusShrinkage
backgroundRadii[2] = maxRadius[0] * radiusShrinkage
backgroundRadii[3] = maxRadius[1] * radiusShrinkage
backgroundDrawable!!.cornerRadii = backgroundRadii
}
}
})
}
companion object {
const val CORNER_SHRINK_RANGE = 0.15f
}
}
class ScrollingActivity:AppCompatActivity(){
重写创建时的乐趣(savedInstanceState:Bundle?){
super.onCreate(savedInstanceState)
setContentView(R.layout.activity\u滚动)
val viewToGrow:View=findViewById(R.id.viewToGrow)
val baseTopPadding=viewToGrow.paddingTop
//确定应用程序栏滚动时顶部填充的增长量。
var maxDeltaPadding=0
val contentView=findviewbyd(android.R.id.content)
ViewCompat.setOnApplyWindowInsetsListener(contentView){},insets->
maxDeltaPadding=insets.systemWindowInsetTop
插图
}
//获取角半径收缩的关键指标。
变量背景半径:FloatArray?=null
var maxRadius:FloatArray?=null
val backgroundDrawable=(viewToGrow.background是否为GradientDrawable?)
if(Build.VERSION.SDK\u INT>=Build.VERSION\u code.N&&backgroundDrawable!=null){
背景半径=背景可拉伸半径
maxRadius=floa