一键定制Android-PickerView主题:从颜色到样式的全自动化方案

一键定制Android-PickerView主题:从颜色到样式的全自动化方案

【免费下载链接】Android-PickerView This is a picker view for android , support linkage effect, timepicker and optionspicker.(时间选择器、省市区三级联动) 【免费下载链接】Android-PickerView 项目地址: https://gitcode.com/gh_mirrors/an/Android-PickerView

你是否还在为Android-PickerView的主题适配而手动修改XML文件?是否因项目主题调整而不得不全局替换十几个颜色值?本文将带你实现一套动态主题生成工具,通过代码自动生成与主APP风格一致的PickerView配色方案,彻底解决主题适配的重复劳动。

读完本文你将获得

  • 掌握Android-PickerView主题构成的核心要素
  • 实现颜色值自动提取与转换的Java工具类
  • 构建支持日间/夜间模式自动切换的主题生成器
  • 学会通过Builder模式动态应用自定义主题
  • 获得可直接复用的主题生成代码库

主题适配的痛点与解决方案

Android-PickerView作为一款功能强大的选择器控件(支持时间选择器TimePickerView和选项选择器OptionsPickerView),其默认主题往往与实际项目需求存在差异。传统的主题修改方式需要开发者手动调整多个XML文件和Java代码中的颜色参数,不仅效率低下,还容易出现配色不一致的问题。

通过分析项目结构,我们发现PickerView的视觉元素主要由以下三部分控制:

mermaid

核心颜色系统解析

默认配色方案的问题

通过分析wheelview/src/main/res/values/colors.xml文件,我们发现PickerView的默认颜色定义如下:

<color name="pickerview_timebtn_nor">#057dff</color>
<color name="pickerview_timebtn_pre">#c2daf5</color>
<color name="pickerview_bg_topbar">#f5f5f5</color>
<color name="pickerview_topbar_title">#000000</color>
<color name="pickerview_wheelview_textcolor_out">#a8a8a8</color>
<color name="pickerview_wheelview_textcolor_center">#2a2a2a</color>
<color name="pickerview_wheelview_textcolor_divider">#d5d5d5</color>
<color name="pickerview_bgColor_overlay">#60000000</color>
<color name="pickerview_bgColor_default">#FFFFFFFF</color>

这些硬编码的颜色值无法与主APP的主题色自动同步。当主APP主题发生变化时(如从蓝色主题切换到绿色主题),PickerView的颜色需要手动修改,这在大型项目中是难以维护的。

颜色映射关系

理想的解决方案是建立主APP主题色到PickerView颜色的映射关系。通过分析app/src/main/res/values/colors.xml中的主色调定义:

<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>

我们可以构建如下的颜色转换规则:

PickerView颜色来源转换规则
按钮正常色(pickerview_timebtn_nor)colorPrimary直接使用
按钮按压色(pickerview_timebtn_pre)colorPrimary降低饱和度30%,提高亮度20%
标题栏背景(pickerview_bg_topbar)colorPrimary提高亮度40%
选中文字色(pickerview_wheelview_textcolor_center)colorPrimary直接使用
未选中文字色(pickerview_wheelview_textcolor_out)colorPrimary降低饱和度50%,降低亮度20%
分割线颜色(pickerview_wheelview_textcolor_divider)colorPrimary降低饱和度60%,提高亮度30%

动态主题生成工具实现

颜色转换工具类

首先,我们需要创建一个颜色转换工具类,用于根据主色调生成PickerView所需的各种衍生颜色:

public class ThemeColorGenerator {
    private int primaryColor;
    private int primaryDarkColor;
    private int accentColor;

    public ThemeColorGenerator(Context context) {
        // 从APP主题中获取主色调
        TypedValue typedValue = new TypedValue();
        context.getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true);
        primaryColor = typedValue.data;
        
        context.getTheme().resolveAttribute(R.attr.colorPrimaryDark, typedValue, true);
        primaryDarkColor = typedValue.data;
        
        context.getTheme().resolveAttribute(R.attr.colorAccent, typedValue, true);
        accentColor = typedValue.data;
    }

    /**
     * 根据主色调生成PickerView所需的所有颜色
     * @return 颜色映射表
     */
    public Map<String, Integer> generatePickerColors() {
        Map<String, Integer> colorMap = new HashMap<>();
        
        // 按钮正常色 - 直接使用主色调
        colorMap.put("timebtn_nor", primaryColor);
        
        // 按钮按压色 - 降低饱和度30%,提高亮度20%
        colorMap.put("timebtn_pre", adjustColor(primaryColor, -30, 20));
        
        // 标题栏背景 - 提高亮度40%
        colorMap.put("bg_topbar", adjustColor(primaryColor, 0, 40));
        
        // 标题文字色 - 如果背景是亮色则使用深色文字,反之亦然
        colorMap.put("topbar_title", isLightColor(colorMap.get("bg_topbar")) ? 0xFF000000 : 0xFFFFFFFF);
        
        // 选中文字色 - 使用主色调
        colorMap.put("wheelview_textcolor_center", primaryColor);
        
        // 未选中文字色 - 降低饱和度50%,降低亮度20%
        colorMap.put("wheelview_textcolor_out", adjustColor(primaryColor, -50, -20));
        
        // 分割线颜色 - 降低饱和度60%,提高亮度30%
        colorMap.put("wheelview_textcolor_divider", adjustColor(primaryColor, -60, 30));
        
        // 遮罩层颜色 - 使用默认值
        colorMap.put("bgColor_overlay", 0x60000000);
        
        // 背景色 - 使用白色或黑色(根据主题模式)
        colorMap.put("bgColor_default", isLightTheme() ? 0xFFFFFFFF : 0xFF212121);
        
        return colorMap;
    }

    /**
     * 调整颜色的饱和度和亮度
     * @param color 原始颜色
     * @param satAdjust 饱和度调整值 (-100 to 100)
     * @param lightAdjust 亮度调整值 (-100 to 100)
     * @return 调整后的颜色
     */
    private int adjustColor(int color, int satAdjust, int lightAdjust) {
        float[] hsv = new float[3];
        Color.colorToHSV(color, hsv);
        
        // 调整饱和度
        hsv[1] = Math.max(0, Math.min(1, hsv[1] * (100 + satAdjust) / 100));
        
        // 调整亮度
        hsv[2] = Math.max(0, Math.min(1, hsv[2] * (100 + lightAdjust) / 100));
        
        return Color.HSVToColor(Color.alpha(color), hsv);
    }
    
    /**
     * 判断颜色是否为亮色
     */
    private boolean isLightColor(int color) {
        return Color.luminance(color) > 0.5;
    }
    
    /**
     * 判断当前是否为浅色主题
     */
    private boolean isLightTheme() {
        return isLightColor(primaryColor);
    }
}

尺寸系统适配

除了颜色,尺寸系统也需要根据APP的整体设计进行适配。通过分析pickerview/src/main/res/values/dimens.xmlwheelview/src/main/res/values/dimens.xml,我们发现PickerView的尺寸定义如下:

<!-- 文字大小 -->
<dimen name="pickerview_topbar_btn_textsize">17sp</dimen>
<dimen name="pickerview_topbar_title_textsize">18sp</dimen>
<dimen name="pickerview_textsize">20sp</dimen>

<!-- 间距 -->
<dimen name="pickerview_topbar_height">44dp</dimen>
<dimen name="pickerview_topbar_padding">20dp</dimen>

我们可以创建一个尺寸适配工具类,根据设备屏幕密度和用户字体大小偏好动态调整这些值:

public class ThemeDimensionGenerator {
    private Context context;
    private float fontScale;
    
    public ThemeDimensionGenerator(Context context) {
        this.context = context;
        // 获取用户字体大小偏好
        fontScale = context.getResources().getConfiguration().fontScale;
    }
    
    /**
     * 生成适配后的尺寸值
     * @return 尺寸映射表
     */
    public Map<String, Float> generateDimensions() {
        Map<String, Float> dimensionMap = new HashMap<>();
        
        // 根据用户字体偏好调整文字大小
        dimensionMap.put("topbar_btn_textsize", 17 * fontScale);
        dimensionMap.put("topbar_title_textsize", 18 * fontScale);
        dimensionMap.put("textsize", 20 * fontScale);
        
        // 固定尺寸(不受字体大小影响)
        dimensionMap.put("topbar_height", dpToPx(44));
        dimensionMap.put("topbar_padding", dpToPx(20));
        
        return dimensionMap;
    }
    
    /**
     * dp转px
     */
    private float dpToPx(float dp) {
        return dp * context.getResources().getDisplayMetrics().density;
    }
}

主题应用工具类

最后,我们需要一个主题应用工具类,将生成的颜色和尺寸应用到PickerView中。通过分析PickerOptions.javaOptionsPickerBuilder.javaTimePickerBuilder.java,我们发现PickerView提供了丰富的样式设置方法:

public class PickerThemeApplier {
    private ThemeColorGenerator colorGenerator;
    private ThemeDimensionGenerator dimensionGenerator;
    private Map<String, Integer> colorMap;
    private Map<String, Float> dimensionMap;
    
    public PickerThemeApplier(Context context) {
        colorGenerator = new ThemeColorGenerator(context);
        dimensionGenerator = new ThemeDimensionGenerator(context);
        colorMap = colorGenerator.generatePickerColors();
        dimensionMap = dimensionGenerator.generateDimensions();
    }
    
    /**
     * 应用主题到时间选择器
     */
    public void applyToTimePicker(TimePickerBuilder builder) {
        // 应用颜色
        builder.setSubmitColor(colorMap.get("timebtn_nor"))
               .setCancelColor(colorMap.get("timebtn_nor"))
               .setTitleColor(colorMap.get("topbar_title"))
               .setBgColor(colorMap.get("bgColor_default"))
               .setTitleBgColor(colorMap.get("bg_topbar"))
               .setTextColorCenter(colorMap.get("wheelview_textcolor_center"))
               .setTextColorOut(colorMap.get("wheelview_textcolor_out"))
               .setDividerColor(colorMap.get("wheelview_textcolor_divider"));
        
        // 应用尺寸
        builder.setSubCalSize(dimensionMap.get("topbar_btn_textsize").intValue())
               .setTitleSize(dimensionMap.get("topbar_title_textsize").intValue())
               .setContentTextSize(dimensionMap.get("textsize").intValue());
    }
    
    /**
     * 应用主题到选项选择器
     */
    public void applyToOptionsPicker(OptionsPickerBuilder builder) {
        // 应用颜色
        builder.setSubmitColor(colorMap.get("timebtn_nor"))
               .setCancelColor(colorMap.get("timebtn_nor"))
               .setTitleColor(colorMap.get("topbar_title"))
               .setBgColor(colorMap.get("bgColor_default"))
               .setTitleBgColor(colorMap.get("bg_topbar"))
               .setTextColorCenter(colorMap.get("wheelview_textcolor_center"))
               .setTextColorOut(colorMap.get("wheelview_textcolor_out"))
               .setDividerColor(colorMap.get("wheelview_textcolor_divider"));
        
        // 应用尺寸
        builder.setSubCalSize(dimensionMap.get("topbar_btn_textsize").intValue())
               .setTitleSize(dimensionMap.get("topbar_title_textsize").intValue())
               .setContentTextSize(dimensionMap.get("textsize").intValue());
    }
}

实际应用示例

集成到项目中

使用这个主题生成工具非常简单,只需在创建PickerView时添加几行代码:

// 创建主题生成器
ThemeApplier themeApplier = new ThemeApplier(this);

// 创建时间选择器并应用主题
TimePickerBuilder timeBuilder = new TimePickerBuilder(this, new OnTimeSelectListener() {
    @Override
    public void onTimeSelect(Date date, View v) {
        // 时间选择回调
        Toast.makeText(MainActivity.this, getTime(date), Toast.LENGTH_SHORT).show();
    }
});
// 应用主题
themeApplier.applyToTimePicker(timeBuilder);
// 其他配置
timeBuilder.setType(new boolean[]{true, true, true, true, true, true})
           .isDialog(true);
TimePickerView pvTime = timeBuilder.build();

// 创建选项选择器并应用主题
OptionsPickerBuilder optionsBuilder = new OptionsPickerBuilder(this, new OnOptionsSelectListener() {
    @Override
    public void onOptionsSelect(int options1, int options2, int options3, View v) {
        // 选项选择回调
        String tx = options1Items.get(options1).getPickerViewText()
                  + options2Items.get(options1).get(options2);
        btn_Options.setText(tx);
    }
});
// 应用主题
themeApplier.applyToOptionsPicker(optionsBuilder);
// 其他配置
optionsBuilder.setTitleText("城市选择")
              .setSelectOptions(0, 1);
OptionsPickerView pvOptions = optionsBuilder.build();

主题切换效果

通过这个工具,PickerView可以自动适配APP的主题变化。以下是不同主题下的效果对比:

mermaid

高级功能:主题切换与保存

支持动态主题切换

为了支持运行时主题切换,我们可以扩展工具类,添加主题切换功能:

/**
 * 切换到指定主题
 * @param themeType 主题类型:0-默认,1-深色,2-自定义
 * @param customPrimaryColor 自定义主题的主色调,当themeType=2时生效
 */
public void switchTheme(int themeType, int customPrimaryColor) {
    switch (themeType) {
        case 0: // 默认主题
            primaryColor = ContextCompat.getColor(context, R.color.colorPrimary);
            break;
        case 1: // 深色主题
            primaryColor = 0xFF333333;
            break;
        case 2: // 自定义主题
            primaryColor = customPrimaryColor;
            break;
    }
    // 重新生成颜色映射
    colorMap = generatePickerColors();
}

保存和恢复主题设置

我们还可以添加SharedPreferences支持,保存用户的主题偏好:

/**
 * 保存主题设置到SharedPreferences
 */
public void saveThemeSettings(int themeType, int customColor) {
    SharedPreferences sp = context.getSharedPreferences("theme_settings", Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = sp.edit();
    editor.putInt("theme_type", themeType);
    editor.putInt("custom_color", customColor);
    editor.apply();
}

/**
 * 从SharedPreferences恢复主题设置
 */
public void restoreThemeSettings() {
    SharedPreferences sp = context.getSharedPreferences("theme_settings", Context.MODE_PRIVATE);
    int themeType = sp.getInt("theme_type", 0);
    int customColor = sp.getInt("custom_color", 0xFF3F51B5);
    switchTheme(themeType, customColor);
}

总结与展望

通过本文介绍的动态主题生成工具,我们解决了Android-PickerView主题适配的痛点,实现了以下目标:

  1. 自动化:自动从APP主题提取颜色,无需手动修改多个文件
  2. 一致性:确保PickerView与APP整体风格保持一致
  3. 灵活性:支持动态主题切换和用户自定义
  4. 可维护性:集中管理主题相关代码,降低维护成本

未来,我们可以进一步扩展这个工具,添加以下功能:

  • 支持更多自定义属性,如字体、圆角半径等
  • 添加主题预览功能,让用户实时看到主题效果
  • 集成Material Design 3的动态颜色系统

项目地址

仓库地址:https://gitcode.com/gh_mirrors/an/Android-PickerView

通过这个动态主题生成工具,你可以轻松实现Android-PickerView与APP主题的完美融合,为用户提供更加一致和专业的视觉体验。现在就将它集成到你的项目中,告别繁琐的手动主题适配吧!

【免费下载链接】Android-PickerView This is a picker view for android , support linkage effect, timepicker and optionspicker.(时间选择器、省市区三级联动) 【免费下载链接】Android-PickerView 项目地址: https://gitcode.com/gh_mirrors/an/Android-PickerView

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值