前言

我们知道,在纯flutter 的项目中,设置透明状态栏只需要在flutter 的入口处添加下面这段代码就可以,

if (Platform.isAndroid) {//设置Android头部的导航栏透明SystemUiOverlayStyle systemUiOverlayStyle = SystemUiOverlayStyle(statusBarColor: Colors.transparent, //全局设置透明statusBarIconBrightness: Brightness.light//light:黑色图标 dark:白色图标//在此处设置statusBarIconBrightness为全局设置);SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);}

对于电量、信号等设置,只需要全局设置 statusBarIconBrightness 就可以.

单页面设置:

appBar: AppBar(
title: new Text(''),
elevation: 0,
brightness: Brightness.dark, //设置为白色字体
),

问题?

那么对于混合开发的项目呢?实测发现,对于Android混合开发的项目,我们打开一个flutter 自带的FlutterActivity ,可以发现,第一次进入页面状态栏很正常,但是第二次打开的时候,状态栏变全白了。单个页面的设置也不生效了,这是怎么回事呢?

源码分析

1、太长不看版

1、继承 FlutterActivity

2、覆写 onPostResume

3、在 onPostResume 中重新设置状态栏

/*** @description: flutter 页面容器*/
public class FlutterContainerActivity extends FlutterActivity {@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 设置透明状态栏StatusBarHelper.translucent(this);}@Overridepublic void onPostResume() {super.onPostResume();// 重新设置 状态栏 图标 modeStatusBarHelper.setStatusBarDarkMode(this);}
}

2、源码原理版

档FlutterActivity 创建 onCreate 的时候,

@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {switchLaunchThemeForNormalTheme();super.onCreate(savedInstanceState);lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);delegate = new FlutterActivityAndFragmentDelegate(this);delegate.onAttach(this);delegate.onActivityCreated(savedInstanceState);configureWindowForTransparency();setContentView(createFlutterView());configureStatusBarForFullscreenFlutterExperience();}

会实例化创建 FlutterActivityAndFragmentDelegate 代理类,用来绑定host , 绑定FlutterEngine .

当FlutterActivity 走完 onResume 后,会进入 onPostResume 这个方法,

@Overrideprotected void onResume() {super.onResume();lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);delegate.onResume();}@Overridepublic void onPostResume() {super.onPostResume();delegate.onPostResume();}

这个方法很简单,主要的逻辑都是通过 delegate 实现,我们进去看下,

 void onPostResume() {Log.v(TAG, "onPostResume()");ensureAlive();if (flutterEngine != null) {if (platformPlugin != null) {// TODO(mattcarroll): find a better way to handle the update of UI overlays than calling// through//                    to platformPlugin. We're implicitly entangling the Window, Activity,// Fragment,//                    and engine all with this one call.platformPlugin.updateSystemUiOverlays();}} else {Log.w(TAG, "onPostResume() invoked before FlutterFragment was attached to an Activity.");}}

在这里,主要是判断 flutterEngine 是否存在,不存在输出log,存在的话,通过调用 platformPlugin.updateSystemUiOverlays() 来更新状态栏。而 platformPlugin 则是在FlutterActivity onCreate 的时候,通过

platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine);

获取的。

我们进入 platformPlugin 来看看具体如何实现的。

在 PlatformPlugin 中,

public void updateSystemUiOverlays() {activity.getWindow().getDecorView().setSystemUiVisibility(mEnabledOverlays);if (currentTheme != null) {setSystemChromeSystemUIOverlayStyle(currentTheme);}}

主要是通过全局变量 currentTheme 来设置的。那这个全局变量 currentTheme 如何赋值的呢?

通过 debug 发现,在我们第一次打开FlutterActivity 的时候,我们在dart 层设置的透明状态栏以及图标,dart 通过 PlatformChannel 的方式传递到了 PlatformPlugin 中进行实现的。当我们在dart 层设置完成后,通过发送 “ SystemChrome.setSystemUIOverlayStyle ” 来通知原生端进行更新,

//PlatformChannel 类 MethodChannel.MethodCallHandler 实现
case "SystemChrome.setSystemUIOverlayStyle":try {SystemChromeStyle systemChromeStyle =decodeSystemChromeStyle((JSONObject) arguments);platformMessageHandler.setSystemUiOverlayStyle(systemChromeStyle);result.success(null);} catch (JSONException | NoSuchFieldException exception) {// JSONException: One or more expected fields were either omitted or referenced an// invalid type.// NoSuchFieldException: One or more of the brightness names are invalid.result.error("error", exception.getMessage(), null);}break;

然后在PlatformPlugin 中调用 “ setSystemChromeSystemUIOverlayStyle ” 方法,设置状态栏并给 currentTheme 赋值的。

结论

到这里我们可以知道,为啥第一次打开FlutterActivity 状态栏有效,第二次打开无效了,因为在 dart 层,main.dart 中

runApp(MyApp());

只会走一次,第二次打开就不会走了。

PS:

StatusBarHelper 源码

import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.Color;
import android.os.Build;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import androidx.annotation.ColorInt;
import androidx.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
import java.lang.reflect.Method;public class StatusBarHelper {private final static int STATUSBAR_TYPE_DEFAULT = 0;private final static int STATUSBAR_TYPE_MIUI = 1;private final static int STATUSBAR_TYPE_FLYME = 2;private final static int STATUSBAR_TYPE_ANDROID6 = 3; // Android 6.0private final static int STATUS_BAR_DEFAULT_HEIGHT_DP = 25; // 大部分状态栏都是25dp// 在某些机子上存在不同的density值,所以增加两个虚拟值public static float sVirtualDensity = -1;public static float sVirtualDensityDpi = -1;private static int sStatusBarHeight = -1;private static @StatusBarTypeint mStatusBarType = STATUSBAR_TYPE_DEFAULT;private static Integer sTransparentValue;public static void translucent(Activity activity) {translucent(activity.getWindow());}public static void translucent(Window window) {translucent(window, 0x40000000);}private static boolean supportTranslucent() {return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT// Essential Phone 在 Android 8 之前沉浸式做得不全,系统不从状态栏顶部开始布局却会下发 WindowInsets&& !(DeviceHelper.isEssentialPhone() && Build.VERSION.SDK_INT < 26);}@TargetApi(19)public static void translucent(Window window, @ColorInt int colorOn5x) {if (!supportTranslucent()) {// 版本小于4.4,绝对不考虑沉浸式return;}//        if (QMUINotchHelper.isNotchOfficialSupport()) {
//            handleDisplayCutoutMode(window);
//        }// 小米和魅族4.4 以上版本支持沉浸式// 小米 Android 6.0 ,开发版 7.7.13 及以后版本设置黑色字体又需要 clear FLAG_TRANSLUCENT_STATUS, 因此还原为官方模式if (DeviceHelper.isFlymeLowerThan(8) || (DeviceHelper.isMIUI() && Build.VERSION.SDK_INT < Build.VERSION_CODES.M)) {window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);return;}if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {int systemUiVisibility = window.getDecorView().getSystemUiVisibility();systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;window.getDecorView().setSystemUiVisibility(systemUiVisibility);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && supportTransclentStatusBar6()) {// android 6以后可以改状态栏字体颜色,因此可以自行设置为透明// ZUK Z1是个另类,自家应用可以实现字体颜色变色,但没开放接口window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);window.setStatusBarColor(Color.TRANSPARENT);} else {// android 5不能修改状态栏字体颜色,因此直接用FLAG_TRANSLUCENT_STATUS,nexus表现为半透明// 魅族和小米的表现如何?// update: 部分手机运用FLAG_TRANSLUCENT_STATUS时背景不是半透明而是没有背景了。。。。。
//                window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);// 采取setStatusBarColor的方式,部分机型不支持,那就纯黑了,保证状态栏图标可见window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);window.setStatusBarColor(colorOn5x);}
//        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//            // android4.4的默认是从上到下黑到透明,我们的背景是白色,很难看,因此只做魅族和小米的
//        } else if(Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1){
//            // 如果app 为白色,需要更改状态栏颜色,因此不能让19一下支持透明状态栏
//            Window window = activity.getWindow();
//            Integer transparentValue = getStatusBarAPITransparentValue(activity);
//            if(transparentValue != null) {
//                window.getDecorView().setSystemUiVisibility(transparentValue);
//            }}}/*** 设置状态栏黑色字体图标,* 支持 4.4 以上版本 MIUI 和 Flyme,以及 6.0 以上版本的其他 Android** @param activity 需要被处理的 Activity*/public static boolean setStatusBarLightMode(Activity activity) {if (activity == null) return false;// 无语系列:ZTK C2016只能时间和电池图标变色。。。。if (DeviceHelper.isZTKC2016()) {return false;}if (mStatusBarType != STATUSBAR_TYPE_DEFAULT) {return setStatusBarLightMode(activity, mStatusBarType);}if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {if (isMIUICustomStatusBarLightModeImpl() && MIUISetStatusBarLightMode(activity.getWindow(), true)) {mStatusBarType = STATUSBAR_TYPE_MIUI;return true;} else if (FlymeSetStatusBarLightMode(activity.getWindow(), true)) {mStatusBarType = STATUSBAR_TYPE_FLYME;return true;} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {Android6SetStatusBarLightMode(activity.getWindow(), true);mStatusBarType = STATUSBAR_TYPE_ANDROID6;return true;}}return false;}/*** 已知系统类型时,设置状态栏黑色字体图标。* 支持 4.4 以上版本 MIUI 和 Flyme,以及 6.0 以上版本的其他 Android** @param activity 需要被处理的 Activity* @param type     StatusBar 类型,对应不同的系统*/private static boolean setStatusBarLightMode(Activity activity, @StatusBarType int type) {if (type == STATUSBAR_TYPE_MIUI) {return MIUISetStatusBarLightMode(activity.getWindow(), true);} else if (type == STATUSBAR_TYPE_FLYME) {return FlymeSetStatusBarLightMode(activity.getWindow(), true);} else if (type == STATUSBAR_TYPE_ANDROID6) {return Android6SetStatusBarLightMode(activity.getWindow(), true);}return false;}/*** 设置状态栏白色字体图标* 支持 4.4 以上版本 MIUI 和 Flyme,以及 6.0 以上版本的其他 Android*/public static boolean setStatusBarDarkMode(Activity activity) {if (activity == null) return false;if (mStatusBarType == STATUSBAR_TYPE_DEFAULT) {// 默认状态,不需要处理return true;}if (mStatusBarType == STATUSBAR_TYPE_MIUI) {return MIUISetStatusBarLightMode(activity.getWindow(), false);} else if (mStatusBarType == STATUSBAR_TYPE_FLYME) {return FlymeSetStatusBarLightMode(activity.getWindow(), false);} else if (mStatusBarType == STATUSBAR_TYPE_ANDROID6) {return Android6SetStatusBarLightMode(activity.getWindow(), false);}return true;}/*** 设置状态栏字体图标为深色,Android 6** @param window 需要设置的窗口* @param light  是否把状态栏字体及图标颜色设置为深色* @return boolean 成功执行返回true*/@TargetApi(23)private static boolean Android6SetStatusBarLightMode(Window window, boolean light) {View decorView = window.getDecorView();int systemUi = decorView.getSystemUiVisibility();if (light) {systemUi |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;} else {systemUi ^= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;}decorView.setSystemUiVisibility(systemUi);if (DeviceHelper.isMIUIV9()) {// MIUI 9 低于 6.0 版本依旧只能回退到以前的方案// https://github.com/Tencent/QMUI_Android/issues/160MIUISetStatusBarLightMode(window, light);}return true;}/*** 设置状态栏字体图标为深色,需要 MIUIV6 以上** @param window 需要设置的窗口* @param light  是否把状态栏字体及图标颜色设置为深色* @return boolean 成功执行返回 true*/@SuppressWarnings("unchecked")public static boolean MIUISetStatusBarLightMode(Window window, boolean light) {boolean result = false;if (window != null) {Class clazz = window.getClass();try {int darkModeFlag;Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");darkModeFlag = field.getInt(layoutParams);Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);if (light) {extraFlagField.invoke(window, darkModeFlag, darkModeFlag);//状态栏透明且黑色字体} else {extraFlagField.invoke(window, 0, darkModeFlag);//清除黑色字体}result = true;} catch (Exception ignored) {}}return result;}/*** 更改状态栏图标、文字颜色的方案是否是MIUI自家的, MIUI9 && Android 6 之后用回Android原生实现* 见小米开发文档说明:https://dev.mi.com/console/doc/detail?pId=1159*/private static boolean isMIUICustomStatusBarLightModeImpl() {if (DeviceHelper.isMIUIV9() && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {return true;}return DeviceHelper.isMIUIV5() || DeviceHelper.isMIUIV6() ||DeviceHelper.isMIUIV7() || DeviceHelper.isMIUIV8();}/*** 设置状态栏图标为深色和魅族特定的文字风格* 可以用来判断是否为 Flyme 用户** @param window 需要设置的窗口* @param light  是否把状态栏字体及图标颜色设置为深色* @return boolean 成功执行返回true*/public static boolean FlymeSetStatusBarLightMode(Window window, boolean light) {boolean result = false;if (window != null) {Android6SetStatusBarLightMode(window, light);// flyme 在 6.2.0.0A 支持了 Android 官方的实现方案,旧的方案失效// 高版本调用这个出现不可预期的 Bug,官方文档也没有给出完整的高低版本兼容方案if (DeviceHelper.isFlymeLowerThan(7)) {try {WindowManager.LayoutParams lp = window.getAttributes();Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField("meizuFlags");darkFlag.setAccessible(true);meizuFlags.setAccessible(true);int bit = darkFlag.getInt(null);int value = meizuFlags.getInt(lp);if (light) {value |= bit;} else {value &= ~bit;}meizuFlags.setInt(lp, value);window.setAttributes(lp);result = true;} catch (Exception ignored) {}} else if (DeviceHelper.isFlyme()) {result = true;}}return result;}/*** 检测 Android 6.0 是否可以启用 window.setStatusBarColor(Color.TRANSPARENT)。*/public static boolean supportTransclentStatusBar6() {return !(DeviceHelper.isZUKZ1() || DeviceHelper.isZTKC2016());}@IntDef({STATUSBAR_TYPE_DEFAULT, STATUSBAR_TYPE_MIUI, STATUSBAR_TYPE_FLYME, STATUSBAR_TYPE_ANDROID6})@Retention(RetentionPolicy.SOURCE)private @interface StatusBarType {}
}

DeviceHelper:

import android.annotation.TargetApi;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Binder;
import android.os.Build;
import android.os.Environment;
import androidx.annotation.Nullable;
import android.text.TextUtils;import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Method;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;public class DeviceHelper {private final static String TAG = "QMUIDeviceHelper";private final static String KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name";private static final String KEY_FLYME_VERSION_NAME = "ro.build.display.id";private final static String FLYME = "flyme";private final static String ZTEC2016 = "zte c2016";private final static String ZUKZ1 = "zuk z1";private final static String ESSENTIAL = "essential";private final static String MEIZUBOARD[] = {"m9", "M9", "mx", "MX"};private static String sMiuiVersionName;private static String sFlymeVersionName;private static boolean sIsTabletChecked = false;private static boolean sIsTabletValue = false;private static final String BRAND = Build.BRAND.toLowerCase();static {Properties properties = new Properties();if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {// android 8.0,读取 /system/uild.prop 会报 permission deniedFileInputStream fileInputStream = null;try {fileInputStream = new FileInputStream(new File(Environment.getRootDirectory(), "build.prop"));properties.load(fileInputStream);} catch (Exception e) {
//                QMUILog.printErrStackTrace(TAG, e, "read file error");} finally {
//                QMUILangHelper.close(fileInputStream);}}Class<?> clzSystemProperties = null;try {clzSystemProperties = Class.forName("android.os.SystemProperties");Method getMethod = clzSystemProperties.getDeclaredMethod("get", String.class);// miuisMiuiVersionName = getLowerCaseName(properties, getMethod, KEY_MIUI_VERSION_NAME);//flymesFlymeVersionName = getLowerCaseName(properties, getMethod, KEY_FLYME_VERSION_NAME);} catch (Exception e) {
//            QMUILog.printErrStackTrace(TAG, e, "read SystemProperties error");}}private static boolean _isTablet(Context context) {return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >=Configuration.SCREENLAYOUT_SIZE_LARGE;}/*** 判断是否为平板设备*/public static boolean isTablet(Context context) {if (sIsTabletChecked) {return sIsTabletValue;}sIsTabletValue = _isTablet(context);sIsTabletChecked = true;return sIsTabletValue;}/*** 判断是否是flyme系统*/public static boolean isFlyme() {return !TextUtils.isEmpty(sFlymeVersionName) && sFlymeVersionName.contains(FLYME);}/*** 判断是否是MIUI系统*/public static boolean isMIUI() {return !TextUtils.isEmpty(sMiuiVersionName);}public static boolean isMIUIV5() {return "v5".equals(sMiuiVersionName);}public static boolean isMIUIV6() {return "v6".equals(sMiuiVersionName);}public static boolean isMIUIV7() {return "v7".equals(sMiuiVersionName);}public static boolean isMIUIV8() {return "v8".equals(sMiuiVersionName);}public static boolean isMIUIV9() {return "v9".equals(sMiuiVersionName);}public static boolean isFlymeLowerThan(int majorVersion){return isFlymeLowerThan(majorVersion, 0, 0);}public static boolean isFlymeLowerThan(int majorVersion, int minorVersion, int patchVersion) {boolean isLower = false;if (sFlymeVersionName != null && !sFlymeVersionName.equals("")) {try{Pattern pattern = Pattern.compile("(\\d+\\.){2}\\d");Matcher matcher = pattern.matcher(sFlymeVersionName);if (matcher.find()) {String versionString = matcher.group();if (versionString.length() > 0) {String[] version = versionString.split("\\.");if (version.length >= 1) {if (Integer.parseInt(version[0]) < majorVersion) {isLower = true;}}if(version.length >= 2 && minorVersion > 0){if (Integer.parseInt(version[1]) < majorVersion) {isLower = true;}}if(version.length >= 3 && patchVersion > 0){if (Integer.parseInt(version[2]) < majorVersion) {isLower = true;}}}}}catch (Throwable ignore){}}return isMeizu() && isLower;}public static boolean isMeizu() {return isPhone(MEIZUBOARD) || isFlyme();}/*** 判断是否为小米* https://dev.mi.com/doc/?p=254*/public static boolean isXiaomi() {return Build.MANUFACTURER.toLowerCase().equals("xiaomi");}public static boolean isVivo() {return BRAND.contains("vivo") || BRAND.contains("bbk");}public static boolean isOppo() {return BRAND.contains("oppo");}public static boolean isHuawei() {return BRAND.contains("huawei") || BRAND.contains("honor");}public static boolean isEssentialPhone(){return BRAND.contains("essential");}/*** 判断是否为 ZUK Z1 和 ZTK C2016。* 两台设备的系统虽然为 android 6.0,但不支持状态栏icon颜色改变,因此经常需要对它们进行额外判断。*/public static boolean isZUKZ1() {final String board = android.os.Build.MODEL;return board != null && board.toLowerCase().contains(ZUKZ1);}public static boolean isZTKC2016() {final String board = android.os.Build.MODEL;return board != null && board.toLowerCase().contains(ZTEC2016);}private static boolean isPhone(String[] boards) {final String board = android.os.Build.BOARD;if (board == null) {return false;}for (String board1 : boards) {if (board.equals(board1)) {return true;}}return false;}/*** 判断悬浮窗权限(目前主要用户魅族与小米的检测)。*/public static boolean isFloatWindowOpAllowed(Context context) {final int version = Build.VERSION.SDK_INT;if (version >= 19) {return checkOp(context, 24);  // 24 是AppOpsManager.OP_SYSTEM_ALERT_WINDOW 的值,该值无法直接访问} else {try {return (context.getApplicationInfo().flags & 1 << 27) == 1 << 27;} catch (Exception e) {e.printStackTrace();return false;}}}@TargetApi(19)private static boolean checkOp(Context context, int op) {final int version = Build.VERSION.SDK_INT;if (version >= Build.VERSION_CODES.KITKAT) {AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);try {Method method = manager.getClass().getDeclaredMethod("checkOp", int.class, int.class, String.class);int property = (Integer) method.invoke(manager, op,Binder.getCallingUid(), context.getPackageName());return AppOpsManager.MODE_ALLOWED == property;} catch (Exception e) {e.printStackTrace();}}return false;}@Nullableprivate static String getLowerCaseName(Properties p, Method get, String key) {String name = p.getProperty(key);if (name == null) {try {name = (String) get.invoke(null, key);} catch (Exception ignored) {}}if (name != null) name = name.toLowerCase();return name;}
}

混合开发Android FlutterActivity 的透明状态栏相关推荐

  1. kotlin与java混合开发_使用kotlin和Java混合开发Android项目爬坑记录

    使用kotlin和Java混合开发Android项目爬坑记录 不定期将开发过程中遇到的问题添加在此处,加深记忆. 主要内容包括但不限于java与kotlin语言的一些区别,以及在使用android-s ...

  2. Android 沉浸式(透明)状态栏细研-超级细还附 Demo

    前言 在 Android 4.4 中引入了沉浸模式的功能,但这个版本非真正的沉浸模式,应该说是透明模式.Android 5.0 以后才可以在系统层面实现真正的沉浸式状态栏. 沉浸式状态栏是为了与当前使 ...

  3. Android 沉浸式透明状态栏与导航栏

    Android 系统自4.2 开始 UI 上就没多大改变,4.4 也只是增加了透明状态栏与导航栏的功能 这个特性是andorid4.4支持的,最少要api19才可以使用.下面介绍一下使用的方法,非常得 ...

  4. Android美化之透明状态栏

    前言: 之前我是把状态栏直接给删掉了,在style中的appTheme中添加这样一条: <item name="android:windowFullscreen">tr ...

  5. Android App开发 教你分清“沉浸式”和“透明状态栏”

    首先科普下,什么是"沉浸式"和"透明状态栏"? 1. 大家平时看到一些App运行后,状态栏会变成半透明,或者颜色跟随App的标题栏变色,这种特性叫"T ...

  6. android开发(50) Android透明状态栏。适用于 4.4 以上及 5.0以上设备

    概述 有时候我们想在 andorid 手机上实现一种 跨越 顶部状态栏的效果,比如一张图片直接显示在 状态栏内.比如下图: 这个页面里有张图片,这个图片显示在整个页面的上部分.状态栏是 漂浮在这个图片 ...

  7. Android UI体验之全屏沉浸式透明状态栏效果

    前言: Android 4.4之后谷歌提供了沉浸式全屏体验, 在沉浸式全屏模式下, 状态栏. 虚拟按键动态隐藏, 应用可以使用完整的屏幕空间, 按照 Google 的说法, 给用户一种 身临其境 的体 ...

  8. android 实现表格横向混动_Flutter混合开发和Android动态更新实践

    Flutter混合开发和Android动态更新实践 感谢闲鱼和csdn的文章给的思路: 本篇是实践性文章包含两部分 将Flutter工程编译后的文件集成到Android项目 将Flutter代码热更新 ...

  9. 【Flutter】Flutter 混合开发 ( Flutter 与 Native 通信 | Android 端实现 BasicMessageChannel 通信 )

    文章目录 前言 一.Android 端 BasicMessageChannel 构造函数 二.Android 端 MessageCodec 子类实现 三.Android 端 setMessageHan ...

最新文章

  1. ASP.NET Web Pages – 文件简介
  2. 以安全之名:俄罗斯强制所有消息应用留后门
  3. 大对象简介+大对象的4种类型+lob类型的优点+lob的组成
  4. shutil python_shutil模块
  5. IDA Pro逆向实战之Crackme(简单篇)
  6. 《一天聊一个设计模式》 策略
  7. 不使用Vmware easy install 安装
  8. VS2005中GridView簡單應用
  9. elasticsearch 去重计数
  10. List<T>和List<?>的区别
  11. 一文搞懂List 、ListObject、List?的区别以及? extends T与? super T的区别
  12. 2021年年度最优质开源软件
  13. SVG 坐标和 viewBox
  14. 空调开关html,酒店墙上空调开关图解—酒店墙上空调开关图案是什么意思
  15. 【SpringBoot+Vue】前后端分离项目之图片上传与下载
  16. 猿辅导python编程课网课怎么样_猿辅导网课怎么样 靠谱吗
  17. mysql 1593_Linux高可用(HA)之MySQL主从复制中出现1593错误码的低级错误
  18. 单因素方差分析与卡方检验有什么区别,能否举个例子?
  19. 普林斯顿大学计算机科学排名,普林斯顿大学计算机硕士专业排名真实干货升级版...
  20. 各地城市治安防控体系建设走到了哪一步?

热门文章

  1. 漫画解读:车规芯片为何比普通芯片贵?跟普通芯片有什么差异?
  2. Windows之使用批处理创建快捷方式到桌面(符号链接)
  3. 弘扬奥运精神,我们49行画个奥运五环
  4. 时序数据库:TimescaleDB的安装
  5. 程序员版“吐槽大会”: 国产综艺节目年终盘点
  6. 手机端没有好的录屏软件?地表最强移动端录屏软件了解一下?
  7. 【转】XenServer错误恢复:断电网卡丢失.虚拟机(VPS)不见
  8. [global::]是什么形式?什么意思?
  9. Matlab-信号系统笔记
  10. table html 合并列,html table上下行合并