Flutter色彩障碍辅助插件color_blindness的使用

发布于 1周前 作者 nodeper 来自 Flutter

Flutter色彩障碍辅助插件 color_blindness 的使用

在开发Flutter应用时,确保应用程序的颜色对所有用户都具有可访问性是非常重要的。为了帮助开发者更好地实现这一目标,可以使用 color_blindness 插件来模拟色盲效果,并进行对比度测试。

插件功能

  1. 更改整个主题:通过包装 ColorScheme 来调用 colorBlindnessColorScheme()
  2. 用于CI测试:使用 colorBlindnessAssertContrast() 进行对比度测试。
  3. 修改单个颜色:可以通过 colorBlindness() 或直接调用特定的方法(如 tritanopia())来修改单个颜色。

使用步骤

添加依赖

首先,在你的 pubspec.yaml 文件中添加 color_blindness 依赖:

dependencies:
  color_blindness: ^VERSION

请将 ^VERSION 替换为最新版本号。

包装 ColorScheme

在你的项目中,只需将 ColorScheme.dark(...) 包装到 colorBlindnessColorScheme() 中:

import 'package:color_blindness/color_blindness.dart';

Theme(
  data: ThemeData(
    colorScheme: colorBlindnessColorScheme(ColorScheme.dark(), ColorBlindnessType.tritanopia),
  ),
  child: MyApp(),
)

CI 测试

你可以添加一个测试来确保 ColorScheme 始终是可访问的。第二个参数是 WCAG 最小阈值,通常至少为 4.5:

colorScheme = ColorScheme.light(
  primary: const Color(0xff9f0042),
  secondary: const Color(0xff1e6100),
);
expect(() => colorBlindnessAssertContrast(colorScheme, 4.0), returnsNormally);

修改单个颜色

你可以使用 colorBlindness() 并传入 ColorBlindnessType 作为第二个参数,或者直接调用方法:

const primary = const Color(0xff9f0042);

// 间接方式
colorBlindness(primary, ColorBlindnessType.tritanopia);

// 直接方式
tritanopia(primary);

示例 Demo

以下是一个完整的示例,展示了如何在实际项目中使用 color_blindness 插件:

import 'package:color_blindness/color_blindness.dart';
import 'package:flutter/material.dart';
import 'package:random_color_scheme/random_color_scheme.dart';
import 'package:url_launcher/url_launcher.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Color Blindness',
      home: const RefreshableHome(),
      theme: ThemeData(
        colorScheme: const ColorScheme.light(
          primary: Color(0xffC2410C),
        ),
      ),
    );
  }
}

class RefreshableHome extends StatelessWidget {
  const RefreshableHome({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      body: const ThemeScreen(),
      appBar: AppBar(
        backgroundColor: Colors.white,
        title: const Text(
          "Color Blindness Color Scheme",
          style: TextStyle(color: Colors.black),
        ),
        actions: [
          IconButton(
            icon: const Icon(Icons.code_rounded, color: Colors.black),
            tooltip: "Source",
            onPressed: () async {
              await launchUrl(Uri.parse("https://github.com/bernaferrari/ColorBlindnessFlutter"));
            },
          )
        ],
        elevation: 0,
      ),
    );
  }
}

class ThemeScreen extends StatefulWidget {
  const ThemeScreen({Key? key}) : super(key: key);

  [@override](/user/override)
  State<ThemeScreen> createState() => _ThemeScreenState();
}

class _ThemeScreenState extends State<ThemeScreen> {
  double sliderValue = 0;
  ColorBlindnessType typeSelected = ColorBlindnessType.none;
  int seed = 0;

  Theme customThemeChild({required int i, required bool isDark}) {
    return Theme(
      data: ThemeData(
        colorScheme: colorBlindnessColorScheme(
          randomColorScheme(seed: i + seed, isDark: isDark, shouldPrint: false),
          typeSelected,
        ),
        outlinedButtonTheme: OutlinedButtonThemeData(
          style: OutlinedButton.styleFrom(
            shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
          ),
        ),
        cardTheme: CardTheme(
          elevation: 0,
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
        ),
      ),
      child: const ThemeItem(),
    );
  }

  String typesToStr() {
    final str = typeSelected.toString().substring(19);
    return str[0].toUpperCase() + str.substring(1);
  }

  String affectedToStr() {
    const m = "of males";
    const f = "of females";
    const p = "of population";

    switch (typeSelected) {
      case ColorBlindnessType.none:
        return "most of the population";
      case ColorBlindnessType.protanomaly:
        return "1% $m, 01% $f";
      case ColorBlindnessType.deuteranomaly:
        return "6% $m, 0.4% $f";
      case ColorBlindnessType.tritanomaly:
        return "01% $p";
      case ColorBlindnessType.protanopia:
        return "1% $m";
      case ColorBlindnessType.deuteranopia:
        return "1% $m";
      case ColorBlindnessType.tritanopia:
        return "less than 1% $p";
      case ColorBlindnessType.achromatopsia:
        return "003% $p";
      case ColorBlindnessType.achromatomaly:
        return "001% $p";
      default:
        return "";
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    final condition = MediaQuery.of(context).size.width > 950;

    return Padding(
      padding: const EdgeInsets.all(4),
      child: SingleChildScrollView(
        child: Column(
          children: [
            Card(
              elevation: 0,
              color: const Color(0xffFFF7ED),
              shape: RoundedRectangleBorder(
                side: const BorderSide(width: 2, color: Color(0xffFED7AA)),
                borderRadius: BorderRadius.circular(8),
              ),
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Text(
                  """
This is the sample for a library.
The idea is for you to plug colorBlindnessColorScheme() into your apps.""",
                  style: Theme.of(context).textTheme.titleSmall,
                  textAlign: TextAlign.center,
                ),
              ),
            ),
            const SizedBox(height: 24),
            Text(
              typesToStr(),
              style: Theme.of(context).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.w600),
              textAlign: TextAlign.center,
            ),
            Text(
              affectedToStr(),
              style: Theme.of(context).textTheme.titleSmall,
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 8),
            ConstrainedBox(
              constraints: const BoxConstraints(maxWidth: 400),
              child: Slider(
                min: 0,
                max: 7,
                divisions: 7,
                value: sliderValue,
                onChanged: (value) {
                  setState(() {
                    sliderValue = value;
                    typeSelected = ColorBlindnessType.values[sliderValue.toInt()];
                  });
                },
              ),
            ),
            ElevatedButton.icon(
              style: ElevatedButton.styleFrom(
                padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
                shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
              ),
              label: const Text("Randomize Themes"),
              icon: const Icon(Icons.shuffle_rounded, size: 16),
              onPressed: () {
                setState(() {
                  seed += 4;
                });
              },
            ),
            const SizedBox(height: 16),
            for (int i = 0; i < 3; i++)
              Flex(
                direction: condition ? Axis.horizontal : Axis.vertical,
                children: [
                  Flexible(
                    flex: condition ? 1 : 0,
                    child: customThemeChild(i: i, isDark: true),
                  ),
                  Flexible(
                    flex: condition ? 1 : 0,
                    child: customThemeChild(i: i, isDark: false),
                  ),
                ],
              ),
          ],
        ),
      ),
    );
  }
}

class ThemeItem extends StatelessWidget {
  const ThemeItem({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Card(
      color: Theme.of(context).colorScheme.surface,
      elevation: 0,
      child: const Row(
        children: [
          Expanded(child: SocialPreview()),
          Expanded(child: ChatPreview()),
        ],
      ),
    );
  }
}

更多关于Flutter色彩障碍辅助插件color_blindness的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter色彩障碍辅助插件color_blindness的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中集成和使用color_blindness插件的一个示例。这个插件可以帮助你调整应用的色彩方案,以更好地支持色盲用户。

首先,你需要在pubspec.yaml文件中添加color_blindness依赖:

dependencies:
  flutter:
    sdk: flutter
  color_blindness: ^latest_version  # 请替换为最新的版本号

然后,运行flutter pub get来安装依赖。

接下来,在你的Dart代码中,你可以按照以下步骤来使用这个插件:

  1. 导入包
import 'package:flutter/material.dart';
import 'package:color_blindness/color_blindness.dart';
  1. 定义一个辅助函数来调整颜色

你可以创建一个函数来调整颜色,以适应不同的色盲类型。例如:

Color adjustColorForColorBlindness(Color color, ColorBlindnessType type) {
  ColorBlindness colorBlindness = ColorBlindness(type);
  return colorBlindness.transform(color);
}
  1. 在Widget中使用调整后的颜色

下面是一个简单的示例,展示如何在Container中使用调整后的颜色:

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Color Blindness Example'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Container(
                width: 100,
                height: 100,
                color: adjustColorForColorBlindness(Colors.red, ColorBlindnessType.protanopia),
                child: Center(child: Text('Protanopia')),
              ),
              SizedBox(height: 20),
              Container(
                width: 100,
                height: 100,
                color: adjustColorForColorBlindness(Colors.red, ColorBlindnessType.deuteranopia),
                child: Center(child: Text('Deuteranopia')),
              ),
              SizedBox(height: 20),
              Container(
                width: 100,
                height: 100,
                color: adjustColorForColorBlindness(Colors.red, ColorBlindnessType.tritanopia),
                child: Center(child: Text('Tritanopia')),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

在这个示例中,我们定义了三个不同颜色的Container,每个Container都使用adjustColorForColorBlindness函数来调整颜色,以适应不同类型的色盲(红色盲、绿色盲和蓝色盲)。

注意:ColorBlindnessType是一个枚举,包含了不同的色盲类型,例如protanopia(红色盲)、deuteranopia(绿色盲)和tritanopia(蓝色盲)等。

这个示例展示了如何在Flutter应用中使用color_blindness插件来调整颜色,以提高应用对色盲用户的友好性。你可以根据具体需求进一步扩展这个示例。

回到顶部