MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Flutter Cupertino Design组件开发实践

2024-05-223.9k 阅读

Flutter Cupertino Design 组件开发基础

Cupertino Design 简介

Flutter 中的 Cupertino Design 是模仿 iOS 设计风格的一套组件库。它为开发者提供了一种创建具有 iOS 风格用户界面的便捷方式,使得 Flutter 应用能够在 iOS 平台上提供原汁原味的 iOS 体验,同时也可通过适当调整在 Android 等其他平台上展现独特风格。

与 Material Design 不同,Cupertino Design 强调简洁、直接的交互和视觉元素。例如,Cupertino 风格的按钮通常有更圆润的边角,并且在交互时会有明显的反馈动画,像按下按钮时的轻微缩放效果。这种设计风格注重给用户带来熟悉且流畅的操作感受,尤其是对于 iOS 用户群体,能够让他们快速上手应用,减少学习成本。

环境搭建与基本使用

在开始使用 Cupertino Design 组件之前,确保你已经安装并配置好了 Flutter 开发环境。创建一个新的 Flutter 项目后,就可以在项目中引入 Cupertino 相关组件。

lib/main.dart 文件中,我们可以简单创建一个包含 Cupertino 风格页面的应用。以下是一个基础示例:

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

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const CupertinoApp(
      home: CupertinoPageScaffold(
        navigationBar: CupertinoNavigationBar(
          middle: Text('Cupertino 示例'),
        ),
        child: Center(
          child: Text('欢迎来到 Cupertino 世界'),
        ),
      ),
    );
  }
}

在这个示例中,我们使用了 CupertinoApp 作为应用的顶级组件,它设置了整个应用的 Cupertino 风格主题。CupertinoPageScaffold 提供了一个标准的页面结构,包含导航栏和内容区域。CupertinoNavigationBar 定义了页面的导航栏,其中 middle 属性设置了导航栏中间显示的文本。

Cupertino 导航组件

CupertinoNavigationBar

CupertinoNavigationBar 是 Cupertino 风格应用中常见的导航栏组件。它具有简洁的外观和流畅的交互效果。除了前面示例中展示的设置中间文本外,还可以在导航栏两侧添加按钮。

例如,我们可以在导航栏左侧添加一个返回按钮:

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

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const CupertinoApp(
      home: CupertinoPageScaffold(
        navigationBar: CupertinoNavigationBar(
          leading: CupertinoButton(
            onPressed: null,
            child: const Icon(CupertinoIcons.back),
          ),
          middle: Text('Cupertino 示例'),
        ),
        child: Center(
          child: Text('欢迎来到 Cupertino 世界'),
        ),
      ),
    );
  }
}

在上述代码中,leading 属性用于设置导航栏左侧的按钮。这里我们使用 CupertinoButton 并搭配 CupertinoIcons.back 图标来创建一个类似 iOS 返回按钮的样式。实际应用中,onPressed 回调函数应实现返回上一页的逻辑,这里为了示例简单设置为 null

CupertinoTabBar 和 CupertinoTabScaffold

CupertinoTabBarCupertinoTabScaffold 用于创建底部标签栏导航。这在许多 iOS 应用中是常见的导航方式,例如社交应用中切换不同功能模块。

以下是一个简单的示例,展示如何创建一个具有两个标签的底部导航栏:

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

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const CupertinoApp(
      home: CupertinoTabScaffold(
        tabBar: CupertinoTabBar(
          items: [
            BottomNavigationBarItem(
              icon: Icon(CupertinoIcons.home),
              label: '首页'
            ),
            BottomNavigationBarItem(
              icon: Icon(CupertinoIcons.settings),
              label: '设置'
            )
          ]
        ),
        tabBuilder: (BuildContext context, int index) {
          switch (index) {
            case 0:
              return CupertinoPageScaffold(
                navigationBar: CupertinoNavigationBar(
                  middle: Text('首页')
                ),
                child: Center(
                  child: Text('这是首页')
                )
              );
            case 1:
              return CupertinoPageScaffold(
                navigationBar: CupertinoNavigationBar(
                  middle: Text('设置')
                ),
                child: Center(
                  child: Text('这是设置页')
                )
              );
            default:
              return Container();
          }
        }
      )
    );
  }
}

在这个示例中,CupertinoTabBaritems 属性定义了底部标签栏的各个项目,每个项目包含一个图标和标签。CupertinoTabScaffoldtabBuilder 回调函数根据当前选中的标签索引构建对应的页面。

Cupertino 按钮组件

CupertinoButton

CupertinoButton 是 Cupertino 风格的按钮组件。它具有多种样式和交互效果。默认情况下,CupertinoButton 在按下时会有一个轻微的缩放效果。

以下是一个简单的 CupertinoButton 示例,点击按钮时在控制台打印信息:

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

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      home: CupertinoPageScaffold(
        navigationBar: CupertinoNavigationBar(
          middle: const Text('按钮示例'),
        ),
        child: Center(
          child: CupertinoButton(
            onPressed: () {
              print('按钮被点击了');
            },
            child: const Text('点击我'),
          ),
        ),
      ),
    );
  }
}

CupertinoButton 还可以通过 color 属性设置背景颜色,padding 属性设置内边距等,以满足不同的设计需求。例如:

CupertinoButton(
  color: CupertinoColors.activeBlue,
  padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
  onPressed: () {
    print('按钮被点击了');
  },
  child: const Text('蓝色背景按钮'),
)

CupertinoSwitch

CupertinoSwitch 是 Cupertino 风格的开关按钮。它常用于设置页面中切换某些功能的开启或关闭状态。

以下是一个简单的 CupertinoSwitch 示例,展示如何获取和更新开关状态:

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

void main() => runApp(const MyApp());

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool _isSwitched = false;

  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      home: CupertinoPageScaffold(
        navigationBar: CupertinoNavigationBar(
          middle: const Text('开关示例'),
        ),
        child: Center(
          child: CupertinoSwitch(
            value: _isSwitched,
            onChanged: (bool value) {
              setState(() {
                _isSwitched = value;
                print('开关状态: $_isSwitched');
              });
            },
          ),
        ),
      ),
    );
  }
}

在这个示例中,我们使用 StatefulWidget 来管理开关的状态。CupertinoSwitchvalue 属性表示当前开关的状态,onChanged 回调函数在开关状态改变时被调用,通过 setState 方法更新状态并打印当前状态到控制台。

Cupertino 表单组件

CupertinoTextField

CupertinoTextField 是 Cupertino 风格的文本输入框。它提供了与 iOS 原生文本输入框相似的外观和交互体验。

以下是一个简单的 CupertinoTextField 示例,展示如何获取用户输入的文本:

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

void main() => runApp(const MyApp());

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _inputText = '';

  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      home: CupertinoPageScaffold(
        navigationBar: CupertinoNavigationBar(
          middle: const Text('文本输入示例'),
        ),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            CupertinoTextField(
              placeholder: '请输入文本',
              onChanged: (String value) {
                setState(() {
                  _inputText = value;
                });
              },
            ),
            Padding(
              padding: const EdgeInsets.only(top: 20),
              child: Text('你输入的是: $_inputText'),
            )
          ],
        ),
      ),
    );
  }
}

在上述代码中,CupertinoTextFieldplaceholder 属性设置了输入框为空时显示的提示文本,onChanged 回调函数在用户输入文本时被调用,通过 setState 方法更新 _inputText 变量并在下方显示用户输入的内容。

CupertinoPicker

CupertinoPicker 是 Cupertino 风格的选择器组件,类似于 iOS 原生的滚轮选择器。它常用于从一组预定义的值中选择一个或多个值。

以下是一个简单的 CupertinoPicker 示例,展示如何创建一个选择颜色的选择器:

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

void main() => runApp(const MyApp());

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  int _selectedIndex = 0;
  final List<String> _colors = ['红色', '绿色', '蓝色'];

  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      home: CupertinoPageScaffold(
        navigationBar: CupertinoNavigationBar(
          middle: const Text('选择器示例'),
        ),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            CupertinoPicker(
              itemExtent: 40,
              onSelectedItemChanged: (int index) {
                setState(() {
                  _selectedIndex = index;
                });
              },
              children: _colors.map((String color) {
                return Center(
                  child: Text(color),
                );
              }).toList(),
            ),
            Padding(
              padding: const EdgeInsets.only(top: 20),
              child: Text('你选择的颜色是: ${_colors[_selectedIndex]}'),
            )
          ],
        ),
      ),
    );
  }
}

在这个示例中,CupertinoPickeritemExtent 属性设置了每个选项的高度。onSelectedItemChanged 回调函数在用户选择不同选项时被调用,通过 setState 方法更新 _selectedIndex 变量并在下方显示用户选择的颜色。

Cupertino 模态组件

CupertinoAlertDialog

CupertinoAlertDialog 是 Cupertino 风格的弹出对话框组件。它用于向用户显示重要信息或询问用户确认某些操作。

以下是一个简单的 CupertinoAlertDialog 示例,展示如何弹出一个包含确认和取消按钮的对话框:

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

void main() => runApp(const MyApp());

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  void _showAlertDialog() {
    showCupertinoDialog(
      context: context,
      builder: (BuildContext context) {
        return CupertinoAlertDialog(
          title: const Text('提示'),
          content: const Text('你确定要执行此操作吗?'),
          actions: [
            CupertinoDialogAction(
              child: const Text('取消'),
              onPressed: () {
                Navigator.pop(context);
              },
            ),
            CupertinoDialogAction(
              child: const Text('确认'),
              onPressed: () {
                Navigator.pop(context);
                print('用户确认操作');
              },
            )
          ],
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      home: CupertinoPageScaffold(
        navigationBar: CupertinoNavigationBar(
          middle: const Text('对话框示例'),
        ),
        child: Center(
          child: CupertinoButton(
            onPressed: _showAlertDialog,
            child: const Text('点击弹出对话框'),
          ),
        ),
      ),
    );
  }
}

在上述代码中,showCupertinoDialog 函数用于弹出对话框。CupertinoAlertDialogtitle 属性设置对话框标题,content 属性设置对话框内容,actions 属性设置对话框底部的按钮。点击按钮时,通过 Navigator.pop(context) 关闭对话框,并在确认按钮点击时打印操作信息。

CupertinoActionSheet

CupertinoActionSheet 是 Cupertino 风格的操作底部弹窗组件。它通常用于在页面底部弹出一系列操作选项。

以下是一个简单的 CupertinoActionSheet 示例:

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

void main() => runApp(const MyApp());

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  void _showActionSheet() {
    showCupertinoModalPopup(
      context: context,
      builder: (BuildContext context) {
        return CupertinoActionSheet(
          title: const Text('操作选项'),
          actions: [
            CupertinoActionSheetAction(
              child: const Text('选项一'),
              onPressed: () {
                Navigator.pop(context);
                print('用户选择了选项一');
              },
            ),
            CupertinoActionSheetAction(
              child: const Text('选项二'),
              onPressed: () {
                Navigator.pop(context);
                print('用户选择了选项二');
              },
            )
          ],
          cancelButton: CupertinoActionSheetAction(
            child: const Text('取消'),
            onPressed: () {
              Navigator.pop(context);
            },
          ),
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      home: CupertinoPageScaffold(
        navigationBar: CupertinoNavigationBar(
          middle: const Text('操作底部弹窗示例'),
        ),
        child: Center(
          child: CupertinoButton(
            onPressed: _showActionSheet,
            child: const Text('点击弹出操作底部弹窗'),
          ),
        ),
      ),
    );
  }
}

在这个示例中,showCupertinoModalPopup 函数用于弹出操作底部弹窗。CupertinoActionSheettitle 属性设置弹窗标题,actions 属性设置操作选项,cancelButton 属性设置取消按钮。点击各选项或取消按钮时,通过 Navigator.pop(context) 关闭弹窗,并打印相应操作信息。

Cupertino 布局与容器组件

CupertinoPageScaffold

CupertinoPageScaffold 是构建 Cupertino 风格页面的基础组件。它提供了一个标准的页面结构,包括导航栏和内容区域。我们在前面的示例中已经多次使用过它。

它的基本结构如下:

CupertinoPageScaffold(
  navigationBar: CupertinoNavigationBar(
    middle: const Text('页面标题'),
  ),
  child: const Center(
    child: Text('页面内容'),
  ),
)

navigationBar 属性用于设置页面的导航栏,child 属性用于设置页面的主要内容区域。通过这种结构,能够快速搭建出符合 Cupertino 风格的页面布局。

CupertinoContainer

CupertinoContainer 类似于 Flutter 中的 Container,但具有 Cupertino 风格的外观和默认样式。它可以用于包裹其他组件,并设置背景颜色、边框、内边距等属性。

以下是一个简单的 CupertinoContainer 示例:

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

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      home: CupertinoPageScaffold(
        navigationBar: CupertinoNavigationBar(
          middle: const Text('容器示例'),
        ),
        child: Center(
          child: CupertinoContainer(
            color: CupertinoColors.lightBackgroundGray,
            padding: const EdgeInsets.all(20),
            child: const Text('这是一个 Cupertino 风格的容器'),
          ),
        ),
      ),
    );
  }
}

在上述代码中,CupertinoContainercolor 属性设置了容器的背景颜色,padding 属性设置了内边距,内部包裹了一个文本组件。

Cupertino 主题定制

主题颜色定制

Cupertino Design 提供了丰富的主题定制选项。其中,主题颜色的定制是重要的一部分。我们可以通过 CupertinoThemeData 来设置应用的主题颜色。

以下是一个简单的示例,展示如何将应用的主要颜色设置为自定义颜色:

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

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      theme: CupertinoThemeData(
        primaryColor: Colors.deepOrange,
      ),
      home: CupertinoPageScaffold(
        navigationBar: CupertinoNavigationBar(
          middle: const Text('主题定制示例'),
        ),
        child: Center(
          child: CupertinoButton(
            onPressed: null,
            child: const Text('按钮'),
          ),
        ),
      ),
    );
  }
}

在这个示例中,通过 CupertinoThemeDataprimaryColor 属性将应用的主要颜色设置为 Colors.deepOrange。此时,像 CupertinoButton 等组件的颜色会根据这个主要颜色进行相应的变化。

字体样式定制

除了颜色定制,字体样式也是主题定制的关键部分。我们可以通过 CupertinoThemeDatatextTheme 属性来定制应用中的字体样式。

以下是一个示例,展示如何将应用中的文本字体设置为特定样式:

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

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      theme: CupertinoThemeData(
        textTheme: CupertinoTextThemeData(
          textStyle: TextStyle(
            fontFamily: 'Arial',
            fontSize: 16,
            color: Colors.black87,
          ),
        ),
      ),
      home: CupertinoPageScaffold(
        navigationBar: CupertinoNavigationBar(
          middle: const Text('主题定制示例'),
        ),
        child: Center(
          child: const Text('这是一段自定义字体样式的文本'),
        ),
      ),
    );
  }
}

在上述代码中,通过 CupertinoTextThemeDatatextStyle 属性设置了应用中所有文本的字体为 Arial,字号为 16,颜色为深灰色。这样,应用内的文本组件都会使用这种字体样式,除非有更具体的样式覆盖。

在不同平台上使用 Cupertino Design

iOS 平台适配

在 iOS 平台上使用 Cupertino Design 组件是最为自然的,因为其本身就是模仿 iOS 设计风格。通常情况下,无需额外的适配工作,组件就能展现出与 iOS 原生应用相似的外观和交互效果。

然而,在某些特定场景下,可能需要根据 iOS 系统版本进行一些微调。例如,不同的 iOS 版本可能对某些组件的样式有细微差异,开发者需要通过条件判断来调整组件的属性。

以下是一个简单的示例,根据 iOS 系统版本调整 CupertinoNavigationBar 的背景颜色:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:device_info_plus/device_info_plus.dart';

void main() => runApp(const MyApp());

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  double _iosVersion = 0;

  @override
  void initState() {
    super.initState();
    _getIOSVersion();
  }

  Future<void> _getIOSVersion() async {
    final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
    final IosDeviceInfo iosDeviceInfo = await deviceInfoPlugin.iosInfo;
    setState(() {
      _iosVersion = double.parse(iosDeviceInfo.systemVersion.split('.').first);
    });
  }

  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      home: CupertinoPageScaffold(
        navigationBar: CupertinoNavigationBar(
          middle: const Text('iOS 适配示例'),
          backgroundColor: _iosVersion >= 14? CupertinoColors.systemBackground : CupertinoColors.white,
        ),
        child: const Center(
          child: Text('这是一个 iOS 适配示例页面'),
        ),
      ),
    );
  }
}

在这个示例中,我们使用 device_info_plus 插件获取 iOS 系统版本。然后根据系统版本是否大于等于 14 来调整 CupertinoNavigationBar 的背景颜色,以适配不同 iOS 版本的视觉风格。

Android 平台适配

在 Android 平台上使用 Cupertino Design 组件可以为应用带来独特的风格。但为了使应用在 Android 平台上看起来更协调,可能需要进行一些额外的适配工作。

例如,Android 系统的默认字体和交互习惯与 iOS 有所不同。我们可以通过设置 CupertinoThemeDatatextThemeprimaryColor 等属性,使其更符合 Android 用户的视觉习惯。

以下是一个简单的示例,在 Android 平台上调整 Cupertino 组件的颜色和字体:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      theme: kIsWeb || defaultTargetPlatform == TargetPlatform.android
         ? CupertinoThemeData(
              primaryColor: Colors.blue,
              textTheme: CupertinoTextThemeData(
                textStyle: TextStyle(
                  fontFamily: 'Roboto',
                  fontSize: 14,
                  color: Colors.black87,
                ),
              ),
            )
          : CupertinoThemeData(),
      home: CupertinoPageScaffold(
        navigationBar: CupertinoNavigationBar(
          middle: const Text('Android 适配示例'),
        ),
        child: const Center(
          child: Text('这是一个 Android 适配示例页面'),
        ),
      ),
    );
  }
}

在这个示例中,通过 defaultTargetPlatform 判断当前平台是否为 Android 或 Web。如果是,则设置 primaryColor 为蓝色,textTheme 使用 Android 常用的 Roboto 字体,并调整字号。这样可以使 Cupertino 组件在 Android 平台上更具亲和力。

通过以上对 Flutter Cupertino Design 组件的详细介绍和实践示例,开发者可以深入了解并灵活运用这些组件,创建出具有独特风格和良好用户体验的应用程序。无论是在 iOS 还是 Android 平台,合理使用 Cupertino Design 组件都能为应用增色不少。同时,通过主题定制和平台适配等技巧,能够进一步优化应用在不同场景下的表现。在实际开发中,开发者还应结合项目需求和用户反馈,不断调整和完善应用的界面设计和交互逻辑,以提供更优质的产品。