Android Draw 在状态栏后面但不在导航栏后面
Posted
技术标签:
【中文标题】Android Draw 在状态栏后面但不在导航栏后面【英文标题】:Android Draw behind Status bar but not behind the navigation bar 【发布时间】:2016-01-26 02:04:02 【问题描述】:我正在研究一种方式,使状态栏完全透明,而不是半透明,并且导航栏保持不变。
我能得到的最接近的是使用标志
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
但这也会在导航栏后面绘制。
背景使这个变得棘手,它是一个微妙的渐变,当我将状态栏颜色设置为渐变的开始时,它看起来几乎正确,但在屏幕顶部有一条微妙的线条。
有没有一种好方法可以让 Activity 适应窗口,只在顶部,但如果底部有导航栏,就不要管它了吗?
【问题讨论】:
【参考方案1】:一个好的方法是来自this answer 的方法一。
要实现完全透明的状态栏,你必须使用 statusBarColor,仅适用于 API 21 及更高版本。 windowTranslucentStatus 在 API 19 及更高版本中可用,但它为状态栏添加了有色背景。但是,设置 windowTranslucentStatus 确实实现了将 statusBarColor 更改为透明的一件事:它设置了 SYSTEM_UI_FLAG_LAYOUT_STABLE 和 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 标志。获得相同效果的最简单方法是手动设置这些 标志,它有效地禁用了 android 强加的插图 布局系统,让您自生自灭。
您在 onCreate 方法中调用此行:
getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
请务必在 /res/values-v21/styles.xml 中设置透明度:
<item name="android:statusBarColor">@android:color/transparent</item>
或以编程方式设置透明度:
getWindow().setStatusBarColor(Color.TRANSPARENT);
这种方法的好处是相同的布局和设计 也可以通过交换透明状态栏在 API 19 上使用 用于有色半透明状态栏。
<item name="android:windowTranslucentStatus">true</item>
我猜你已经尝试过这个或类似的东西。如果这不起作用,请确保您的根元素是 FrameLayout
。
【讨论】:
默认为 android.support.design.widget.CoordinatorLayout 而不是框架布局。成功了,谢谢【参考方案2】:免责声明: 这是补充答案,因为接受的答案在 API 级别 30 之前有效且不被弃用,因为系统 自 API 级别 30 起,可见性标志已被弃用。
setDecorFitsSystemWindows()
为您的应用实现edge-to-edge(即应用将扩展其内容以扩展到整个屏幕以覆盖系统状态栏和导航栏)
这可以在活动中实现:
WindowCompat.setDecorFitsSystemWindows(window, false)
现在剩下的就是避免与系统导航栏重叠:
As per documentation:
您可以通过对插图做出反应来解决重叠问题,插图指定了哪些 屏幕的某些部分与导航等系统 UI 相交 栏或状态栏。相交可能意味着简单地显示 上面的内容,但它也可以通知你的应用程序关于系统 手势也是。
所以,我们需要处理 API 级别 30+ 的插入,以避免应用与底部导航栏重叠:
/*
* Making the Navigation system bar not overlapping with the activity
*/
if (Build.VERSION.SDK_INT >= 30)
// Root ViewGroup of my activity
val root = findViewById<ConstraintLayout>(R.id.root)
ViewCompat.setOnApplyWindowInsetsListener(root) view, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
// Apply the insets as a margin to the view. Here the system is setting
// only the bottom, left, and right dimensions, but apply whichever insets are
// appropriate to your layout. You can also update the view padding
// if that's more appropriate.
view.layoutParams = (view.layoutParams as FrameLayout.LayoutParams).apply
leftMargin = insets.left
bottomMargin = insets.bottom
rightMargin = insets.right
// Return CONSUMED if you don't want want the window insets to keep being
// passed down to descendant views.
WindowInsetsCompat.CONSUMED
Check documentation 了解更多信息。
加分:
如果您打算将<item name="android:windowTranslucentStatus">true</item>
用于较低的API 级别,那么您必须覆盖API-30 中的主题/样式;即有一个默认样式的res\values-v30\themes.xml
(当然没有windowTranslucentStatus
)
【讨论】:
有没有办法使用 WindowCompat 的这个新方法只在状态栏后面绘制?正如您所提到的,这目前使应用程序在状态栏和导航栏后面绘制。 @vepzfe 你能在答案ViewCompat.setOnApplyWindowInsetsListener
中添加这段代码吗,这将使它在底部导航栏上方绘制......还要确保你没有添加`topMargin = insets .top` 使其不会在状态栏上绘制
也请查看this answer;还有更详细的
感谢您的链接。所以简而言之,避免在导航栏后面绘制的唯一方法是使用插图并设置底部边距,因为没有办法告诉系统不要在那里绘制应用程序。
我明白了。我现在知道了。诚然,旧的弃用代码仍然有效。我之所以要为系统寻找一种方法,是因为我的特定活动的布局非常复杂,有多个底部工作表,因此设置底部边距不起作用,并且需要在布局中进行大量更改。因此,直到我能找到更好的解决方案,使用旧的弃用标志。我尝试为装饰视图和 decorView.rootView 甚至使用 window.attributes 的窗口设置下边距,但这些都不起作用。以上是关于Android Draw 在状态栏后面但不在导航栏后面的主要内容,如果未能解决你的问题,请参考以下文章