Android 水滴屏、全屏适配

何谓刘海屏?何谓水滴屏?

上述两种屏幕都可以统称为刘海屏,不过对于右侧较小的刘海,业界一般称为水滴屏或美人尖。

目前国内流行的手机厂商主要有:vivo、oppo、华为、小米。各厂商对刘海屏的适配都大不相同,各自有各自对刘海屏的适配API,具体的适配方法可以阅读相应的官网:

VIVO: https://dev.vivo.com.cn/documentCenter/doc/103

OPPO: https://open.oppomobile.com/wiki/doc#id=10159

小米: https://dev.mi.com/console/doc/detail?pId=1293

华为: https://developer.huawei.com/consumer/cn/devservice/doc/50114?from=timeline

下面介绍几种适配方法:

1.StatusBarUtil工具类

1.1 StatusBarUtil工具类

public class StatusBarUtil {

//透明度

public static final int DEFAULT_STATUS_BAR_ALPHA = 112;

private static final int FAKE_STATUS_BAR_VIEW_ID = R.id.statusbarutil_fake_status_bar_view;

private static final int FAKE_TRANSLUCENT_VIEW_ID = R.id.statusbarutil_translucent_view;

private static final int TAG_KEY_HAVE_SET_OFFSET = -123;

/**

* 设置状态栏颜色

*

* @param activity 需要设置的 activity

* @param color 状态栏颜色值

*/

public static void setColor(Activity activity, @ColorInt int color) {

setColor(activity, color, DEFAULT_STATUS_BAR_ALPHA);

}

/**

* 设置状态栏颜色

*

* @param activity 需要设置的activity

* @param color 状态栏颜色值

* @param statusBarAlpha 状态栏透明度

*/

public static void setColor(Activity activity, @ColorInt int color, @IntRange(from = 0, to = 255) int statusBarAlpha) {

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().setStatusBarColor(calculateStatusColor(color, statusBarAlpha));

} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();

View fakeStatusBarView = decorView.findViewById(FAKE_STATUS_BAR_VIEW_ID);

if (fakeStatusBarView != null) {

if (fakeStatusBarView.getVisibility() == View.GONE) {

fakeStatusBarView.setVisibility(View.VISIBLE);

}

fakeStatusBarView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha));

} else {

decorView.addView(createStatusBarView(activity, color, statusBarAlpha));

}

setRootView(activity);

}

}

/**

* 为滑动返回界面设置状态栏颜色

*

* @param activity 需要设置的activity

* @param color 状态栏颜色值

*/

public static void setColorForSwipeBack(Activity activity, int color) {

setColorForSwipeBack(activity, color, DEFAULT_STATUS_BAR_ALPHA);

}

/**

* 为滑动返回界面设置状态栏颜色

*

* @param activity 需要设置的activity

* @param color 状态栏颜色值

* @param statusBarAlpha 状态栏透明度

*/

public static void setColorForSwipeBack(Activity activity, @ColorInt int color,

@IntRange(from = 0, to = 255) int statusBarAlpha) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

ViewGroup contentView = ((ViewGroup) activity.findViewById(android.R.id.content));

View rootView = contentView.getChildAt(0);

int statusBarHeight = getStatusBarHeight(activity);

if (rootView != null && rootView instanceof CoordinatorLayout) {

final CoordinatorLayout coordinatorLayout = (CoordinatorLayout) rootView;

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {

coordinatorLayout.setFitsSystemWindows(false);

contentView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha));

boolean isNeedRequestLayout = contentView.getPaddingTop() < statusBarHeight;

if (isNeedRequestLayout) {

contentView.setPadding(0, statusBarHeight, 0, 0);

coordinatorLayout.post(new Runnable() {

@Override

public void run() {

coordinatorLayout.requestLayout();

}

});

}

} else {

coordinatorLayout.setStatusBarBackgroundColor(calculateStatusColor(color, statusBarAlpha));

}

} else {

contentView.setPadding(0, statusBarHeight, 0, 0);

contentView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha));

}

setTransparentForWindow(activity);

}

}

/**

* 设置状态栏纯色 不加半透明效果

*

* @param activity 需要设置的 activity

* @param color 状态栏颜色值

*/

public static void setColorNoTranslucent(Activity activity, @ColorInt int color) {

setColor(activity, color, 0);

}

/**

* 设置状态栏纯色 不加半透明效果 字体为黑色

*

* @param activity 需要设置的 activity

* @param color 状态栏颜色值

*/

public static void setColorNoTranslucentLightMode(Activity activity, @ColorInt int color) {

setColor(activity, color, 0);

//setLightMode(activity);

}

/**

* 设置状态栏颜色(5.0以下无半透明效果,不建议使用)

*

* @param activity 需要设置的 activity

* @param color 状态栏颜色值

*/

@Deprecated

public static void setColorDiff(Activity activity, @ColorInt int color) {

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {

return;

}

transparentStatusBar(activity);

ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);

// 移除半透明矩形,以免叠加

View fakeStatusBarView = contentView.findViewById(FAKE_STATUS_BAR_VIEW_ID);

if (fakeStatusBarView != null) {

if (fakeStatusBarView.getVisibility() == View.GONE) {

fakeStatusBarView.setVisibility(View.VISIBLE);

}

fakeStatusBarView.setBackgroundColor(color);

} else {

contentView.addView(createStatusBarView(activity, color));

}

setRootView(activity);

}

/**

* 使状态栏半透明

*

* 适用于图片作为背景的界面,此时需要图片填充到状态栏

*

* @param activity 需要设置的activity

*/

public static void setTranslucent(Activity activity) {

setTranslucent(activity, DEFAULT_STATUS_BAR_ALPHA);

}

/**

* 使状态栏半透明

*

* 适用于图片作为背景的界面,此时需要图片填充到状态栏

*

* @param activity 需要设置的activity

* @param statusBarAlpha 状态栏透明度

*/

public static void setTranslucent(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha) {

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {

return;

}

setTransparent(activity);

addTranslucentView(activity, statusBarAlpha);

}

/**

* 针对根布局是 CoordinatorLayout, 使状态栏半透明

*

* 适用于图片作为背景的界面,此时需要图片填充到状态栏

*

* @param activity 需要设置的activity

* @param statusBarAlpha 状态栏透明度

*/

public static void setTranslucentForCoordinatorLayout(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha) {

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {

return;

}

transparentStatusBar(activity);

addTranslucentView(activity, statusBarAlpha);

}

/**

* 设置状态栏全透明

*

* @param activity 需要设置的activity

*/

public static void setTransparent(Activity activity) {

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {

return;

}

transparentStatusBar(activity);

setRootView(activity);

}

/**

* 使状态栏透明(5.0以上半透明效果,不建议使用)

*

* 适用于图片作为背景的界面,此时需要图片填充到状态栏

*

* @param activity 需要设置的activity

*/

@Deprecated

public static void setTranslucentDiff(Activity activity) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

// 设置状态栏透明

activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

setRootView(activity);

}

}

/**

* 为DrawerLayout 布局设置状态栏变色

*

* @param activity 需要设置的activity

* @param drawerLayout DrawerLayout

* @param color 状态栏颜色值

*/

public static void setColorForDrawerLayout(Activity activity, DrawerLayout drawerLayout, @ColorInt int color) {

setColorForDrawerLayout(activity, drawerLayout, color, DEFAULT_STATUS_BAR_ALPHA);

}

/**

* 为DrawerLayout 布局设置状态栏颜色,纯色

*

* @param activity 需要设置的activity

* @param drawerLayout DrawerLayout

* @param color 状态栏颜色值

*/

public static void setColorNoTranslucentForDrawerLayout(Activity activity, DrawerLayout drawerLayout, @ColorInt int color) {

setColorForDrawerLayout(activity, drawerLayout, color, 0);

}

/**

* 为DrawerLayout 布局设置状态栏颜色,纯色 字体为黑色

*

* @param activity 需要设置的activity

* @param drawerLayout DrawerLayout

* @param color 状态栏颜色值

*/

public static void setColorNoTranslucentForDrawerLayoutLightMode(Activity activity, DrawerLayout drawerLayout, @ColorInt int color) {

setColorForDrawerLayout(activity, drawerLayout, color, 0);

setLightMode(activity);

}

/**

* 为DrawerLayout 布局设置状态栏变色

*

* @param activity 需要设置的activity

* @param drawerLayout DrawerLayout

* @param color 状态栏颜色值

* @param statusBarAlpha 状态栏透明度

*/

public static void setColorForDrawerLayout(Activity activity, DrawerLayout drawerLayout, @ColorInt int color,

@IntRange(from = 0, to = 255) int statusBarAlpha) {

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().setStatusBarColor(Color.TRANSPARENT);

} else {

activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

}

// 生成一个状态栏大小的矩形

// 添加 statusBarView 到布局中

ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0);

View fakeStatusBarView = contentLayout.findViewById(FAKE_STATUS_BAR_VIEW_ID);

if (fakeStatusBarView != null) {

if (fakeStatusBarView.getVisibility() == View.GONE) {

fakeStatusBarView.setVisibility(View.VISIBLE);

}

fakeStatusBarView.setBackgroundColor(color);

} else {

contentLayout.addView(createStatusBarView(activity, color), 0);

}

// 内容布局不是 LinearLayout 时,设置padding top

if (!(contentLayout instanceof LinearLayout) && contentLayout.getChildAt(1) != null) {

contentLayout.getChildAt(1)

.setPadding(contentLayout.getPaddingLeft(), getStatusBarHeight(activity) + contentLayout.getPaddingTop(),

contentLayout.getPaddingRight(), contentLayout.getPaddingBottom());

}

// 设置属性

setDrawerLayoutProperty(drawerLayout, contentLayout);

addTranslucentView(activity, statusBarAlpha);

}

/**

* 设置 DrawerLayout 属性

*

* @param drawerLayout DrawerLayout

* @param drawerLayoutContentLayout DrawerLayout 的内容布局

*/

private static void setDrawerLayoutProperty(DrawerLayout drawerLayout, ViewGroup drawerLayoutContentLayout) {

ViewGroup drawer = (ViewGroup) drawerLayout.getChildAt(1);

drawerLayout.setFitsSystemWindows(false);

drawerLayoutContentLayout.setFitsSystemWindows(false);

drawerLayoutContentLayout.setClipToPadding(true);

drawer.setFitsSystemWindows(false);

}

/**

* 为DrawerLayout 布局设置状态栏变色(5.0以下无半透明效果,不建议使用)

*

* @param activity 需要设置的activity

* @param drawerLayout DrawerLayout

* @param color 状态栏颜色值

*/

@Deprecated

public static void setColorForDrawerLayoutDiff(Activity activity, DrawerLayout drawerLayout, @ColorInt int color) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

// 生成一个状态栏大小的矩形

ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0);

View fakeStatusBarView = contentLayout.findViewById(FAKE_STATUS_BAR_VIEW_ID);

if (fakeStatusBarView != null) {

if (fakeStatusBarView.getVisibility() == View.GONE) {

fakeStatusBarView.setVisibility(View.VISIBLE);

}

fakeStatusBarView.setBackgroundColor(calculateStatusColor(color, DEFAULT_STATUS_BAR_ALPHA));

} else {

// 添加 statusBarView 到布局中

contentLayout.addView(createStatusBarView(activity, color), 0);

}

// 内容布局不是 LinearLayout 时,设置padding top

if (!(contentLayout instanceof LinearLayout) && contentLayout.getChildAt(1) != null) {

contentLayout.getChildAt(1).setPadding(0, getStatusBarHeight(activity), 0, 0);

}

// 设置属性

setDrawerLayoutProperty(drawerLayout, contentLayout);

}

}

/**

* 为 DrawerLayout 布局设置状态栏透明

*

* @param activity 需要设置的activity

* @param drawerLayout DrawerLayout

*/

public static void setTranslucentForDrawerLayout(Activity activity, DrawerLayout drawerLayout) {

setTranslucentForDrawerLayout(activity, drawerLayout, DEFAULT_STATUS_BAR_ALPHA);

}

/**

* 为 DrawerLayout 布局设置状态栏透明

*

* @param activity 需要设置的activity

* @param drawerLayout DrawerLayout

*/

public static void setTranslucentForDrawerLayout(Activity activity, DrawerLayout drawerLayout,

@IntRange(from = 0, to = 255) int statusBarAlpha) {

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {

return;

}

setTransparentForDrawerLayout(activity, drawerLayout);

addTranslucentView(activity, statusBarAlpha);

}

/**

* 为 DrawerLayout 布局设置状态栏透明

*

* @param activity 需要设置的activity

* @param drawerLayout DrawerLayout

*/

public static void setTransparentForDrawerLayout(Activity activity, DrawerLayout drawerLayout) {

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {

return;

}

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().setStatusBarColor(Color.TRANSPARENT);

} else {

activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

}

ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0);

// 内容布局不是 LinearLayout 时,设置padding top

if (!(contentLayout instanceof LinearLayout) && contentLayout.getChildAt(1) != null) {

contentLayout.getChildAt(1).setPadding(0, getStatusBarHeight(activity), 0, 0);

}

// 设置属性

setDrawerLayoutProperty(drawerLayout, contentLayout);

}

/**

* 为 DrawerLayout 布局设置状态栏透明(5.0以上半透明效果,不建议使用)

*

* @param activity 需要设置的activity

* @param drawerLayout DrawerLayout

*/

@Deprecated

public static void setTranslucentForDrawerLayoutDiff(Activity activity, DrawerLayout drawerLayout) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

// 设置状态栏透明

activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

// 设置内容布局属性

ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0);

contentLayout.setFitsSystemWindows(true);

contentLayout.setClipToPadding(true);

// 设置抽屉布局属性

ViewGroup vg = (ViewGroup) drawerLayout.getChildAt(1);

vg.setFitsSystemWindows(false);

// 设置 DrawerLayout 属性

drawerLayout.setFitsSystemWindows(false);

}

}

/**

* 为头部是 ImageView 的界面设置状态栏全透明

*

* @param activity 需要设置的activity

* @param needOffsetView 需要向下偏移的 View

*/

public static void setTransparentForImageView(Activity activity, View needOffsetView) {

setTranslucentForImageView(activity, 0, needOffsetView);

}

/**

* 为头部是 ImageView 的界面设置状态栏透明(使用默认透明度)

*

* @param activity 需要设置的activity

* @param needOffsetView 需要向下偏移的 View

*/

public static void setTranslucentForImageView(Activity activity, View needOffsetView) {

setTranslucentForImageView(activity, DEFAULT_STATUS_BAR_ALPHA, needOffsetView);

}

/**

* 为头部是 ImageView 的界面设置状态栏透明

*

* @param activity 需要设置的activity

* @param statusBarAlpha 状态栏透明度

* @param needOffsetView 需要向下偏移的 View

*/

public static void setTranslucentForImageView(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha,

View needOffsetView) {

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {

return;

}

setTransparentForWindow(activity);

addTranslucentView(activity, statusBarAlpha);

if (needOffsetView != null) {

Object haveSetOffset = needOffsetView.getTag(TAG_KEY_HAVE_SET_OFFSET);

if (haveSetOffset != null && (Boolean) haveSetOffset) {

return;

}

ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) needOffsetView.getLayoutParams();

layoutParams.setMargins(layoutParams.leftMargin, layoutParams.topMargin + getStatusBarHeight(activity),

layoutParams.rightMargin, layoutParams.bottomMargin);

needOffsetView.setTag(TAG_KEY_HAVE_SET_OFFSET, true);

}

}

/**

* 为 fragment 头部是 ImageView 的设置状态栏透明

*

* @param activity fragment 对应的 activity

* @param needOffsetView 需要向下偏移的 View

*/

public static void setTranslucentForImageViewInFragment(Activity activity, View needOffsetView) {

setTranslucentForImageViewInFragment(activity, DEFAULT_STATUS_BAR_ALPHA, needOffsetView);

}

/**

* 为 fragment 头部是 ImageView 的设置状态栏透明

*

* @param activity fragment 对应的 activity

* @param needOffsetView 需要向下偏移的 View

*/

public static void setTransparentForImageViewInFragment(Activity activity, View needOffsetView) {

setTranslucentForImageViewInFragment(activity, 0, needOffsetView);

}

/**

* 为 fragment 头部是 ImageView 的设置状态栏透明

*

* @param activity fragment 对应的 activity

* @param statusBarAlpha 状态栏透明度

* @param needOffsetView 需要向下偏移的 View

*/

public static void setTranslucentForImageViewInFragment(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha,

View needOffsetView) {

setTranslucentForImageView(activity, statusBarAlpha, needOffsetView);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {

clearPreviousSetting(activity);

}

}

/**

* 隐藏伪状态栏 View

*

* @param activity 调用的 Activity

*/

public static void hideFakeStatusBarView(Activity activity) {

ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();

View fakeStatusBarView = decorView.findViewById(FAKE_STATUS_BAR_VIEW_ID);

if (fakeStatusBarView != null) {

fakeStatusBarView.setVisibility(View.GONE);

}

View fakeTranslucentView = decorView.findViewById(FAKE_TRANSLUCENT_VIEW_ID);

if (fakeTranslucentView != null) {

fakeTranslucentView.setVisibility(View.GONE);

}

}

@TargetApi(Build.VERSION_CODES.M)

public static void setLightMode(Activity activity) {

setMIUIStatusBarDarkIcon(activity, true);

setMeizuStatusBarDarkIcon(activity, true);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

}

}

@TargetApi(Build.VERSION_CODES.M)

public static void setDarkMode(Activity activity) {

setMIUIStatusBarDarkIcon(activity, false);

setMeizuStatusBarDarkIcon(activity, false);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

}

}

/**

* 修改 MIUI V6 以上状态栏颜色

*/

private static void setMIUIStatusBarDarkIcon(@NonNull Activity activity, boolean darkIcon) {

Class clazz = activity.getWindow().getClass();

try {

@SuppressLint("PrivateApi")

Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");

Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");

int darkModeFlag = field.getInt(layoutParams);

Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);

extraFlagField.invoke(activity.getWindow(), darkIcon ? darkModeFlag : 0, darkModeFlag);

} catch (Exception e) {

//e.printStackTrace();

}

}

/**

* 修改魅族状态栏字体颜色 Flyme 4.0

*/

private static void setMeizuStatusBarDarkIcon(@NonNull Activity activity, boolean darkIcon) {

try {

WindowManager.LayoutParams lp = activity.getWindow().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 (darkIcon) {

value |= bit;

} else {

value &= ~bit;

}

meizuFlags.setInt(lp, value);

activity.getWindow().setAttributes(lp);

} catch (Exception e) {

//e.printStackTrace();

}

}

///

@TargetApi(Build.VERSION_CODES.KITKAT)

private static void clearPreviousSetting(Activity activity) {

ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();

View fakeStatusBarView = decorView.findViewById(FAKE_STATUS_BAR_VIEW_ID);

if (fakeStatusBarView != null) {

decorView.removeView(fakeStatusBarView);

ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);

rootView.setPadding(0, 0, 0, 0);

}

}

/**

* 添加半透明矩形条

*

* @param activity 需要设置的 activity

* @param statusBarAlpha 透明值

*/

private static void addTranslucentView(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha) {

ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);

View fakeTranslucentView = contentView.findViewById(FAKE_TRANSLUCENT_VIEW_ID);

if (fakeTranslucentView != null) {

if (fakeTranslucentView.getVisibility() == View.GONE) {

fakeTranslucentView.setVisibility(View.VISIBLE);

}

fakeTranslucentView.setBackgroundColor(Color.argb(statusBarAlpha, 0, 0, 0));

} else {

contentView.addView(createTranslucentStatusBarView(activity, statusBarAlpha));

}

}

/**

* 生成一个和状态栏大小相同的彩色矩形条

*

* @param activity 需要设置的 activity

* @param color 状态栏颜色值

* @return 状态栏矩形条

*/

private static View createStatusBarView(Activity activity, @ColorInt int color) {

return createStatusBarView(activity, color, 0);

}

/**

* 生成一个和状态栏大小相同的半透明矩形条

*

* @param activity 需要设置的activity

* @param color 状态栏颜色值

* @param alpha 透明值

* @return 状态栏矩形条

*/

private static View createStatusBarView(Activity activity, @ColorInt int color, int alpha) {

// 绘制一个和状态栏一样高的矩形

View statusBarView = new View(activity);

LinearLayout.LayoutParams params =

new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity));

statusBarView.setLayoutParams(params);

statusBarView.setBackgroundColor(calculateStatusColor(color, alpha));

statusBarView.setId(FAKE_STATUS_BAR_VIEW_ID);

return statusBarView;

}

/**

* 设置根布局参数

*/

private static void setRootView(Activity activity) {

ViewGroup parent = (ViewGroup) activity.findViewById(android.R.id.content);

for (int i = 0, count = parent.getChildCount(); i < count; i++) {

View childView = parent.getChildAt(i);

if (childView instanceof ViewGroup) {

childView.setFitsSystemWindows(true);

((ViewGroup) childView).setClipToPadding(true);

}

}

}

/**

* 设置透明

*/

private static void setTransparentForWindow(Activity activity) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

activity.getWindow().setStatusBarColor(Color.TRANSPARENT);

activity.getWindow()

.getDecorView()

.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

activity.getWindow()

.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

}

}

/**

* 使状态栏透明

*/

@TargetApi(Build.VERSION_CODES.KITKAT)

private static void transparentStatusBar(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);

}

}

/**

* 创建半透明矩形 View

*

* @param alpha 透明值

* @return 半透明 View

*/

private static View createTranslucentStatusBarView(Activity activity, int alpha) {

// 绘制一个和状态栏一样高的矩形

View statusBarView = new View(activity);

LinearLayout.LayoutParams params =

new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity));

statusBarView.setLayoutParams(params);

statusBarView.setBackgroundColor(Color.argb(alpha, 0, 0, 0));

statusBarView.setId(FAKE_TRANSLUCENT_VIEW_ID);

return statusBarView;

}

/**

* 获取状态栏高度

*

* @param context context

* @return 状态栏高度

*/

public static int getStatusBarHeight(Context context) {

// 获得状态栏高度

int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");

return context.getResources().getDimensionPixelSize(resourceId);

}

/***

* 只能作用于activity

*/

public static void setTaskBarColored(Activity context, int color) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

Window w = context.getWindow();

w.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

//status bar height

int statusBarHeight = getStatusBarHeight(context);

View view = new View(context);

view.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));

view.getLayoutParams().height = statusBarHeight;

((ViewGroup) w.getDecorView()).addView(view);

//view.setBackgroundColor(context.getResources().getColor(R.color.colorPrimaryTaskBar));

view.setBackgroundColor(color);

}

}

/**

* 计算状态栏颜色

*

* @param color color值

* @param alpha alpha值

* @return 最终的状态栏颜色

*/

private static int calculateStatusColor(@ColorInt int color, int alpha) {

if (alpha == 0) {

return color;

}

float a = 1 - alpha / 255f;

int red = color >> 16 & 0xff;

int green = color >> 8 & 0xff;

int blue = color & 0xff;

red = (int) (red * a + 0.5);

green = (int) (green * a + 0.5);

blue = (int) (blue * a + 0.5);

return 0xff << 24 | red << 16 | green << 8 | blue;

}

/***

* Android设置背景图延伸到状态栏

* https://www.codenong.com/cs106491245/

* @param context

*/

public static void transparentStatusBarForImage(Activity context) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

//5.0 全透明实现

//getWindow.setStatusBarColor(Color.TRANSPARENT)

Window window = context.getWindow();

window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);

window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);

window.setStatusBarColor(Color.TRANSPARENT);

} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

//4.4 全透明状态栏

context.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

}

}

// 设置状态栏文字颜色为黑色

public static void setStatusBarLightMode(Activity activity) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

View decorView = activity.getWindow().getDecorView();

int systemUiVisibility = decorView.getSystemUiVisibility();

decorView.setSystemUiVisibility(systemUiVisibility | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);

}

}

// 设置状态栏文字颜色为白色

public static void setStatusBarDarkMode(Activity activity) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

View decorView = activity.getWindow().getDecorView();

int systemUiVisibility = decorView.getSystemUiVisibility();

decorView.setSystemUiVisibility(systemUiVisibility & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);

}

}

// 设置状态栏(纯)颜色

public static void setStatusBarColor(Activity activity, int colorResId) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

Window window = activity.getWindow();

window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);

window.setStatusBarColor(activity.getResources().getColor(colorResId));

}

}

public static void setStatusBarColor(Dialog dialog, int colorResId) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

Window window = dialog.getWindow();

window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);

window.setStatusBarColor(dialog.getContext().getResources().getColor(colorResId));

}

}

/***

* 设置dialog的状态栏的字体颜色

* @param dialog DialogFragment

*/

public static void setStatusBarLightMode(Dialog dialog) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

View decorView = dialog.getWindow().getDecorView();

int systemUiVisibility = decorView.getSystemUiVisibility();

decorView.setSystemUiVisibility(systemUiVisibility | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);

}

}

}

1.2 AndroidManifest.xml

android:name="android.notch_support"

android:value="true" />

android:name="notch.config"

android:value="portrait|landscape" />

android:name="android.max_aspect"

android:value="2.4" />

1.3 ids.xml

2.NotchScreenTool第三方库

2.1 代码

// 支持显示到刘海区域

NotchScreenManager.getInstance().setDisplayInNotch(this);

// 获取刘海屏信息

NotchScreenManager.getInstance().getNotchInfo(this, new INotchScreen.NotchScreenCallback() {

@Override

public void onResult(INotchScreen.NotchScreenInfo notchScreenInfo) {

Log.i(TAG, "Is this screen notch? " + notchScreenInfo.hasNotch);

if (notchScreenInfo.hasNotch) {

for (Rect rect : notchScreenInfo.notchRects) {

Log.i(TAG, "notch screen Rect = " + rect.toShortString());

}

}

}

});

2.2 AndroidManifest.xml

标签中增加属性:android:resizeableActivity="false" 或者不设置

同时在节点下增加一个meta-data标签:

2.3 githup

githup

3.ImmersionBar第三方库

3.1 依赖

// 基础依赖包,必须要依赖

implementation 'com.geyifeng.immersionbar:immersionbar:3.2.2'

// kotlin扩展(可选)

implementation 'com.geyifeng.immersionbar:immersionbar-ktx:3.2.2'

// fragment快速实现(可选)已废弃

implementation 'com.geyifeng.immersionbar:immersionbar-components:3.2.2'

3.2 关于全面屏与刘海

关于全面屏

在manifest加入如下配置,四选其一,或者都写

① 升级targetSdkVersion为25以上版本,现在基本都是25以上了,所以以下三个没有必要配置了

② 在manifest的Application节点中加入

android:resizeableActivity="true"

③ 在manifest的Application节点中加入

android:maxAspectRatio="2.4"

④ 在manifest的Application节点下加入

android:name="android.max_aspect"

android:value="2.4" />

关于刘海屏

在manifest的Application节点下加入,vivo和oppo没有找到相关配置信息

android:name="android.notch_support"

android:value="true"/>

android:name="notch.config"

android:value="portrait|landscape" />

3.3 Api详解

基础用法 ImmersionBar.with(this).init();

高级用法(每个参数的意义) ImmersionBar.with(this)

.transparentStatusBar() //透明状态栏,不写默认透明色

.transparentNavigationBar() //透明导航栏,不写默认黑色(设置此方法,fullScreen()方法自动为true)

.transparentBar() //透明状态栏和导航栏,不写默认状态栏为透明色,导航栏为黑色(设置此方法,fullScreen()方法自动为true)

.statusBarColor(R.color.colorPrimary) //状态栏颜色,不写默认透明色

.navigationBarColor(R.color.colorPrimary) //导航栏颜色,不写默认黑色

.barColor(R.color.colorPrimary) //同时自定义状态栏和导航栏颜色,不写默认状态栏为透明色,导航栏为黑色

.statusBarAlpha(0.3f) //状态栏透明度,不写默认0.0f

.navigationBarAlpha(0.4f) //导航栏透明度,不写默认0.0F

.barAlpha(0.3f) //状态栏和导航栏透明度,不写默认0.0f

.statusBarDarkFont(true) //状态栏字体是深色,不写默认为亮色

.navigationBarDarkIcon(true) //导航栏图标是深色,不写默认为亮色

.autoDarkModeEnable(true) //自动状态栏字体和导航栏图标变色,必须指定状态栏颜色和导航栏颜色才可以自动变色哦

.autoStatusBarDarkModeEnable(true,0.2f) //自动状态栏字体变色,必须指定状态栏颜色才可以自动变色哦

.autoNavigationBarDarkModeEnable(true,0.2f) //自动导航栏图标变色,必须指定导航栏颜色才可以自动变色哦

.flymeOSStatusBarFontColor(R.color.btn3) //修改flyme OS状态栏字体颜色

.fullScreen(true) //有导航栏的情况下,activity全屏显示,也就是activity最下面被导航栏覆盖,不写默认非全屏

.hideBar(BarHide.FLAG_HIDE_BAR) //隐藏状态栏或导航栏或两者,不写默认不隐藏

.addViewSupportTransformColor(toolbar) //设置支持view变色,可以添加多个view,不指定颜色,默认和状态栏同色,还有两个重载方法

.titleBar(view) //解决状态栏和布局重叠问题,任选其一

.titleBarMarginTop(view) //解决状态栏和布局重叠问题,任选其一

.statusBarView(view) //解决状态栏和布局重叠问题,任选其一

.fitsSystemWindows(true) //解决状态栏和布局重叠问题,任选其一,默认为false,当为true时一定要指定statusBarColor(),不然状态栏为透明色,还有一些重载方法

.supportActionBar(true) //支持ActionBar使用

.statusBarColorTransform(R.color.orange) //状态栏变色后的颜色

.navigationBarColorTransform(R.color.orange) //导航栏变色后的颜色

.barColorTransform(R.color.orange) //状态栏和导航栏变色后的颜色

.removeSupportView(toolbar) //移除指定view支持

.removeSupportAllView() //移除全部view支持

.navigationBarEnable(true) //是否可以修改导航栏颜色,默认为true

.navigationBarWithKitkatEnable(true) //是否可以修改安卓4.4和emui3.x手机导航栏颜色,默认为true

.navigationBarWithEMUI3Enable(true) //是否可以修改emui3.x手机导航栏颜色,默认为true

.keyboardEnable(true) //解决软键盘与底部输入框冲突问题,默认为false,还有一个重载方法,可以指定软键盘mode

.keyboardMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) //单独指定软键盘模式

.setOnKeyboardListener(new OnKeyboardListener() { //软键盘监听回调,keyboardEnable为true才会回调此方法

@Override

public void onKeyboardChange(boolean isPopup, int keyboardHeight) {

LogUtils.e(isPopup); //isPopup为true,软键盘弹出,为false,软键盘关闭

}

})

.setOnNavigationBarListener(onNavigationBarListener) //导航栏显示隐藏监听,目前只支持华为和小米手机

.setOnBarListener(OnBarListener) //第一次调用和横竖屏切换都会触发,可以用来做刘海屏遮挡布局控件的问题

.addTag("tag") //给以上设置的参数打标记

.getTag("tag") //根据tag获得沉浸式参数

.reset() //重置所以沉浸式参数

.init(); //必须调用方可应用以上所配置的参数

在Activity中实现沉浸式

java用法 ImmersionBar.with(this).init();

kotlin用法 immersionBar {

statusBarColor(R.color.colorPrimary)

navigationBarColor(R.color.colorPrimary)

}

在Fragment中实现沉浸式

在Fragment使用ImmersionBar

第一种,fragment如果配合viewpager2使用的话,并且使用了Behavior指定了BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT,直接在fragment的onResume里直接实现沉浸式第二种,当使用show()和hide()来控制Fragment显示隐藏的时候,直接在fragment的onResume与onHiddenChanged(参数hidden为false)方法里实现沉浸式第三种(废弃),你的Fragment直接继承SimpleImmersionFragment或者ImmersionFragment类,在initImmersionBar方法中实现沉浸式代码,只有当immersionBarEnabled返回为true才可以走initImmersionBar方法哦,不过immersionBarEnabled默认返回已经为true了,如果当前Fragment不想走沉浸式方法,请将immersionBarEnabled设置为false第四种(废弃),如果你的Fragment不能继承SimpleImmersionFragment或者ImmersionFragment类,请参考SimpleImmersionFragment实现SimpleImmersionOwner接口,或者参考ImmersionFragment实现ImmersionOwner接口

在Activity使用ImmersionBar

第一种,当结合viewpager2使用的时候,请使用viewpager2的registerOnPageChangeCallback的方法监听沉浸式第二种,当结合viewpager使用的时候,请使用viewpager的addOnPageChangeListener的方法监听沉浸式,参考demo中FragmentThreeActivity这个类第三种,当使用show()和hide()来控制Fragment显示隐藏的时候,请在tab切换的时候使用ImmersionBar,参考demo中FragmentFourActivity这个类

使用Fragment第三方框架Fragmentation实现沉浸式

参考demo中FragmentFiveActivity和BaseFiveFragment这个类

在Dialog中实现沉浸式,具体实现参考demo

①结合dialogFragment使用,可以参考demo中的BaseDialogFragment这个类 ImmersionBar.with(this).init();

②其他dialog,关闭dialog的时候必须调用销毁方法 ImmersionBar.with(this, dialog).init();

销毁方法: java中 ImmersionBar.destroy(this, dialog);

kotlin中 destroyImmersionBar(dialog)

在PopupWindow中实现沉浸式,具体实现参考demo

重点是调用以下方法,但是此方法会导致有导航栏的手机底部布局会被导航栏覆盖,还有底部输入框无法根据软键盘弹出而弹出,具体适配请参考demo。

popupWindow.setClippingEnabled(false);

状态栏与布局顶部重叠解决方案,六种方案根据不同需求任选其一

① 使用dimen自定义状态栏高度,不建议使用,因为设备状态栏高度并不是固定的 在values-v19/dimens.xml文件下 25dp

在values/dimens.xml文件下 0dp

然后在布局界面添加view标签,高度指定为status_bar_height

xmlns:app="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@color/darker_gray"

android:orientation="vertical">

android:layout_width="match_parent"

android:layout_height="@dimen/status_bar_height"

android:background="@color/colorPrimary" />

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:background="@color/colorPrimary"

app:title="方法一"

app:titleTextColor="@android:color/white" />

② 使用系统的fitsSystemWindows属性,使用该属性不会导致输入框与软键盘冲突问题,不要再Fragment使用该属性,只适合纯色状态栏

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

android:fitsSystemWindows="true">

然后使用ImmersionBar时候必须指定状态栏颜色 ImmersionBar.with(this)

.statusBarColor(R.color.colorPrimary)

.init();

注意:ImmersionBar一定要在设置完布局以后使用, ③ 使用ImmersionBar的fitsSystemWindows(boolean fits)方法,只适合纯色状态栏 ImmersionBar.with(this)

.fitsSystemWindows(true) //使用该属性,必须指定状态栏颜色

.statusBarColor(R.color.colorPrimary)

.init();

④ 使用ImmersionBar的statusBarView(View view)方法,可以用来适配渐变色状态栏、侧滑返回 在标题栏的上方增加View标签,高度指定为0dp

xmlns:app="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@color/darker_gray"

android:orientation="vertical">

android:layout_width="match_parent"

android:layout_height="0dp"

android:background="@color/colorPrimary" />

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:background="@color/colorPrimary"

app:title="方法四"

app:titleTextColor="@android:color/white" />

然后使用ImmersionBar的statusBarView方法,指定view就可以啦 ImmersionBar.with(this)

.statusBarView(view)

.init();

//或者

//ImmersionBar.setStatusBarView(this,view);

⑤ 使用ImmersionBar的titleBar(View view)方法,原理是设置paddingTop,可以用来适配渐变色状态栏、侧滑返回 ImmersionBar.with(this)

.titleBar(view) //可以为任意view,如果是自定义xml实现标题栏的话,标题栏根节点不能为RelativeLayout或者ConstraintLayout,以及其子类

.init();

//或者

//ImmersionBar.setTitleBar(this, view);

⑥ 使用ImmersionBar的titleBarMarginTop(View view)方法,原理是设置marginTop,只适合纯色状态栏 ImmersionBar.with(this)

.titleBarMarginTop(view) //可以为任意view

.statusBarColor(R.color.colorPrimary) //指定状态栏颜色,根据情况是否设置

.init();

//或者使用静态方法设置

//ImmersionBar.setTitleBarMarginTop(this,view);

解决EditText和软键盘的问题

第一种方案 ImmersionBar.with(this)

.keyboardEnable(true) //解决软键盘与底部输入框冲突问题

// .keyboardEnable(true, WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE

// | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) //软键盘自动弹出

.init();

第二种方案 不使用keyboardEnable方法,只需要在布局的根节点(最外层节点)加上android:fitsSystemWindows="true"属性即可,只适合纯色状态栏

当白色背景状态栏遇到不能改变状态栏字体为深色的设备时,解决方案

ImmersionBar.with(this)

.statusBarDarkFont(true, 0.2f) //原理:如果当前设备支持状态栏字体变色,会设置状态栏字体为黑色,如果当前设备不支持状态栏字体变色,会使当前状态栏加上透明度,否则不执行透明度

.init();

状态栏和导航栏其它方法

public static boolean hasNavigationBar(Activity activity) 判断是否存在导航栏 public static int getNavigationBarHeight(Activity activity) 获得导航栏的高度 public static int getNavigationBarWidth(Activity activity) 获得导航栏的宽度 public static boolean isNavigationAtBottom(Activity activity) 判断导航栏是否在底部 public static int getStatusBarHeight(Activity activity) 获得状态栏的高度 public static int getActionBarHeight(Activity activity) 获得ActionBar的高度 public static boolean hasNotchScreen(Activity activity) 是否是刘海屏 public static boolean getNotchHeight(Activity activity) 获得刘海屏高度 public static boolean isSupportStatusBarDarkFont() 判断当前设备支不支持状态栏字体设置为黑色 public static boolean isSupportNavigationIconDark() 判断当前设备支不支持导航栏图标设置为黑色 public static void hideStatusBar(Window window) 隐藏状态栏

4.EdgeUtils

EdgeUtils:安卓沉浸式方案(edge to edge)封装

githup

参考阅读

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。