Android app实现暗黑模式 安卓适配暗黑模式_Android app实现暗黑模式

AndroidQ版本发布已经快一年了 虽然市场使用的占有率还不是太高 但是新手机 5G手机基本搭载的都是AndroidQ 所以AndroidQ的适配已经近在眼前了

AndroidQ两大主要变动:

1.暗黑模式适配

2.私有目录与公共目录文件的交互

首先我们来谈谈暗黑模式

在 Android Q 里,Dark theme 暗黑模式得到了系统级的支持。 暗黑模式不仅酷炫,而且有降低屏幕耗电、在光线较暗的环境中使用更舒适等好处。

Force Dark

其实我们的需求很明确,就是使用了硬编码也能被适配成暗黑模式。Android 10 新增的 Force Dark 强制暗黑就实现了这个功能。

Android app实现暗黑模式 安卓适配暗黑模式_文件名_02

增加了一个 forceDarkAllowed 的配置,这是 compileSdkVersion 升级到 29 新增的配置,按字面意思就是「开启强制暗黑」。 这样就已经完成配置了,在 Android 10 的机器上运行一下,切换暗黑模式,背景被强制转换成黑色了,连我们写死的色值都改了,虽然方便,但这也给我们一种不安全感。 要是 Force Dark 适配出来的颜色不是我们想要的怎么办?我们还能自定义暗黑色值吗?也是可以的。

Force Dark 自定义适配

除了主题新增了 forceDarkAllowed 这个配置,View 里面也有。 如果某个 View 的需要使用自定义色值适配暗黑模式,我们需要对这个 View 添加这个配置,让 Force Dark 排除它:

android:forceDarkAllowed="false"然后在代码里根据当前是否处于暗黑模式,对色值进行动态设置。 对于 View 的 forceDarkAllowed,有几点需要注意:

在 View 中使用这个配置的前提是,当前主题开启了 Force Dark

默认值是 true,所以设为 true 和不设是一样的

作用范围是当前 View 以及它所有的子 View

综上可以看出,其实目前并没有很好的 Force Dark 自定义方案。好在 Force Dark 的整体效果没什么大问题,就算要自定义,我们也尽量只对子 View 进行自定义。

/****************************分割线********************************/

接下来我们谈谈AndroidQ文件存储问题

临时性解决方案

...

永久性解决方案(研究中...如果有问题望提出,大家一起进步)

首先AndroidQ上不允许对公共目录直接访问和操作

AndroidQ之前我们可以使用

File file =new File(Environment.getExternalStorageDirectory() + File.separator + "文件名");

存储和操作文件

AndroidQ之后我们对于一些只需要保存 然后app内存使用的资源保存方式采用私有目录保存

File file =new File(context.getExternalFilesDir(null), "文件名");

getExternalFilesDir参数是表示文件会保存在app内部的什么类型文件夹下

默认传null为files

但是对于一些我们需要外部使用的文件资源上述存储就不能实现了

例如下载的视频和图片 拍照裁剪后保存的图片等等

以下示例为保存视频到相册

首先使用AndroidQ存储私有文件的方法存储文件

然后copy一份到相册

ContentValues contentValues =new ContentValues();
contentValues.put(MediaStore.Video.Media.DISPLAY_NAME, "文件名");
contentValues.put(MediaStore.Video.Media.MIME_TYPE, "文件类型例如video/mp4");
contentValues.put(MediaStore.Video.Media.RELATIVE_PATH, "文件存放路径例如Movies/my_video");
Uri uri = ContextUtil.getContext().getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, contentValues);
PBitmapUtils.copyFile(ContextUtil.getContext(), "私有文件的路径", uri);
//contentValues除了上述关键信息外 还有很多其他信息 如有需要请自行度娘
//如果要保存图片MediaStore.Video.Media中的Video替换为Images
//文件类型改为image/png等等 类型很多自行动态获取修改不要写死
//文件路径改为Pictures/my_image 类型很多自定动态传入
public static boolean copyFile(Context context, String sourceFilePath, final Uri insertUri) {
if (insertUri ==null) {
return false;
}
ContentResolver resolver = context.getContentResolver();
InputStream is =null;//输入流
OutputStream os =null;//输出流
try {
os = resolver.openOutputStream(insertUri);
if (os ==null) {
return false;
}
File sourceFile =new File(sourceFilePath);
if (sourceFile.exists()) {// 文件存在时
is =new FileInputStream(sourceFile); // 读入原文件
//输入流读取文件,输出流写入指定目录
return copyFileWithStream(os, is);
}
return false;
}catch (Exception e) {
e.printStackTrace();
return false;
}finally {
try {
if (is !=null) {
is.close();
}
if (os !=null) {
os.close();
}
}catch (IOException e) {
e.printStackTrace();
}
}
}
private static boolean copyFileWithStream(OutputStream os, InputStream is) {
if (os ==null || is ==null) {
return false;
}
int read =0;
while (true) {
try {
byte[] buffer =new byte[1444];
while ((read = is.read(buffer)) != -1) {
os.write(buffer, 0, read);
os.flush();
}
return true;
}catch (IOException e) {
e.printStackTrace();
return false;
}finally {
try {
os.close();
is.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
}
有人可能问不判断版本直接用androidQ的写法可不可以
也可以也不可以 contentValues中还是需要做判断的
AndroidQ以下使用MediaStore.Video.Media.Data
AndroidQ 使用MediaStore.Video.Media.RELATIVE_PATH
举报/反馈