You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter应用中自定义字号(按需调字体高度)实现方法咨询

Flutter 实现用户自定义字号调整功能

核心思路

通过状态管理维护用户选择的字号选项,再封装一个全局可用的文本组件,自动读取当前选中的字号(及行高)渲染内容。以下是具体实现步骤:


1. 实现字号状态管理

创建状态管理类,保存用户选择的字号选项并提供更新方法:

import 'package:flutter/foundation.dart';

// 预设字号选项
enum FontSizeOption { small, normal, large, extraLarge }

class FontSizeManager extends ChangeNotifier {
  // 默认选中正常字号
  FontSizeOption _selectedOption = FontSizeOption.normal;

  FontSizeOption get selectedOption => _selectedOption;

  // 映射选项到具体字号值(可按需自定义)
  double get currentFontSize {
    switch (_selectedOption) {
      case FontSizeOption.small:
        return 12;
      case FontSizeOption.normal:
        return 14;
      case FontSizeOption.large:
        return 16;
      case FontSizeOption.extraLarge:
        return 18;
    }
  }

  // 可选:映射选项到对应行高
  double get currentLineHeight {
    switch (_selectedOption) {
      case FontSizeOption.small:
        return 1.2;
      case FontSizeOption.normal:
        return 1.4;
      case FontSizeOption.large:
        return 1.6;
      case FontSizeOption.extraLarge:
        return 1.8;
    }
  }

  void updateFontSize(FontSizeOption newOption) {
    _selectedOption = newOption;
    notifyListeners();
  }
}

2. 在应用顶层注入状态

用ChangeNotifierProvider包裹整个应用,让所有子组件能访问字号状态:

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

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => FontSizeManager(),
      child: const MyApp(),
    ),
  );
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: const HomePage(),
    );
  }
}

3. 构建字号选择界面

提供用户选择字号的UI,比如单选列表:

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

  @override
  Widget build(BuildContext context) {
    final fontSizeManager = Provider.of<FontSizeManager>(context);

    return Scaffold(
      appBar: AppBar(title: const Text('调整字号')),
      body: ListView(
        children: [
          RadioListTile<FontSizeOption>(
            title: const Text('小号'),
            value: FontSizeOption.small,
            groupValue: fontSizeManager.selectedOption,
            onChanged: (value) {
              if (value != null) {
                fontSizeManager.updateFontSize(value);
                Navigator.pop(context);
              }
            },
          ),
          RadioListTile<FontSizeOption>(
            title: const Text('默认'),
            value: FontSizeOption.normal,
            groupValue: fontSizeManager.selectedOption,
            onChanged: (value) {
              if (value != null) {
                fontSizeManager.updateFontSize(value);
                Navigator.pop(context);
              }
            },
          ),
          RadioListTile<FontSizeOption>(
            title: const Text('大号'),
            value: FontSizeOption.large,
            groupValue: fontSizeManager.selectedOption,
            onChanged: (value) {
              if (value != null) {
                fontSizeManager.updateFontSize(value);
                Navigator.pop(context);
              }
            },
          ),
          RadioListTile<FontSizeOption>(
            title: const Text('超大号'),
            value: FontSizeOption.extraLarge,
            groupValue: fontSizeManager.selectedOption,
            onChanged: (value) {
              if (value != null) {
                fontSizeManager.updateFontSize(value);
                Navigator.pop(context);
              }
            },
          ),
        ],
      ),
    );
  }
}

4. 封装自适应文本组件

创建自定义Text组件,自动读取当前选中的字号和行高:

class ScalableText extends StatelessWidget {
  final String text;
  final TextStyle? style;
  final TextAlign? textAlign;
  final int? maxLines;

  const ScalableText(
    this.text, {
    super.key,
    this.style,
    this.textAlign,
    this.maxLines,
  });

  @override
  Widget build(BuildContext context) {
    final fontSizeManager = Provider.of<FontSizeManager>(context);

    return Text(
      text,
      textAlign: textAlign,
      maxLines: maxLines,
      style: style?.copyWith(
            fontSize: fontSizeManager.currentFontSize,
            height: fontSizeManager.currentLineHeight,
          ) ??
          TextStyle(
            fontSize: fontSizeManager.currentFontSize,
            height: fontSizeManager.currentLineHeight,
          ),
    );
  }
}

5. 在页面中使用

用ScalableText替代普通Text,字号会跟随用户选择自动变化:

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const ScalableText('首页'),
        actions: [
          IconButton(
            icon: const Icon(Icons.settings),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => const FontSizeSettingsPage()),
              );
            },
          ),
        ],
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: const [
            ScalableText(
              '这是一段自适应字号的文本内容,用户选择不同的字号选项后,这段文字的大小和行高会自动调整。',
              textAlign: TextAlign.justify,
            ),
            SizedBox(height: 20),
            ScalableText(
              '标题文本',
              style: TextStyle(fontWeight: FontWeight.bold),
            ),
          ],
        ),
      ),
    );
  }
}

补充说明

  • 若需持久化用户的字号选择,可在FontSizeManager中加入本地存储逻辑(如shared_preferences),启动时读取上次保存的选项。
  • 若项目使用其他状态管理方案(如Riverpod、Bloc),可将字号状态迁移至对应方案,核心逻辑保持一致。

内容的提问来源于stack exchange,提问作者Jaimin Modi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 12:27:16