[英]Completely transparent navigation bar but it shouldn't affect the status bar on Android
[英]Android Completely transparent Status Bar?
我搜索了文檔,但只找到了這個:Link 。 哪個是用來使酒吧半透明的? 我要做的是使狀態欄完全透明(如下圖所示)並使其向后兼容 APK<19:
我的 styles.xml:
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="AppTheme" parent="Theme.AppCompat.Light">
<item name="android:actionBarStyle">@style/ThemeActionBar</item>
<item name="android:windowActionBarOverlay">true</item>
<!-- Support library compatibility -->
<item name="actionBarStyle">@style/ThemeActionBar</item>
<item name="windowActionBarOverlay">true</item>
</style>
<style name="ThemeActionBar" parent="Widget.AppCompat.Light.ActionBar.Solid">
<item name="android:background"> @null </item>
<!-- Support library compatibility -->
<item name="background">@null</item>
<item name="android:displayOptions"> showHome | useLogo</item>
<item name="displayOptions">showHome|useLogo</item>
</style>
</resources>
我能做的:
您需要做的就是在您的主題中設置這些屬性:
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
您希望擁有透明狀態欄的活動/容器布局需要此屬性集:
android:fitsSystemWindows="true"
通常不可能在 pre-kitkat 上確定執行此操作,看起來您可以執行此操作, 但一些奇怪的代碼使其如此。
編輯:我會推薦這個庫: https ://github.com/jgilfelt/SystemBarTint 用於大量的棒棒糖前狀態欄顏色控制。
經過深思熟慮,我了解到完全禁用棒棒糖狀態欄和導航欄上的半透明或任何顏色的答案是在窗口上設置此標志:
// In Activity's onCreate() for instance
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Window w = getWindow();
w.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
}
不需要其他主題,它會產生如下內容:
您可以使用下面的代碼使狀態欄透明。 查看帶有紅色突出顯示的圖像,可幫助您識別以下代碼的使用
您的 Android 應用程序的 Kotlin 代碼片段
Step:1在 On create Method 中寫下代碼
if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 21) {
setWindowFlag(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, true)
}
if (Build.VERSION.SDK_INT >= 19) {
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
}
if (Build.VERSION.SDK_INT >= 21) {
setWindowFlag(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, false)
window.statusBarColor = Color.TRANSPARENT
}
Step2:您需要下面代碼中描述的 SetWindowFlag 方法。
private fun setWindowFlag(bits: Int, on: Boolean) {
val win = window
val winParams = win.attributes
if (on) {
winParams.flags = winParams.flags or bits
} else {
winParams.flags = winParams.flags and bits.inv()
}
win.attributes = winParams
}
您的 android 應用程序的 Java 代碼片段:
Step1:主要活動代碼
if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 21) {
setWindowFlag(this, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, true);
}
if (Build.VERSION.SDK_INT >= 19) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
if (Build.VERSION.SDK_INT >= 21) {
setWindowFlag(this, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, false);
getWindow().setStatusBarColor(Color.TRANSPARENT);
}
Step2: SetWindowFlag 方法
public static void setWindowFlag(Activity activity, final int bits, boolean on) {
Window win = activity.getWindow();
WindowManager.LayoutParams winParams = win.getAttributes();
if (on) {
winParams.flags |= bits;
} else {
winParams.flags &= ~bits;
}
win.setAttributes(winParams);
}
只需將這行代碼添加到您的主 java 文件中:
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
);
適用於 Android KitKat 及更高版本(對於那些想要透明狀態欄且不操縱 NavigationBar 的人,因為所有這些答案也會使 NavigationBar 透明!)
實現它的最簡單方法:
將這 3 行代碼放入styles.xml (v19)
-> 如果您不知道如何擁有它 (v19),只需將它們寫入您的默認styles.xml
,然后使用alt + enter自動創建它:
<item name="android:windowFullscreen">false</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:fitsSystemWindows">false</item>
現在,轉到您的MainActivity
類並將此方法放在類中的 onCreate 之外:
public static void setWindowFlag(Activity activity, final int bits, boolean on) {
Window win = activity.getWindow();
WindowManager.LayoutParams winParams = win.getAttributes();
if (on) {
winParams.flags |= bits;
} else {
winParams.flags &= ~bits;
}
win.setAttributes(winParams);
}
然后把這段代碼放到Activity的onCreate
方法中:
if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 21) {
setWindowFlag(this, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, true);
}
if (Build.VERSION.SDK_INT >= 19) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
//make fully Android Transparent Status bar
if (Build.VERSION.SDK_INT >= 21) {
setWindowFlag(this, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, false);
getWindow().setStatusBarColor(Color.TRANSPARENT);
}
而已!
您可以使用外部庫StatusBarUtil :
添加到您的模塊級別build.gradle
:
compile 'com.jaeger.statusbarutil:library:1.4.0'
然后,您可以對 Activity 使用以下 util 使狀態欄透明:
StatusBarUtil.setTransparent(Activity activity)
例子:
完全透明的狀態欄和導航欄
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
transparentStatusAndNavigation();
}
private void transparentStatusAndNavigation() {
//make full transparent statusBar
if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 21) {
setWindowFlag(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, true);
}
if (Build.VERSION.SDK_INT >= 19) {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
);
}
if (Build.VERSION.SDK_INT >= 21) {
setWindowFlag(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, false);
getWindow().setStatusBarColor(Color.TRANSPARENT);
getWindow().setNavigationBarColor(Color.TRANSPARENT);
}
}
private void setWindowFlag(final int bits, boolean on) {
Window win = getWindow();
WindowManager.LayoutParams winParams = win.getAttributes();
if (on) {
winParams.flags |= bits;
} else {
winParams.flags &= ~bits;
}
win.setAttributes(winParams);
}
在狀態欄下繪制布局:
值/樣式.xml
<item name="android:windowTranslucentStatus">true</item>
值-v21/styles.xml
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@color/colorPrimaryDark</item>
使用 CoordinatorLayout/DrawerLayout 已經處理了 fitSystemWindows 參數或創建自己的布局,如下所示:
public class FitsSystemWindowConstraintLayout extends ConstraintLayout {
private Drawable mStatusBarBackground;
private boolean mDrawStatusBarBackground;
private WindowInsetsCompat mLastInsets;
private Map<View, int[]> childsMargins = new HashMap<>();
public FitsSystemWindowConstraintLayout(Context context) {
this(context, null);
}
public FitsSystemWindowConstraintLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FitsSystemWindowConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (ViewCompat.getFitsSystemWindows(this)) {
ViewCompat.setOnApplyWindowInsetsListener(this, new android.support.v4.view.OnApplyWindowInsetsListener() {
@Override
public WindowInsetsCompat onApplyWindowInsets(View view, WindowInsetsCompat insets) {
FitsSystemWindowConstraintLayout layout = (FitsSystemWindowConstraintLayout) view;
layout.setChildInsets(insets, insets.getSystemWindowInsetTop() > 0);
return insets.consumeSystemWindowInsets();
}
});
setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
TypedArray typedArray = context.obtainStyledAttributes(new int[]{android.R.attr.colorPrimaryDark});
try {
mStatusBarBackground = typedArray.getDrawable(0);
} finally {
typedArray.recycle();
}
} else {
mStatusBarBackground = null;
}
}
public void setChildInsets(WindowInsetsCompat insets, boolean draw) {
mLastInsets = insets;
mDrawStatusBarBackground = draw;
setWillNotDraw(!draw && getBackground() == null);
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
if (ViewCompat.getFitsSystemWindows(this)) {
ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) child.getLayoutParams();
if (ViewCompat.getFitsSystemWindows(child)) {
ViewCompat.dispatchApplyWindowInsets(child, insets);
} else {
int[] childMargins = childsMargins.get(child);
if (childMargins == null) {
childMargins = new int[]{layoutParams.leftMargin, layoutParams.topMargin, layoutParams.rightMargin, layoutParams.bottomMargin};
childsMargins.put(child, childMargins);
}
if (layoutParams.leftToLeft == LayoutParams.PARENT_ID) {
layoutParams.leftMargin = childMargins[0] + insets.getSystemWindowInsetLeft();
}
if (layoutParams.topToTop == LayoutParams.PARENT_ID) {
layoutParams.topMargin = childMargins[1] + insets.getSystemWindowInsetTop();
}
if (layoutParams.rightToRight == LayoutParams.PARENT_ID) {
layoutParams.rightMargin = childMargins[2] + insets.getSystemWindowInsetRight();
}
if (layoutParams.bottomToBottom == LayoutParams.PARENT_ID) {
layoutParams.bottomMargin = childMargins[3] + insets.getSystemWindowInsetBottom();
}
}
}
}
}
requestLayout();
}
public void setStatusBarBackground(Drawable bg) {
mStatusBarBackground = bg;
invalidate();
}
public Drawable getStatusBarBackgroundDrawable() {
return mStatusBarBackground;
}
public void setStatusBarBackground(int resId) {
mStatusBarBackground = resId != 0 ? ContextCompat.getDrawable(getContext(), resId) : null;
invalidate();
}
public void setStatusBarBackgroundColor(@ColorInt int color) {
mStatusBarBackground = new ColorDrawable(color);
invalidate();
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mDrawStatusBarBackground && mStatusBarBackground != null) {
int inset = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
if (inset > 0) {
mStatusBarBackground.setBounds(0, 0, getWidth(), inset);
mStatusBarBackground.draw(canvas);
}
}
}
}
main_activity.xml
<FitsSystemWindowConstraintLayout 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">
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:src="@drawable/toolbar_background"
app:layout_constraintBottom_toBottomOf="@id/toolbar"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="0dp"
android:layout_height="?attr/actionBarSize"
android:background="@android:color/transparent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Content"
android:textSize="48sp" />
</LinearLayout>
</FitsSystemWindowConstraintLayout>
結果:
簡單明了,適用於幾乎所有用例(API 級別 16 及以上):
在您的應用主題中使用以下標簽使狀態欄透明:
<item name="android:statusBarColor">@android:color/transparent</item>
然后在您的活動的 onCreate 方法中使用此代碼。
View decorView = getWindow().getDecorView(); decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
這就是你需要做的一切;)
您可以從 開發人員文檔中了解更多信息。 我還建議閱讀這篇博文。
科特林代碼:
val decorView = window.decorView
decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
在這里查看我的另一個答案
這是 kotlin 中的一個擴展,可以解決問題:
fun Activity.setTransparentStatusBar() {
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.statusBarColor = Color.TRANSPARENT
}
}
在頂部布局中使用android:fitsSystemWindows="false"
有三個步驟:
1)只需將此代碼段用於您的 OnCreate 方法
// FullScreen
getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
如果您正在處理 Fragment,則應將此代碼段放在活動的 OnCreate 方法中。
2)一定要在 /res/values-v21/styles.xml 中設置透明度:
<item name="android:statusBarColor">@android:color/transparent</item>
或者您可以以編程方式設置透明度:
getWindow().setStatusBarColor(Color.TRANSPARENT);
3)無論如何你應該在styles.xml中添加代碼段
<item name="android:windowTranslucentStatus">true</item>
注意:此方法僅適用於 API 21 及更高版本。
對於具有日/夜支持的 API > 23,您可以使用下面的擴展。 要理解的重要部分是android:fitsSystemWindows="true"
使用填充在插圖內移動(就像使用工具欄一樣)。 因此,將其放置在您的根布局中是沒有意義的(除了 DrawerLayout、CoordinatorLayout,......這些使用它們自己的實現)。
<style name="Theme.YourApp.DayNight" parent="Theme.MaterialComponents.DayNight.NoActionBar">
...
<item name="android:windowLightStatusBar">@bool/isDayMode</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
<androidx.constraintlayout.widget.ConstraintLayout
...>
<com.google.android.material.appbar.MaterialToolbar
...
android:fitsSystemWindows="true">
</androidx.constraintlayout.widget.ConstraintLayout
fun Activity.transparentStatusBar() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
} else {
window.setDecorFitsSystemWindows(false)
}
}
然后像這樣調用它:
class YourActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
transparentStatusBar()
}
}
查看 Chris Banes 的這些幻燈片:成為一名主要的窗戶裝配工
編輯:如果您在導航欄后面浮動的內容有問題,請使用
// using Insetter
binding.yourViewHere.applySystemWindowInsetsToPadding(bottom = true)
我剛在這里找到
因為已經過了 6 年,默認的 minSDKAPI 是 21 (Lollipop) *CMIIW。 這是我總結透明狀態欄而不與導航按鈕重疊的方法:
fun setStatusBarTransparent(activity: Activity, view: View) {
activity.apply {
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
window.statusBarColor = ContextCompat.getColor(this, R.color.transparent)
WindowCompat.setDecorFitsSystemWindows(window, false)
ViewCompat.setOnApplyWindowInsetsListener(view) { root, windowInset ->
val inset = windowInset.getInsets(WindowInsetsCompat.Type.systemBars())
root.updateLayoutParams<ViewGroup.MarginLayoutParams> {
leftMargin = inset.left
bottomMargin = inset.bottom
rightMargin = inset.right
}
WindowInsetsCompat.CONSUMED
}
}
}
我將該函數放在名為UiUtils
的Object
類中,因此當我在我的活動中調用該函數時(我也使用 View Binding)。 它看起來像這樣:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
UiUtils.setStatusBarTransparent(this, bind.root)
...
}
希望我的回答能幫到大家:)
這是我經過大量搜索后找到的一種簡單方法。
步驟1
在你的主題中放這個項目
<item name="android:statusBarColor" tools:targetApi="lollipop">@android:color/transparent</item>
第2步
在主要活動中
WindowCompat.setDecorFitsSystemWindows(window, false)
如果您使用 BottomNavigationBar,則非常重要
在某些設備中,如果在您的應用程序中使用 API 30+,您會發現系統導航欄與底部導航欄重疊。
這是解決這個問題。
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
}
}
在您的 XML 中使用此代碼,您將能夠在您的活動中看到時間欄:
<android.support.design.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">
我發現擺弄 style.xml 和活動太麻煩,因此創建了一個通用實用程序方法,它具有以下選項集
爪哇
Window window = getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
window.setStatusBarColor(Color.TRANSPARENT);
科特林 DSL
activity.window.apply {
clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
statusBarColor = Color.TRANSPARENT
}
這就是實現透明狀態欄所需的全部內容。 希望這可以幫助。
<style name="Theme.Transparent" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
</style>
試試下面的代碼:
private static void setStatusBarTransparent(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
activity.getWindow(). setStatusBarColor(Color.TRANSPARENT);
} else {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
}
這對我有用:
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowTranslucentStatus">false</item>
<item name="android:windowTranslucentNavigation">false</item>
您還可以使用動畫頭像和動畫文本查看我的示例
閱讀我在Medium上的帖子
因此,讓我解釋一下它是如何工作的。 我創建了實現AppBarLayout.OnOffsetChangedListener的自定義視圖。 在HeadCollapsing自定義視圖內部,我在AppBarLayout中創建了文本和圖像視圖。
class HeadCollapsing(context: Context, attrs: AttributeSet?) :
FrameLayout(context, attrs), AppBarLayout.OnOffsetChangedListener {
private fun findViews() {
appBarLayout = findParentAppBarLayout()
avatarContainerView = findViewById(R.id.imgb_avatar_wrap)
titleToolbarText = findViewById<AppCompatTextView>(id)
}
private fun findParentAppBarLayout(): AppBarLayout {
val parent = this.parent
return parent as? AppBarLayout ?: if (parent.parent is AppBarLayout) {
parent.parent as AppBarLayout
} else {
throw IllegalStateException("Must be inside an AppBarLayout")
}
}
...
override fun onOffsetChanged(appBarLayout: AppBarLayout, offset:Int) {
...
//Calculate expanded percentage
val expandedPercentage = 1 - -offset / maxOffset
updateViews(expandedPercentage)
}
}
然后通過計算的百分比更改視圖。 例如,文本視圖如何更改:
when {
inversePercentage < ABROAD -> {
titleToolbarText?.visibility = View.VISIBLE
titleTolbarTextSingle?.visibility = View.INVISIBLE
}
inversePercentage > ABROAD -> {
titleToolbarText?.visibility = View.INVISIBLE
titleTolbarTextSingle?.visibility = View.VISIBLE
titleTolbarTextSingle?.let {
animateShowText(it)
}
}
}
檢測何時需要圖像折疊為創建的Pair對象制作動畫
private var cashCollapseState: kotlin.Pair<Int, Int>? = null
狀態:TO_EXPANDED_STATE,TO_COLLAPSED_STATE,WAIT_FOR_SWITCH,SWITCHED
companion object {
const val ABROAD = 0.95f
const val TO_EXPANDED_STATE = 0
const val TO_COLLAPSED_STATE = 1
const val WAIT_FOR_SWITCH = 0
const val SWITCHED = 1
}
然后為頭像切換狀態的漸變動畫:
when {
cashCollapseState != null && cashCollapseState != state -> {
when (state.first) {
TO_EXPANDED_STATE -> {
// do calculates
}
TO_COLLAPSED_STATE -> {
ValueAnimator.ofFloat(avatarContainerView.translationX, translationX).apply {
addUpdateListener {
avatarContainerView.translationX = it.animatedValue as Float
}
duration = 350
(state.first == TO_COLLAPSED_STATE).apply {
if (this) interpolator = LinearInterpolator()
}
start()
}
//SWITCH STATE CASE
cashCollapseState = kotlin.Pair(state.first, SWITCHED)
}
else -> {
cashCollapseState = kotlin.Pair(state.first, WAIT_FOR_SWITCH)
}
只需進入MainActivity.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Window g = getWindow();
g.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
setContentView(R.layout.activity_main);
}
在我的情況下,我根本不調用“onCreate”(它是一個反應原生應用程序,這也可以通過使用 react-native StatusBar 組件來修復),也可以使用這個:
override fun onStart() {
super.onStart()
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
window.statusBarColor = Color.TRANSPARENT
}
雖然上面的所有答案都圍繞着相同的基本思想,但您可以使用上面的示例之一讓它與簡單的布局一起工作。 但是,我想在使用滑動“全屏”(標簽欄旁邊)片段導航時更改背景顏色,並保持常規導航、標簽和操作欄。
在仔細閱讀了 Anton Hadutski 的一篇文章后,我更好地理解了發生了什么。
我有DrawerLayout
和ConstraintLayout
(即容器),它有Toolbar
,包括主要片段和BottomNavigationView
。
將具有DrawerLayout
的fitsSystemWindows
設置為 true 是不夠的,您需要同時設置DrawerLayout
和ConstraintLayout
。 假設透明狀態欄,狀態欄顏色現在與ConstraintLayout
的背景顏色相同。
但是,包含的片段仍然具有狀態欄插圖,因此在 with 頂部設置另一個“全屏”片段的動畫不會改變狀態欄的顏色。
參考文章中的一些代碼進入Activity
的onCreate
:
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.container)) { view, insets ->
insets.replaceSystemWindowInsets(
insets.systemWindowInsetLeft,
0,
insets.systemWindowInsetRight,
insets.systemWindowInsetBottom
)
}
一切都很好,除了現在Toolbar
沒有解決狀態欄的高度。 更多參考文章,我們有一個完整的解決方案:
val toolbar = findViewById<Toolbar>(R.id.my_toolbar)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.container)) { view, insets ->
val params = toolbar.layoutParams as ViewGroup.MarginLayoutParams
params.topMargin = insets.systemWindowInsetTop
toolbar.layoutParams = params
insets.replaceSystemWindowInsets(
insets.systemWindowInsetLeft,
0,
insets.systemWindowInsetRight,
insets.systemWindowInsetBottom
)
}
main_activity.xml(請注意Toolbar
中的marginTop是用來預覽的,會被代碼代替):
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
>
<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/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/green"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<androidx.appcompat.widget.Toolbar
android:id="@+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_constraintTop_toTopOf="@id/container"
android:layout_marginTop="26dp"
android:background="@android:color/transparent"
...>
...
</androidx.appcompat.widget.Toolbar>
<include layout="@layout/content_main" />
...
</androidx.constraintlayout.widget.ConstraintLayout>
...
</androidx.drawerlayout.widget.DrawerLayout>
這是 Kotlin 擴展:
fun Activity.transparentStatusBar() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
window.statusBarColor = Color.TRANSPARENT
} else
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
}
android:fitsSystemWindows="true"
僅適用於 v21。 我們可以在主題 xml 或父布局(如LinearLayout
或CoordinateLayout
)中設置它。 對於 v21 以下,我們無法添加此標志。 請根據您的需要使用不同的style.xml
文件創建不同的值文件夾。
<item name="android:statusBarColor" tools:targetApi="lollipop">@android:color/transparent</item>
<!--<item name="android:windowLightStatusBar" tools:targetApi="m">true</item>-->
不要使用windowLightStatusBar
而是使用statusBarColor = @android:color/transparent
在 setContentView() 之前將這些行添加到您的活動中
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Window w = getWindow();
w.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
}
將這兩行添加到您的 AppTheme
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
最后一件事你的 minSdkVersion 必須 b 19
minSdkVersion 19
就我而言,因為我有一個底部工具欄,所以在測試以前的解決方案時遇到了問題,android 系統按鈕被我的底部菜單覆蓋,我的解決方案是在活動中添加:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
// force full screen mode requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.main_activity_container);
您可以使用下面的代碼。
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
getWindow().setStatusBarColor(Color.TRANSPARENT);
將此布局包含在您的主布局中。
工具欄.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/toolbarNav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
app:contentInsetEnd="0dp"
app:contentInsetLeft="0dp"
app:contentInsetRight="0dp"
app:contentInsetStart="0dp">
<RelativeLayout
android:id="@+id/rlBackImageLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/main_background2"> //add your color here
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/_40sdp"
android:layout_marginTop="@dimen/_16sdp"
android:orientation="horizontal">
<ImageView
android:id="@+id/toolbarIcon"
android:layout_width="@dimen/_30sdp"
android:layout_height="@dimen/_30sdp"
android:layout_gravity="center"
android:layout_marginStart="@dimen/_10sdp"
android:padding="@dimen/_5sdp"
android:src="@drawable/nav_icon" />
<TextView
android:id="@+id/txtTitle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_marginEnd="@dimen/_30sdp"
android:fontFamily="@font/muli_semibold"
android:gravity="center"
android:textColor="#fff"
android:textSize="@dimen/_14ssp"
android:textStyle="bold"
tools:text="test Data" />
</LinearLayout>
</RelativeLayout>
</androidx.appcompat.widget.Toolbar>
注意:您可以將 SDP 和 SSP 分別替換為 dp 和 sp。
這應該工作
// 例如在 Activity 的 onCreate() 中
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Window w = getWindow();
w.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
}
以下代碼將使您的狀態欄和導航欄透明(請注意,這將使您的布局成為全屏布局,就像游戲中使用的布局一樣):
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
hideSystemUI();
}
}
private void hideSystemUI() {
// Enables sticky immersive mode.
// For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE_STICKY.
// Or for regular immersive mode replace it with SYSTEM_UI_FLAG_IMMERSIVE
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
// Set the content to appear under the system bars so that the
// content doesn't resize when the system bars hide and show.
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
// Hide the nav bar and status bar
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN);
}
要了解更多信息,請訪問此鏈接。
以下代碼將創建一個完全透明的狀態欄:
package com.demo;
import android.app.Activity;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 21) {
setWindowFlag(this, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, true);
}
if (Build.VERSION.SDK_INT >= 19) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
if (Build.VERSION.SDK_INT >= 21) {
setWindowFlag(this, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, false);
getWindow().setStatusBarColor(Color.TRANSPARENT);
}
}
public static void setWindowFlag(Activity activity, final int bits, boolean on) {
Window win = activity.getWindow();
WindowManager.LayoutParams winParams = win.getAttributes();
if (on) {
winParams.flags |= bits;
} else {
winParams.flags &= ~bits;
}
win.setAttributes(winParams);
}
}
此解決方案適用於希望擁有完全透明的StatusBar並且NavigationBar不受影響的用戶。 令人難以置信的是,這聽起來如此簡單,以至於讓包括我在內的不止一個人感到頭疼。
這就是我說的最終結果
我們將只需要兩個函數,我建議在我們的 Activity 的 OnCreate 中調用它們,第一個是setStatusBar() ,它負責使同一個函數變得透明。
private fun setStatusBar() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.apply {
clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
decorView.systemUiVisibility =
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
} else {
decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
}
statusBarColor = Color.TRANSPARENT
}
}
第二個, setMargins()負責設置與頂部限制的視圖相對應的邊距,否則,這些視圖將在狀態欄下方看到。
private fun setMargins() {
ViewCompat.setOnApplyWindowInsetsListener(
findViewById(R.id.your_parent_view)
) { _, insets ->
val view = findViewById<FrameLayout>(R.id.your_child_view)
val params = view.layoutParams as ViewGroup.MarginLayoutParams
params.setMargins(
0,
insets.systemWindowInsetTop,
0,
0
)
view.layoutParams = params
insets.consumeSystemWindowInsets()
}
}
最終代碼如下所示:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.your_layout))
setStatusBar()
setMargins()
}
private fun setStatusBar() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.apply {
clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
decorView.systemUiVisibility =
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
} else {
decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
}
statusBarColor = Color.TRANSPARENT
}
}
private fun setMargins() {
ViewCompat.setOnApplyWindowInsetsListener(
findViewById(R.id.your_parent_view)
) { _, insets ->
val view = findViewById<FrameLayout>(R.id.your_child_view)
val params = view.layoutParams as ViewGroup.MarginLayoutParams
params.setMargins(
0,
insets.systemWindowInsetTop,
0,
0
)
view.layoutParams = params
insets.consumeSystemWindowInsets()
}
}
您可以在以下帖子中找到所有這一切的更詳細解釋
我還留下了一個測試項目,這些概念正在發揮作用。
如果您使用的是 React Native,則其他帖子不起作用。 React 有自己的處理方式。
來自react-native
的<StatusBar translucent backgroundColor="transparent" />
是要走的路,感謝這篇文章,這將覆蓋 App 中的 android 設置。
但是,有兩件事要知道:
2022 年最優雅的解決方案:
private fun hideStatusBar() {
val windowInsetsController = ViewCompat.getWindowInsetsController(window.decorView) ?: return
windowInsetsController.hide(WindowInsetsCompat.Type.statusBars())
}
實現狀態欄完全透明:首先在themes.xml中自定義主題為
<style name="QuiloThemeLight" parent="Theme.AppCompat.Light.NoActionBar">
Java:
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
getWindow().setStatusBarColor(Color.TRANSPARENT);
Kotlin:
activity.window.apply {
clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
statusBarColor = Color.TRANSPARENT
}
對於谷歌的最后更新。 這是我的代碼。 這將對狀態欄和導航欄透明:將您的主題更改為:
<style name="Theme.Pink"
parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/pink_primary</item>
<item name="colorPrimaryVariant">@color/pink_dark</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/pink_light</item>
<item name="colorSecondaryVariant">@color/pink_primary</item>
<item name="colorOnSecondary">@color/black</item>
<item name="android:textColor">?attr/colorOnPrimary</item>
<!-- Status bar color. -->
<!-- Customize your theme here. -->
//transparent statusbar
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowIsTranslucent">true</item>
//transparent navigationbar
<item name="android:windowTranslucentNavigation">true</item>
</style>
然后在layout(文件xml)中:添加2個屬性point_top和point_bottom來確定app其他組件的margin值的position:
<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"
android:background="@drawable/bg_activity">
<TextView
android:id="@+id/point_top"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/point_bottom"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<.....>
</androidx.constraintlayout.widget.ConstraintLayout>
然后在 baseActivity 或 yourActivity: 在 onCreate 中添加此代碼:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = setLayout()
//set inset for view
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, insets ->
val paramsTop =
findViewById<TextView>(R.id.point_top).layoutParams as MarginLayoutParams
paramsTop.setMargins(0, insets.getInsets(WindowInsetsCompat.Type.systemBars()).top, 0, 0)
findViewById<TextView>(R.id.point_top).layoutParams = paramsTop
val paramsBottom =
findViewById<TextView>(R.id.point_bottom).layoutParams as MarginLayoutParams
paramsBottom.setMargins(0, 0, 0, insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom)
findViewById<TextView>(R.id.point_bottom).layoutParams = paramsBottom
insets.consumeSystemWindowInsets()
}
setContentView(binding.root)
}
希望這對大家有所幫助。
這僅適用於 API 級別 >= 21。它適用於我。 這是我的代碼(Kotlin)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<View>(android.R.id.content).systemUiVisibility =
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
}
我在調查這個庫時找到了答案: https ://github.com/laobie/StatusBarUtil
所以你需要在你的活動中添加以下代碼
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
window.statusBarColor = Color.TRANSPARENT
} else {
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.