Flutter 三方库 cached_network_image 的鸿蒙化适配与实战指南
欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net

本文详细介绍如何在Flutter鸿蒙应用中实现一个功能丰富的颜色选择器,支持RGB滑块调节、HEX颜色代码显示和预设颜色选择。

一、前言

颜色选择器是设计工具和主题定制应用中的核心组件。无论是UI设计、主题配置、还是个性化设置,都需要一个直观易用的颜色选择器。本文将介绍如何在Flutter鸿蒙应用中实现一个支持RGB调节、HEX代码显示、预设颜色的颜色选择器组件。

二、效果展示

在这里插入图片描述

2.1 功能特性

功能 描述
RGB滑块 分别调节红、绿、蓝三色通道
实时预览 颜色变化实时显示
HEX代码 显示十六进制颜色代码
一键复制 复制颜色代码到剪贴板
预设颜色 快速选择常用颜色
智能文字 根据背景色自动调整文字颜色

三、项目背景与目标

3.1 项目背景

在设计工具、主题定制、个性化设置等场景中,颜色选择是必不可少的操作。一个优秀的颜色选择器可以帮助用户快速找到心仪的颜色,提升用户体验。

3.2 项目目标

  • 实现RGB三通道调节
  • 支持HEX颜色代码显示
  • 提供预设颜色快速选择
  • 支持鸿蒙平台运行

四、技术架构设计

4.1 整体架构

┌─────────────────────────────────────┐
│           UI Layer (Widgets)         │
│  ┌──────────┐  ┌──────────┐         │
│  │  Slider  │  │   Card   │         │
│  └──────────┘  └──────────┘         │
├─────────────────────────────────────┤
│        State Management              │
│  ┌──────────────────────────────┐   │
│  │    StatefulWidget + State    │   │
│  └──────────────────────────────┘   │
├─────────────────────────────────────┤
│         Business Logic              │
│  ┌────────────┐  ┌───────────────┐  │
│  │   Color    │  │   Clipboard   │  │
│  │  Generator │  │    Service    │  │
│  └────────────┘  └───────────────┘  │
└─────────────────────────────────────┘

4.2 核心数据结构

double _red = 0;
double _green = 0;
double _blue = 0;
late Color _selectedColor;

五、详细实现

5.1 Flutter端实现

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class ColorPickerPage extends StatefulWidget {
  const ColorPickerPage({super.key});

  
  State<ColorPickerPage> createState() => _ColorPickerPageState();
}

class _ColorPickerPageState extends State<ColorPickerPage> {
  double _red = 0;
  double _green = 0;
  double _blue = 0;
  late Color _selectedColor;

  
  void initState() {
    super.initState();
    _selectedColor = Color.fromRGBO(_red, _green, _blue, 1.0);
  }

  void _updateColor() {
    setState(() {
      _selectedColor = Color.fromRGBO(_red.round(), _green.round(), _blue.round(), 1.0);
    });
  }

  String _getHexColor() {
    return '#${_selectedColor.value.toRadixString(16).substring(2).toUpperCase()}';
  }

  void _copyToClipboard() {
    Clipboard.setData(ClipboardData(text: _getHexColor()));
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('颜色代码已复制到剪贴板')),
    );
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('颜色选择器'),
        centerTitle: true,
        backgroundColor: Colors.deepPurple,
        foregroundColor: Colors.white,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            Card(
              child: Container(
                height: 200,
                decoration: BoxDecoration(
                  color: _selectedColor,
                  borderRadius: BorderRadius.circular(12),
                ),
                child: Center(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Text(
                        _getHexColor(),
                        style: TextStyle(
                          fontSize: 32,
                          fontWeight: FontWeight.bold,
                          color: _selectedColor.computeLuminance() > 0.5
                              ? Colors.black
                              : Colors.white,
                        ),
                      ),
                      const SizedBox(height: 16),
                      ElevatedButton.icon(
                        onPressed: _copyToClipboard,
                        icon: const Icon(Icons.copy),
                        label: const Text('复制颜色代码'),
                        style: ElevatedButton.styleFrom(
                          backgroundColor: _selectedColor.computeLuminance() > 0.5
                              ? Colors.black
                              : Colors.white,
                          foregroundColor: _selectedColor,
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),
            const SizedBox(height: 24),
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Column(
                  children: [
                    _buildColorSlider(
                      label: '红色',
                      value: _red,
                      color: Colors.red,
                      onChanged: (value) {
                        _red = value;
                        _updateColor();
                      },
                    ),
                    const SizedBox(height: 16),
                    _buildColorSlider(
                      label: '绿色',
                      value: _green,
                      color: Colors.green,
                      onChanged: (value) {
                        _green = value;
                        _updateColor();
                      },
                    ),
                    const SizedBox(height: 16),
                    _buildColorSlider(
                      label: '蓝色',
                      value: _blue,
                      color: Colors.blue,
                      onChanged: (value) {
                        _blue = value;
                        _updateColor();
                      },
                    ),
                  ],
                ),
              ),
            ),
            const SizedBox(height: 24),
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text(
                      '预设颜色',
                      style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                    ),
                    const SizedBox(height: 16),
                    Wrap(
                      spacing: 8,
                      runSpacing: 8,
                      children: [
                        Colors.red,
                        Colors.green,
                        Colors.blue,
                        Colors.yellow,
                        Colors.purple,
                        Colors.orange,
                        Colors.pink,
                        Colors.teal,
                      ].map((color) {
                        return GestureDetector(
                          onTap: () {
                            setState(() {
                              _red = color.red.toDouble();
                              _green = color.green.toDouble();
                              _blue = color.blue.toDouble();
                              _selectedColor = color;
                            });
                          },
                          child: Container(
                            width: 50,
                            height: 50,
                            decoration: BoxDecoration(
                              color: color,
                              shape: BoxShape.circle,
                              border: Border.all(
                                color: _selectedColor == color
                                    ? Colors.black
                                    : Colors.transparent,
                                width: 3,
                              ),
                            ),
                          ),
                        );
                      }).toList(),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildColorSlider({
    required String label,
    required double value,
    required Color color,
    required ValueChanged<double> onChanged,
  }) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          '$label: ${value.round()}',
          style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
        ),
        Slider(
          value: value,
          min: 0,
          max: 255,
          divisions: 255,
          activeColor: color,
          onChanged: onChanged,
        ),
      ],
    );
  }
}

5.2 UI界面实现

UI界面采用Material Design 3设计风格,主要包含以下组件:

  1. 颜色预览区:使用Card组件展示当前选择的颜色
  2. RGB滑块:使用Slider组件分别调节红、绿、蓝三通道
  3. 预设颜色:使用Wrap布局展示预设颜色圆形按钮

六、核心功能解析

6.1 颜色生成

根据RGB值生成Color对象:

void _updateColor() {
  setState(() {
    _selectedColor = Color.fromRGBO(_red.round(), _green.round(), _blue.round(), 1.0);
  });
}

6.2 HEX代码转换

将Color转换为十六进制字符串:

String _getHexColor() {
  return '#${_selectedColor.value.toRadixString(16).substring(2).toUpperCase()}';
}

6.3 智能文字颜色

根据背景色亮度自动调整文字颜色:

color: _selectedColor.computeLuminance() > 0.5
    ? Colors.black
    : Colors.white,

computeLuminance()返回0.0到1.0之间的值,大于0.5表示颜色较亮,使用黑色文字;否则使用白色文字。

七、实际应用场景

7.1 设计工具

在设计工具中选择颜色,用于UI设计、图形设计等。

7.2 主题定制

在应用设置中自定义主题颜色,实现个性化配置。

7.3 绘画应用

在绘画应用中选择画笔颜色。

7.4 标签颜色

在标签管理中为标签选择颜色。

八、优化建议

8.1 功能扩展

  • 添加HSL颜色模式
  • 支持透明度调节
  • 添加颜色历史记录
  • 支持颜色名称显示

8.2 用户体验优化

  • 添加颜色预览动画
  • 支持手势选择颜色
  • 添加颜色对比度提示
  • 支持颜色收藏功能

8.3 性能优化

  • 使用防抖处理滑块变化
  • 优化颜色计算性能
  • 添加颜色缓存

九、常见问题与解决方案

9.1 颜色精度问题

问题:Slider的divisions可能导致颜色不够精确

解决方案:设置divisions为255,确保每个整数值都可以选择

9.2 HEX代码格式问题

问题:Color.value包含Alpha通道,需要截取

解决方案:使用substring(2)截取RGB部分

'#${_selectedColor.value.toRadixString(16).substring(2).toUpperCase()}'

9.3 预设颜色比较问题

问题:预设颜色选择后边框不显示

解决方案:使用_selectedColor == color进行精确比较

十、总结

本文详细介绍了如何在Flutter鸿蒙应用中实现一个功能丰富的颜色选择器组件。通过合理的架构设计和清晰的代码实现,我们成功创建了一个支持RGB调节、HEX代码显示、预设颜色选择的实用组件。该组件可以广泛应用于设计工具、主题定制、绘画应用等场景,为用户提供便捷的颜色选择服务。

十一、参考资料

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐