Android O 新特性 系统主题

一.系统主题介绍

android P都已经出来好久了,今天在使用Android P过程中发现在Dislpay下面有一个主题设置(Device theme)

如下所示
在这里插入图片描述
可以看出一个有3个选项,通过使用后发现,他运行用户设置手机主题,跟app主题不一样,这里的主题设置可以供系统以及所有应用查询.系统主题一共有暗和亮两张状态.上面设置中3个选项代表的意义如下:

  1. Automatic (base on wallpaper):系统检查当前设置的手机壁纸属于暗还是亮,然后更具判断设置主题
  2. Light:设置亮主题
  3. Dark:设置暗主题

设置亮主题:

在这里插入图片描述
设置暗主题:
在这里插入图片描述

这样看效果还是挺明显的.通过源码发现,目前系统上launche和SystemUI监听了系统主题的状态,然后显示系统的主题,其他app如果需要根据系统当前主题,也需要实时监听主题变化,

二.如何实现系统主题

个人app要监听系统主题,直接使用WallpaperManager,addOnColorsChangedListener方法,通过listener回调
实现步奏如下:

step1:获取WallpaperManager
            if (wallpaperManager == null) {
                wallpaperManager = WallpaperManager.getInstance(context.getApplicationContext());
            }

调用WallpaperManager的单例,实际上就是getSystemService

    public static WallpaperManager getInstance(Context context) {
        return (WallpaperManager)context.getSystemService(
                Context.WALLPAPER_SERVICE);
    }
step2:监听主题变化

这个回调方法会在主题切换中触发,下面是触发后调用的方法

WallpaperManager.OnColorsChangedListener  onColorsChangedListener = new WallpaperManager.OnColorsChangedListener(){
    @Override
    public void onColorsChanged(WallpaperColors colors, int which) {//1
        if (WallpaperManager.FLAG_SYSTEM ==  which) {//2
                updateTheme(colors);
        }
     }
};
wallpaperManager.addOnColorsChangedListener(onColorsChangedListene, null);//3
WallpaperColors colorsSystem = wallpaperManager.getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
updateTheme(colorsSystem);//4
  • 3.处是监听主题变化,第二个参数是handler,如果选择null.表示主线程的looper对应的hander
  • 1处返回两个参数WallpaperColors,which;WallpaperColors可以判断属于亮还是暗主题,which表示锁屏(WallpaperManager.FLAG_LOCK)还是系统(WallpaperManager.FLAG_SYSTEM),因为主题设置有一个Automatic (base on wallpaper)选项,而锁屏壁纸和桌面壁纸可以不一样,那么换壁纸的时候,会有差异.一般app是参考系统(WallpaperManager.FLAG_SYSTEM)这个配置主题,如2处
  • 4处,因为主题回调是在切换主题才会进行,app开始运行的时候,需要回去当时的主题

因为系统主题是在android O上才有的,如果要app最低版本是android O以下,请做判断

 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O_MR1) {
 }
step3:判断主题是亮还是暗

下面是SystemUI判断主题的代码片段

public void updateTheme(WallpaperColors colors) {
            final boolean useDarkTheme = colors != null
                    && (colors.getColorHints() & HINT_SUPPORTS_DARK_THEME) != 0;
}

打印log可以发现colors.getColorHints()在亮的时候是4,暗的时候是6,而HINT_SUPPORTS_DARK_THEME == 2
在这里插入图片描述
WallpaperColors这个类很多方法被hide修饰,包括getColorHints方法,导致非系统无法调用,如图
在这里插入图片描述
Android P后面又限制通过反射来调用系统API,直接调用这个方法是没戏了,但是这个类的toString方法又把这个值给打印出来了.
在这里插入图片描述
我们可以截取这个值,然后在判断,于是修改上面的判断

public void updateTheme(WallpaperColors colors) {
            final boolean useDarkTheme = colors != null
                    && (getColorHints(colors) & HINT_SUPPORTS_DARK_THEME) != 0;
}

private int getColorHints(WallpaperColors colors) {
        String str = colors.toString();
        int index = str.lastIndexOf("h: ");
        String val = str.substring(index + 3, str.length() - 1);
        if (TextUtils.isDigitsOnly(val)) {
            return Integer.valueOf(val);
        }
        Log.e(TAG, "can not get getColorHints!!");
        return 0;
    }

改法不优雅,只能将就使用了

step4:退出监听
 wallpaperManager.removeOnColorsChangedListener(onColorsChangedListener);

三.介绍WallpaperColors类

WallpaperColors源码解释:Provides information about the colors of a wallpaper.这个记录壁纸的color
WallpaperColors有几个有意思的方法

方法 返回类型 意义
getPrimaryColor() Color 获取墙纸最具视觉代表性的颜色。
getSecondaryColor() Color 获得了壁纸的第二个最卓越的颜色。
getTertiaryColor() Color 获得了壁纸的第三个最卓越的颜色。
getMainColors() List of Color 按重要性排序的最杰出的颜色列表。
getColorHints() int 壁纸颜色提示的组合。(暗或者亮)
calculateDarkHints(Bitmap source) int 根据传入的Bitmap,检查图像是否足够明亮
fromBitmap(@NonNull Bitmap bitmap) WallpaperColors 根据传入的Bitmap,检查图像返回WallpaperColors
fromDrawable(Drawable drawable) WallpaperColors 根据传入的Drawable,检查图像返回WallpaperColors

四.分享一个封装好的类

import android.app.WallpaperColors;
import android.app.WallpaperManager;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;

public final class ColorExtractor {

    public interface ColorsChange {
        public void themeChange(boolean useDarkTheme);
    }

    private static ColorExtractor colorExtractor;
    private static final String TAG = "ColorExtractor";
    private WallpaperManager wallpaperManager;
    private static final int HINT_SUPPORTS_DARK_THEME = 1 << 1;
    private WallpaperManager.OnColorsChangedListener onColorsChangedListene;
    private List<ColorsChange> listens;

    private ColorExtractor() {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O_MR1) {
            onColorsChangedListene = new WallpaperManager.OnColorsChangedListener() {
                @Override
                public void onColorsChanged(WallpaperColors colors, int which) {
                    if (which == WallpaperManager.FLAG_SYSTEM) {
                        final boolean useDarkTheme = colors != null
                                && (getColorHints(colors) & HINT_SUPPORTS_DARK_THEME) != 0;
                        if (listens != null && listens.size() > 0) {
                            for (ColorsChange colorsChange : listens) {
                                colorsChange.themeChange(useDarkTheme);
                            }
                        }
                    }

                }
            };
        }
        listens = new ArrayList<>();
    }

    public static ColorExtractor getInstance() {
        if (colorExtractor == null) {
            colorExtractor = new ColorExtractor();
        }
        return colorExtractor;
    }

    public void startListen(Context context) {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O_MR1) {
            if (wallpaperManager == null) {
                wallpaperManager = WallpaperManager.getInstance(context.getApplicationContext());
            }
            WallpaperColors colorsSystem = wallpaperManager.getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
            final boolean useDarkTheme = colorsSystem != null
                    && (getColorHints(colorsSystem) & HINT_SUPPORTS_DARK_THEME) != 0;
            if (listens != null && listens.size() > 0) {
                for (ColorsChange colorsChange : listens) {
                    colorsChange.themeChange(useDarkTheme);
                }
            }
            wallpaperManager.addOnColorsChangedListener(onColorsChangedListene, null);
        }
    }



    public void addThemeChange(ColorsChange colorsChange) {
        if (!listens.contains(colorsChange)) {
            listens.add(colorsChange);
        }
    }

    public void removeThemeChange(ColorsChange colorsChange) {
        if (listens.contains(colorsChange)) {
            listens.remove(colorsChange);
        }
    }


    public void stopListen() {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O_MR1) {
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O_MR1) {
                wallpaperManager.removeOnColorsChangedListener(onColorsChangedListene);
            }
            if (listens != null) {
                listens.clear();
            }
        }

    }


    private int getColorHints(WallpaperColors colors) {
        String str = colors.toString();

        int index = str.lastIndexOf("h: ");
        String val = str.substring(index + 3, str.length() - 1);
        if (TextUtils.isDigitsOnly(val)) {
            return Integer.valueOf(val);
        }

        Log.e(TAG, "can not get getColorHints!!");
        return 0;
    }
}
使用方法:
//单例实例化
ColorExtractor colorExtractor = ColorExtractor.getInstance();
//注册监听事件,因为WallpaperManager注册的时候会调用初始主题,所以为了能获取初始值,所以在开始addThemeChange之前先注册监听事件.
colorExtractor.addThemeChange(new ColorExtractor.ColorsChange() {
    @Override
    public void themeChange(boolean useDarkTheme) {
        Log.i(TAG, "useDarkTheme[" + useDarkTheme + "]");
    }
});
//开始监听;一般在onStart(或onCreate)方法
colorExtractor.startListen(this);
//结束监听,一般在onStop(或onDestory)方法
colorExtractor.stopListen();
发布了67 篇原创文章 · 获赞 42 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/w1764662543/article/details/99955628