是否可以轻松地将 CoordinatorLayout 内的 AppBarLayout 下方的视图内容居中?
Is it possible to easily center the content of the view below AppBarLayout, inside CoordinatorLayout?
背景
假设您有一个带有 CoordinatorLayout 和 AppBarLayout 的滚动 activity,其中您有一个顶部 header 可以在底部滚动时折叠(可能有 RecyclerView 或 NestedScrollView)。
像这样:
现在,您需要在底部区域(显示文本的地方)的中心放置一个加载视图(例如,LinearLayout 中的一个 ProgressBar 和一个 TextView),然后再显示内容。
问题
我使用 ViewAnimator 在状态之间切换,但如果我选择将加载视图居中,它会显示在中心下方,因为底部区域占用更多 space 实际显示(如您可以滚动它)。
我试过的
我已经执行了 2 个解决方案,效果很好:
1.获取loading view的size和它的parent,用它来计算loading view的top margin
2. 将loading view的bottom padding设置为upper area size的一半(本例中为90dp,也就是upper area 180dp的一半)。这有点容易,但是如果 activity 或底部区域的 parent 中的任何内容的 UI 发生变化,它将破坏位于中心的修复。
密码
与 IDE 向导中的几乎相同,但此处:
ScrollingActivity.java
public class ScrollingActivity extends AppCompatActivity {
private ViewAnimator mViewAnimator;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scrolling);
setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
mViewAnimator = findViewById(R.id.viewAnimator);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_scrolling, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
mViewAnimator.showNext();
return true;
}
return super.onOptionsItemSelected(item);
}
}
res/layout/activity_scrolling.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.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:fitsSystemWindows="true"
tools:context="com.example.user.myapplication.ScrollingActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar" android:layout_width="match_parent" android:layout_height="@dimen/app_bar_height"
android:fitsSystemWindows="true" android:theme="@style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbar_layout" android:layout_width="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true" app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed" app:toolbarId="@+id/toolbar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<ViewAnimator
android:id="@+id/viewAnimator" android:layout_width="match_parent" android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:id="@+id/loader" android:layout_width="match_parent" android:layout_height="match_parent"
android:gravity="center" android:orientation="vertical">
<ProgressBar
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="loading"/>
</LinearLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/contentView" android:layout_width="match_parent" android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin" android:text="@string/large_text"/>
</android.support.v4.widget.NestedScrollView>
</ViewAnimator>
</android.support.design.widget.CoordinatorLayout>
res/menu/menu_scrolling.xml
<menu 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" tools:context="com.example.user.myapplication.ScrollingActivity">
<item
android:id="@+id/action_settings" android:orderInCategory="100" android:title="click"
app:showAsAction="always"/>
</menu>
问题
事实是,我可以自己计算,但我想知道是否有其他简单的方法可以做到这一点。也许是某种我不知道的旗帜?
我问这个是因为真实应用中的底部区域更复杂(上面的示例是为了演示问题),有一个片段甚至一个 TabLayout&ViewPager 有多个片段,所以计算的东西有点奇怪这些片段中的 parent Activity 用于此目的。
不仅如此,我在底部还有一个tabLayout(属于activity),这让我更讨厌考虑。
我认为从 ViewAnimator 中删除 app:layout_behavior="@string/appbar_scrolling_view_behavior"
应该可以解决问题。
或者,如果这不起作用,则将 ViewAnimator 包装在没有 behvariour 的 RelativeLayout 中,以便 ViewGroup 位于 AppBarLayout 后面,因此您的视图将居中。
更新 1(不工作)
测试了我提出的 2 个视图的建议并且有效:
<android.support.design.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:fitsSystemWindows="true"
tools:context="com.example.user.myapplication.ScrollingActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar" android:layout_width="match_parent" android:layout_height="@dimen/app_bar_height"
android:fitsSystemWindows="true" android:theme="@style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbar_layout" android:layout_width="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true" app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed" app:toolbarId="@+id/toolbar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/contentView" android:layout_width="match_parent" android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin" android:text="@string/large_text"/>
</android.support.v4.widget.NestedScrollView>
<LinearLayout
android:id="@+id/loader" android:layout_width="match_parent" android:layout_height="match_parent"
android:gravity="center" android:orientation="vertical" android:visibility="gone">
<ProgressBar
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="loading"/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
只需根据您的逻辑在视图中交换@+id/loader 和@+id/contentView 的可见性,这应该可行,但遗憾的是您错过了 ViewAnimator 的动画。
更新 2
我完全使用这段代码对其进行了测试(只是更改了 android 的自定义样式),它使加载器在整个视图中居中。只需在“@+id/loader”中尝试 adding/removing app:layout_behavior="@string/appbar_scrolling_view_behavior"
这样您就可以看到加载程序的位置发生了变化:
通过该行为,它以 AppBarLayout 下方的区域为中心。
没有它,它位于屏幕中心。
<android.support.design.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="com.example.user.myapplication.ScrollingActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="180dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:toolbarId="@+id/toolbar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/contentView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="@string/large_text"/>
</android.support.v4.widget.NestedScrollView>
<LinearLayout
android:id="@+id/loader"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="loading"/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
更新 3
显然,当 CollapsingToolbarLayout extended 时,它会将其下方的视图向下推(如果它具有 app:layout_behavior="@string/appbar_scrolling_view_behavior"
),同时考虑到内部工具栏的高度,这就是为什么当它处于这种状态时,那个视图的内容没有居中。
因此,在我们想要居中的视图具有透明背景并且仅占据区域中心的情况下,解决此问题的一种方法是利用 app:behavior_overlapTop / setOverlayTop(int) 并将该视图与 AppBarLayout 重叠工具栏的高度 (?attr/actionBarSize
):
<android.support.design.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="com.example.user.myapplication.ScrollingActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="180dp"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:toolbarId="@+id/toolbar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/contentView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="@string/large_text" />
</android.support.v4.widget.NestedScrollView>
<LinearLayout
android:id="@+id/loader"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone"
app:behavior_overlapTop="?attr/actionBarSize"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="loading"/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
希望对您有所帮助
尝试自定义行为。
class ViewBelowAppBarBehavior @JvmOverloads constructor(
context: Context? = null, attrs: AttributeSet? = null) : CoordinatorLayout.Behavior<View>(context, attrs) {
override fun layoutDependsOn(parent: CoordinatorLayout?, child: View?, dependency: View?) = dependency is AppBarLayout
override fun onDependentViewChanged(parent: CoordinatorLayout?, child: View?, dependency: View?): Boolean {
val appBar = dependency as AppBarLayout
// т.к. y - отрицательное число
val currentAppBarHeight = appBar.height + appBar.y
val parentHeight = parent?.height ?: 0
val placeHolderHeight = (parentHeight - currentAppBarHeight).toInt()
child?.layoutParams?.height = placeHolderHeight
child?.requestLayout()
return false
}
}
关于@Yarh 的回答的更详细的解释,非常完美:
首先创建您自己的布局行为(在我的例子中,我派生自 AppBarLayout.ScrollingViewBehavior
以保留原始行为)
class AdaptiveHeightScrollingViewBehavior(
context: Context,
attrs: AttributeSet
) : AppBarLayout.ScrollingViewBehavior(context, attrs) {
override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
(dependency as? AppBarLayout)?.let { appBar ->
val appBarHeight = appBar.height + appBar.y
child.layoutParams.height = (parent.height - appBarHeight).toInt()
child.requestLayout()
}
return super.onDependentViewChanged(parent, child, dependency)
}
}
然后在您的布局中使用 ViewPager/FragmentContainer/ViewGroup 或其他任何行为,只需确保它是 AppBarLayout
的同级
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.sample.behavior.AdaptiveHeightScrollingViewBehavior" />
背景
假设您有一个带有 CoordinatorLayout 和 AppBarLayout 的滚动 activity,其中您有一个顶部 header 可以在底部滚动时折叠(可能有 RecyclerView 或 NestedScrollView)。
像这样:
现在,您需要在底部区域(显示文本的地方)的中心放置一个加载视图(例如,LinearLayout 中的一个 ProgressBar 和一个 TextView),然后再显示内容。
问题
我使用 ViewAnimator 在状态之间切换,但如果我选择将加载视图居中,它会显示在中心下方,因为底部区域占用更多 space 实际显示(如您可以滚动它)。
我试过的
我已经执行了 2 个解决方案,效果很好: 1.获取loading view的size和它的parent,用它来计算loading view的top margin 2. 将loading view的bottom padding设置为upper area size的一半(本例中为90dp,也就是upper area 180dp的一半)。这有点容易,但是如果 activity 或底部区域的 parent 中的任何内容的 UI 发生变化,它将破坏位于中心的修复。
密码
与 IDE 向导中的几乎相同,但此处:
ScrollingActivity.java
public class ScrollingActivity extends AppCompatActivity {
private ViewAnimator mViewAnimator;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scrolling);
setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
mViewAnimator = findViewById(R.id.viewAnimator);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_scrolling, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
mViewAnimator.showNext();
return true;
}
return super.onOptionsItemSelected(item);
}
}
res/layout/activity_scrolling.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.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:fitsSystemWindows="true"
tools:context="com.example.user.myapplication.ScrollingActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar" android:layout_width="match_parent" android:layout_height="@dimen/app_bar_height"
android:fitsSystemWindows="true" android:theme="@style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbar_layout" android:layout_width="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true" app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed" app:toolbarId="@+id/toolbar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<ViewAnimator
android:id="@+id/viewAnimator" android:layout_width="match_parent" android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:id="@+id/loader" android:layout_width="match_parent" android:layout_height="match_parent"
android:gravity="center" android:orientation="vertical">
<ProgressBar
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="loading"/>
</LinearLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/contentView" android:layout_width="match_parent" android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin" android:text="@string/large_text"/>
</android.support.v4.widget.NestedScrollView>
</ViewAnimator>
</android.support.design.widget.CoordinatorLayout>
res/menu/menu_scrolling.xml
<menu 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" tools:context="com.example.user.myapplication.ScrollingActivity">
<item
android:id="@+id/action_settings" android:orderInCategory="100" android:title="click"
app:showAsAction="always"/>
</menu>
问题
事实是,我可以自己计算,但我想知道是否有其他简单的方法可以做到这一点。也许是某种我不知道的旗帜?
我问这个是因为真实应用中的底部区域更复杂(上面的示例是为了演示问题),有一个片段甚至一个 TabLayout&ViewPager 有多个片段,所以计算的东西有点奇怪这些片段中的 parent Activity 用于此目的。
不仅如此,我在底部还有一个tabLayout(属于activity),这让我更讨厌考虑。
我认为从 ViewAnimator 中删除 app:layout_behavior="@string/appbar_scrolling_view_behavior"
应该可以解决问题。
或者,如果这不起作用,则将 ViewAnimator 包装在没有 behvariour 的 RelativeLayout 中,以便 ViewGroup 位于 AppBarLayout 后面,因此您的视图将居中。
更新 1(不工作)
测试了我提出的 2 个视图的建议并且有效:
<android.support.design.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:fitsSystemWindows="true"
tools:context="com.example.user.myapplication.ScrollingActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar" android:layout_width="match_parent" android:layout_height="@dimen/app_bar_height"
android:fitsSystemWindows="true" android:theme="@style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbar_layout" android:layout_width="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true" app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed" app:toolbarId="@+id/toolbar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/contentView" android:layout_width="match_parent" android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin" android:text="@string/large_text"/>
</android.support.v4.widget.NestedScrollView>
<LinearLayout
android:id="@+id/loader" android:layout_width="match_parent" android:layout_height="match_parent"
android:gravity="center" android:orientation="vertical" android:visibility="gone">
<ProgressBar
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="loading"/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
只需根据您的逻辑在视图中交换@+id/loader 和@+id/contentView 的可见性,这应该可行,但遗憾的是您错过了 ViewAnimator 的动画。
更新 2
我完全使用这段代码对其进行了测试(只是更改了 android 的自定义样式),它使加载器在整个视图中居中。只需在“@+id/loader”中尝试 adding/removing app:layout_behavior="@string/appbar_scrolling_view_behavior"
这样您就可以看到加载程序的位置发生了变化:
通过该行为,它以 AppBarLayout 下方的区域为中心。
没有它,它位于屏幕中心。
<android.support.design.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="com.example.user.myapplication.ScrollingActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="180dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:toolbarId="@+id/toolbar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/contentView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="@string/large_text"/>
</android.support.v4.widget.NestedScrollView>
<LinearLayout
android:id="@+id/loader"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="loading"/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
更新 3
显然,当 CollapsingToolbarLayout extended 时,它会将其下方的视图向下推(如果它具有 app:layout_behavior="@string/appbar_scrolling_view_behavior"
),同时考虑到内部工具栏的高度,这就是为什么当它处于这种状态时,那个视图的内容没有居中。
因此,在我们想要居中的视图具有透明背景并且仅占据区域中心的情况下,解决此问题的一种方法是利用 app:behavior_overlapTop / setOverlayTop(int) 并将该视图与 AppBarLayout 重叠工具栏的高度 (?attr/actionBarSize
):
<android.support.design.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="com.example.user.myapplication.ScrollingActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="180dp"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:toolbarId="@+id/toolbar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/contentView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="@string/large_text" />
</android.support.v4.widget.NestedScrollView>
<LinearLayout
android:id="@+id/loader"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone"
app:behavior_overlapTop="?attr/actionBarSize"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="loading"/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
希望对您有所帮助
尝试自定义行为。
class ViewBelowAppBarBehavior @JvmOverloads constructor(
context: Context? = null, attrs: AttributeSet? = null) : CoordinatorLayout.Behavior<View>(context, attrs) {
override fun layoutDependsOn(parent: CoordinatorLayout?, child: View?, dependency: View?) = dependency is AppBarLayout
override fun onDependentViewChanged(parent: CoordinatorLayout?, child: View?, dependency: View?): Boolean {
val appBar = dependency as AppBarLayout
// т.к. y - отрицательное число
val currentAppBarHeight = appBar.height + appBar.y
val parentHeight = parent?.height ?: 0
val placeHolderHeight = (parentHeight - currentAppBarHeight).toInt()
child?.layoutParams?.height = placeHolderHeight
child?.requestLayout()
return false
}
}
关于@Yarh 的回答的更详细的解释,非常完美:
首先创建您自己的布局行为(在我的例子中,我派生自 AppBarLayout.ScrollingViewBehavior
以保留原始行为)
class AdaptiveHeightScrollingViewBehavior(
context: Context,
attrs: AttributeSet
) : AppBarLayout.ScrollingViewBehavior(context, attrs) {
override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
(dependency as? AppBarLayout)?.let { appBar ->
val appBarHeight = appBar.height + appBar.y
child.layoutParams.height = (parent.height - appBarHeight).toInt()
child.requestLayout()
}
return super.onDependentViewChanged(parent, child, dependency)
}
}
然后在您的布局中使用 ViewPager/FragmentContainer/ViewGroup 或其他任何行为,只需确保它是 AppBarLayout
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.sample.behavior.AdaptiveHeightScrollingViewBehavior" />