(contentLayoutId) {
11 | override fun initView() {
12 | }
13 |
14 | override fun initData() {
15 | }
16 |
17 | override fun onCreateOptionsMenu(menu: Menu?): Boolean {
18 | menuInflater.inflate(R.menu.menu_main, menu)
19 | return super.onCreateOptionsMenu(menu)
20 | }
21 |
22 | override fun onOptionsItemSelected(item: MenuItem): Boolean {
23 | when (item.itemId) {
24 | R.id.immersiveDrawerActivity -> startActivity(
25 | Intent(
26 | this,
27 | ImmersiveDrawerActivity::class.java
28 | )
29 | )
30 |
31 | R.id.immersiveImageActivity -> startActivity(
32 | Intent(
33 | this,
34 | ImmersiveImageActivity::class.java
35 | )
36 | )
37 |
38 | R.id.darkStatusBarActivity -> startActivity(
39 | Intent(
40 | this,
41 | DarkStatusBarActivity::class.java
42 | )
43 | )
44 |
45 | R.id.mainActivity -> startActivity(Intent(this, MainActivity::class.java))
46 | }
47 | finish()
48 | return super.onOptionsItemSelected(item)
49 | }
50 | }
--------------------------------------------------------------------------------
/docs/css/extra.css:
--------------------------------------------------------------------------------
1 | @font-face{
2 | font-family: 'Iosevka Curly';
3 | src: local('Iosevka Curly Medium'),
4 | url('https://raw.githubusercontent.com/liangjingkanji/liangjingkanji/master/font/iosevka-curly/iosevka-curly-medium.woff2') format('woff2');
5 | font-display: swap;
6 | font-weight: normal;
7 | font-style: normal;
8 | }
9 | @font-face{
10 | font-family: 'Iosevka Curly';
11 | src: local('Iosevka Curly Bold'),
12 | url('https://raw.githubusercontent.com/liangjingkanji/liangjingkanji/master/font/iosevka-curly/iosevka-curly-bold.woff2') format('woff2');
13 | font-display: swap;
14 | font-weight: bold;
15 | font-style: normal;
16 | }
17 | @font-face{
18 | font-family: 'HYYouYuan';
19 | src: local('HYYouYuan-55W'),
20 | url('https://raw.githubusercontent.com/liangjingkanji/liangjingkanji/master/font/HYYouYuan/HYYouYuan-55W.ttf') format('truetype');
21 | font-display: swap;
22 | font-weight: normal;
23 | font-style: normal;
24 | }
25 | @font-face{
26 | font-family: 'HYYouYuan';
27 | src: local('HYYouYuan-75W'),
28 | url('https://raw.githubusercontent.com/liangjingkanji/liangjingkanji/master/font/HYYouYuan/HYYouYuan-75W.ttf') format('truetype');
29 | font-display: swap;
30 | font-weight: bold;
31 | font-style: normal;
32 | }
33 |
34 | * {
35 | -webkit-font-feature-settings: "liga" on, "calt" on;
36 | -webkit-font-smoothing: subpixel-antialiased;
37 | -moz-osx-font-smoothing: auto;
38 | text-rendering: optimizeLegibility;
39 | font-family: "Iosevka Curly", HYYouYuan !important;
40 | }
41 |
42 | code,
43 | .md-nav,
44 | .md-typeset code,
45 | .md-typeset {
46 | font-size: 14px !important;
47 | }
48 |
49 | .highlight span.filename,
50 | .md-typeset .admonition-title,
51 | .md-typeset summary {
52 | font-weight: normal;
53 | }
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-kapt'
3 | apply plugin: 'kotlin-android'
4 |
5 | android {
6 | compileSdkVersion 33
7 |
8 | signingConfigs {
9 | signed {
10 | storeFile file("../signed")
11 | storePassword "s73dfyUxkjuq"
12 | keyAlias "key0"
13 | keyPassword "s73dfyUxkjuq"
14 | }
15 | }
16 | defaultConfig {
17 | applicationId "com.drake.statusbar.sample"
18 | minSdkVersion 19
19 | targetSdkVersion 33
20 | versionCode 1
21 | versionName "1.0"
22 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
23 | signingConfig signingConfigs.signed
24 | }
25 |
26 | buildFeatures.dataBinding = true
27 |
28 | buildTypes {
29 | release {
30 | minifyEnabled false
31 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
32 | }
33 | }
34 | compileOptions {
35 | targetCompatibility JavaVersion.VERSION_11
36 | sourceCompatibility JavaVersion.VERSION_11
37 | }
38 |
39 | applicationVariants.all {
40 | it.outputs.each { output ->
41 | output.outputFileName = "StatusBar.apk"
42 | }
43 | }
44 | }
45 |
46 | dependencies {
47 | implementation fileTree(dir: 'libs', include: ['*.jar'])
48 | implementation 'androidx.appcompat:appcompat:1.6.1'
49 | implementation 'androidx.core:core-ktx:1.10.1'
50 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
51 | implementation 'com.google.android.material:material:1.9.0'
52 | implementation project(path: ':statusbar')
53 |
54 | implementation 'com.github.liangjingkanji:Engine:0.0.74'
55 | implementation 'com.github.liangjingkanji:debugkit:1.3.0'
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
13 |
14 |
20 |
23 |
26 |
27 |
28 |
29 |
35 |
36 |
--------------------------------------------------------------------------------
/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: StatusBar
2 | site_description: StatusBar document
3 | repo_url: https://github.com/liangjingkanji/StatusBar
4 | extra:
5 | social:
6 | - icon: fontawesome/brands/github
7 | link: https://github.com/liangjingkanji
8 | - icon: fontawesome/brands/qq
9 | link: https://raw.githubusercontent.com/liangjingkanji/liangjingkanji/master/img/group-qrcode.png
10 |
11 | site_author: 劉強東
12 | copyright: Copyright © 2018 - 2023 劉強東
13 | repo_name: GitHub
14 | docs_dir: 'docs'
15 | extra_css:
16 | - css/extra.css
17 | theme:
18 | name: material
19 | custom_dir: docs/material
20 | favicon: img/book-open.svg
21 | logo: img/book-open.svg
22 | palette:
23 | - media: "(prefers-color-scheme: light)"
24 | scheme: default
25 | primary: white
26 | font: false
27 | language: zh
28 | features:
29 | - navigation.top
30 | - navigation.prune
31 | - navigation.footer
32 | - navigation.instant
33 | - search.highlight
34 | - search.suggest
35 | - search.share
36 | - content.code.copy
37 | - content.code.annotate
38 | plugins:
39 | - offline
40 | - search:
41 | separator: '[\s\-,:!=\[\]()"/]+|(?!\b)(?=[A-Z][a-z])|\.(?!\d)|&[lg]t;'
42 | lang:
43 | - en
44 | - zh
45 | markdown_extensions:
46 | - toc:
47 | permalink: true
48 | - pymdownx.tasklist:
49 | custom_checkbox: true
50 | - pymdownx.tabbed:
51 | alternate_style: true
52 | - pymdownx.highlight:
53 | anchor_linenums: true
54 | line_spans: __span
55 | pygments_lang_class: true
56 | - pymdownx.inlinehilite
57 | - pymdownx.snippets
58 | - pymdownx.superfences
59 | - attr_list
60 | - def_list
61 | - md_in_html
62 | - admonition
63 | - pymdownx.highlight
64 | - pymdownx.details
65 | - pymdownx.caret
66 | - pymdownx.keys
67 | - pymdownx.mark
68 | - pymdownx.tilde
69 | - pymdownx.emoji:
70 | emoji_index: !!python/name:materialx.emoji.twemoji
71 | emoji_generator: !!python/name:materialx.emoji.to_svg
72 |
73 | nav:
74 | - 通用透明状态栏: 'index.md'
75 | - 图片透明状态栏: 'image.md'
76 | - 状态栏字体颜色: 'font.md'
77 | - 其他: 'other.md'
--------------------------------------------------------------------------------
/docs/material/partials/footer.html:
--------------------------------------------------------------------------------
1 | {% import "partials/language.html" as lang with context %}
2 |
3 |
4 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## StatusBar
2 |
3 | 
4 |
5 | 一行代码的透明状态栏
6 |
7 |
8 | 使用文档
9 | | 无法访问?
10 | | 下载体验
11 |
12 |
13 | 
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | ### 特点
23 |
24 | - [x] 学习成本低
25 | - [x] 启用/关闭透明状态栏
26 | - [x] 状态栏背景/文字颜色
27 | - [x] 状态栏/导航栏高度
28 | - [x] 为View设置指定状态栏高度的Padding/Margin
29 | - [x] 支持Activity/Fragment/DrawerLayout
30 |
31 |
32 |
33 |
34 | ## 安装
35 |
36 | Project 的 settings.gradle 添加仓库
37 |
38 | ```kotlin
39 | dependencyResolutionManagement {
40 | repositories {
41 | // ...
42 | maven { url 'https://jitpack.io' }
43 | }
44 | }
45 | ```
46 |
47 | Module 的 build.gradle 添加依赖框架
48 |
49 | ```groovy
50 | implementation 'com.github.liangjingkanji:StatusBar:2.0.5'
51 | ```
52 |
53 |
54 |
55 | ## License
56 |
57 | ```
58 | MIT License
59 |
60 | Copyright (c) 2023 劉強東 https://github.com/liangjingkanji
61 |
62 | Permission is hereby granted, free of charge, to any person obtaining a copy
63 | of this software and associated documentation files (the "Software"), to deal
64 | in the Software without restriction, including without limitation the rights
65 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
66 | copies of the Software, and to permit persons to whom the Software is
67 | furnished to do so, subject to the following conditions:
68 |
69 | The above copyright notice and this permission notice shall be included in all
70 | copies or substantial portions of the Software.
71 |
72 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
73 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
74 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
75 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
76 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
77 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
78 | SOFTWARE.
79 | ```
80 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/statusbar/src/main/java/com/drake/statusbar/StatusBar.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2023 劉強東 https://github.com/liangjingkanji
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.drake.statusbar
26 |
27 | import android.annotation.SuppressLint
28 | import android.app.Activity
29 | import android.content.Context
30 | import android.content.res.Resources
31 | import android.graphics.Color
32 | import android.graphics.drawable.ColorDrawable
33 | import android.os.Build
34 | import android.util.TypedValue
35 | import android.view.View
36 | import android.view.ViewGroup
37 | import android.view.WindowManager
38 | import android.widget.RelativeLayout
39 | import androidx.annotation.ColorInt
40 | import androidx.annotation.ColorRes
41 | import androidx.appcompat.app.AppCompatActivity
42 |
43 | private const val COLOR_TRANSPARENT = 0
44 |
45 | //
46 | /** 设置状态栏颜色 */
47 | fun Activity.statusBarColor(@ColorInt color: Int) {
48 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
49 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
50 | window?.statusBarColor = color
51 | }
52 | }
53 |
54 | /** 设置状态栏颜色 */
55 | fun Activity.statusBarColorRes(@ColorRes colorRes: Int) = statusBarColor(resources.getColor(colorRes))
56 |
57 | //
58 |
59 |
60 | //
61 | /**
62 | * 使用视图的背景色作为状态栏颜色
63 | * @param v 提取该View的背景颜色设置为状态栏颜色, 如果该View没有背景颜色则该函数调用无效
64 | * @param darkMode 是否显示暗色状态栏文字颜色
65 | */
66 | @JvmOverloads
67 | fun Activity.immersive(v: View, darkMode: Boolean? = null) {
68 | val background = v.background
69 | if (background is ColorDrawable) {
70 | immersive(background.color, darkMode)
71 | }
72 | }
73 |
74 | /**
75 | * 设置透明状态栏或者状态栏颜色, 此函数会导致状态栏覆盖界面,
76 | * 如果不希望被状态栏遮挡Toolbar请再调用[statusPadding]设置视图的paddingTop 或者 [statusMargin]设置视图的marginTop为状态栏高度
77 | *
78 | * 如果不指定状态栏颜色则会应用透明状态栏(全屏属性), 会导致键盘遮挡输入框
79 | *
80 | * @param color 状态栏颜色, 不指定则为透明状态栏
81 | * @param darkMode 是否显示暗色状态栏文字颜色
82 | */
83 | @SuppressLint("ObsoleteSdkInt")
84 | @JvmOverloads
85 | fun Activity.immersive(@ColorInt color: Int = COLOR_TRANSPARENT, darkMode: Boolean? = null) {
86 | when {
87 | Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> {
88 | when (color) {
89 | COLOR_TRANSPARENT -> {
90 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
91 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
92 | window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
93 | window.statusBarColor = color
94 | }
95 | else -> {
96 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
97 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
98 | window.statusBarColor = color
99 | }
100 | }
101 | }
102 | Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT -> {
103 | window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
104 | if (color != COLOR_TRANSPARENT) {
105 | setTranslucentView(window.decorView as ViewGroup, color)
106 | }
107 | }
108 | }
109 | if (darkMode != null) {
110 | darkMode(darkMode)
111 | }
112 | }
113 |
114 | /**
115 | * 退出沉浸式状态栏并恢复默认状态栏颜色
116 | *
117 | * @param black 是否显示黑色状态栏白色文字(不恢复状态栏颜色)
118 | */
119 | @JvmOverloads
120 | fun Activity.immersiveExit(black: Boolean = false) {
121 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
122 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
123 | window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
124 | and View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
125 |
126 | // 恢复默认状态栏颜色
127 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
128 | if (black) {
129 | window.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
130 | } else {
131 | val typedArray = obtainStyledAttributes(intArrayOf(android.R.attr.statusBarColor))
132 | window.statusBarColor = typedArray.getColor(0, 0)
133 | typedArray.recycle()
134 | }
135 | }
136 | }
137 | }
138 |
139 | /**
140 | * 获取颜色资源值来设置状态栏
141 | */
142 | @JvmOverloads
143 | fun Activity.immersiveRes(@ColorRes color: Int, darkMode: Boolean? = null) =
144 | immersive(resources.getColor(color), darkMode)
145 |
146 | //
147 |
148 |
149 | //
150 |
151 |
152 | /**
153 | * 开关状态栏暗色模式, 并不会透明状态栏, 只是单纯的状态栏文字变暗色调.
154 | *
155 | * @param darkMode 状态栏文字是否为暗色
156 | */
157 | @JvmOverloads
158 | fun Activity.darkMode(darkMode: Boolean = true) {
159 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
160 | var systemUiVisibility = window.decorView.systemUiVisibility
161 | systemUiVisibility = if (darkMode) {
162 | systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
163 | } else {
164 | systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
165 | }
166 | window.decorView.systemUiVisibility = systemUiVisibility
167 | }
168 | }
169 |
170 | //
171 |
172 | //
173 |
174 | /**
175 | * 增加View的paddingTop, 增加高度为状态栏高度, 用于防止视图和状态栏重叠
176 | * 如果是RelativeLayout设置padding值会导致centerInParent等属性无法正常显示
177 | * @param remove 如果默认paddingTop大于状态栏高度则添加无效, 如果小于状态栏高度则无法删除
178 | */
179 | @JvmOverloads
180 | fun View.statusPadding(remove: Boolean = false) {
181 | if (this is RelativeLayout) {
182 | throw UnsupportedOperationException("Unsupported set statusPadding for RelativeLayout")
183 | }
184 | if (Build.VERSION.SDK_INT >= 19) {
185 | val statusBarHeight = context.statusBarHeight
186 | val lp = layoutParams
187 | if (lp != null && lp.height > 0) {
188 | lp.height += statusBarHeight //增高
189 | }
190 | if (remove) {
191 | if (paddingTop < statusBarHeight) return
192 | setPadding(
193 | paddingLeft, paddingTop - statusBarHeight,
194 | paddingRight, paddingBottom
195 | )
196 | } else {
197 | if (paddingTop >= statusBarHeight) return
198 | setPadding(
199 | paddingLeft, paddingTop + statusBarHeight,
200 | paddingRight, paddingBottom
201 | )
202 | }
203 | }
204 | }
205 |
206 | /**
207 | * 增加View的marginTop值, 增加高度为状态栏高度, 用于防止视图和状态栏重叠
208 | * @param remove 如果默认marginTop大于状态栏高度则添加无效, 如果小于状态栏高度则无法删除
209 | */
210 | @JvmOverloads
211 | fun View.statusMargin(remove: Boolean = false) {
212 | if (Build.VERSION.SDK_INT >= 19) {
213 | val statusBarHeight = context.statusBarHeight
214 | val lp = layoutParams as ViewGroup.MarginLayoutParams
215 | if (remove) {
216 | if (lp.topMargin < statusBarHeight) return
217 | lp.topMargin -= statusBarHeight
218 | layoutParams = lp
219 | } else {
220 | if (lp.topMargin >= statusBarHeight) return
221 | lp.topMargin += statusBarHeight
222 | layoutParams = lp
223 | }
224 | }
225 | }
226 |
227 |
228 | /**
229 | * 创建假的透明栏
230 | */
231 | private fun Context.setTranslucentView(container: ViewGroup, color: Int) {
232 | if (Build.VERSION.SDK_INT >= 19) {
233 | var simulateStatusBar: View? = container.findViewById(android.R.id.custom)
234 | if (simulateStatusBar == null && color != 0) {
235 | simulateStatusBar = View(container.context)
236 | simulateStatusBar.id = android.R.id.custom
237 | val lp = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight)
238 | container.addView(simulateStatusBar, lp)
239 | }
240 | simulateStatusBar?.setBackgroundColor(color)
241 | }
242 | }
243 |
244 | //
245 |
246 | //
247 |
248 | /**
249 | * 设置ActionBar的背景颜色
250 | */
251 | fun AppCompatActivity.setActionBarBackground(@ColorInt color: Int) {
252 | supportActionBar?.setBackgroundDrawable(ColorDrawable(color))
253 | }
254 |
255 | fun AppCompatActivity.setActionBarBackgroundRes(@ColorRes color: Int) {
256 | supportActionBar?.setBackgroundDrawable(ColorDrawable(resources.getColor(color)))
257 | }
258 |
259 | /**
260 | * 设置ActionBar的背景颜色为透明
261 | */
262 | fun AppCompatActivity.setActionBarTransparent() {
263 | supportActionBar?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
264 | }
265 | //
266 |
267 | //
268 |
269 | /**
270 | * 显示或隐藏导航栏, 系统开启可以隐藏, 系统未开启不能开启
271 | *
272 | * @param enabled 是否显示导航栏
273 | */
274 | @JvmOverloads
275 | fun Activity.setNavigationBar(enabled: Boolean = true) {
276 | if (Build.VERSION.SDK_INT in 12..18) {
277 | if (enabled) {
278 | window.decorView.systemUiVisibility = View.VISIBLE
279 | } else {
280 | window.decorView.systemUiVisibility = View.GONE
281 | }
282 | } else if (Build.VERSION.SDK_INT >= 19) {
283 | val systemUiVisibility = window.decorView.systemUiVisibility
284 | if (enabled) {
285 | window.decorView.systemUiVisibility =
286 | systemUiVisibility and View.SYSTEM_UI_FLAG_HIDE_NAVIGATION and View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
287 | } else {
288 | window.decorView.systemUiVisibility = systemUiVisibility or
289 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
290 | }
291 | }
292 | }
293 |
294 | /**
295 | * 设置是否全屏
296 | *
297 | * @param enabled 是否全屏显示
298 | */
299 | @JvmOverloads
300 | fun Activity.setFullscreen(enabled: Boolean = true) {
301 | val systemUiVisibility = window.decorView.systemUiVisibility
302 | window.decorView.systemUiVisibility = if (enabled) {
303 | systemUiVisibility or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
304 | } else {
305 | systemUiVisibility or View.SYSTEM_UI_FLAG_LAYOUT_STABLE and View.SYSTEM_UI_FLAG_FULLSCREEN.inv()
306 | }
307 | }
308 |
309 | /**
310 | * 是否有导航栏
311 | */
312 | val Activity?.isNavigationBar: Boolean
313 | get() {
314 | this ?: return false
315 | val vp = window.decorView as? ViewGroup
316 | if (vp != null) {
317 | for (i in 0 until vp.childCount) {
318 | vp.getChildAt(i).context.packageName
319 | if (vp.getChildAt(i).id != -1 && "navigationBarBackground" ==
320 | resources.getResourceEntryName(vp.getChildAt(i).id)
321 | ) return true
322 | }
323 | }
324 | return false
325 | }
326 |
327 | /**
328 | * 如果当前设备存在导航栏返回导航栏高度, 否则0
329 | */
330 | val Context?.navigationBarHeight: Int
331 | get() {
332 | this ?: return 0
333 | val resourceId: Int = resources.getIdentifier("navigation_bar_height", "dimen", "android")
334 | var height = 0
335 | if (resourceId > 0) {
336 | height = resources.getDimensionPixelSize(resourceId)
337 | }
338 | return height
339 | }
340 |
341 |
342 | /**
343 | * 状态栏高度
344 | */
345 | val Context?.statusBarHeight: Int
346 | get() {
347 | this ?: return 0
348 | var result = 24
349 | val resId = resources.getIdentifier("status_bar_height", "dimen", "android")
350 | result = if (resId > 0) {
351 | resources.getDimensionPixelSize(resId)
352 | } else {
353 | TypedValue.applyDimension(
354 | TypedValue.COMPLEX_UNIT_DIP,
355 | result.toFloat(), Resources.getSystem().displayMetrics
356 | ).toInt()
357 | }
358 | return result
359 | }
360 | //
361 |
--------------------------------------------------------------------------------