Skip to content

第5章:Flutter 基础组件

5.1 文本组件(Text)

基本用法

Text 组件是 Flutter 中最常用的组件之一,用于显示文本内容。

基本语法

dart
Text(
  'Hello Flutter',
  style: TextStyle(
    fontSize: 18,
    fontWeight: FontWeight.bold,
    color: Colors.blue,
  ),
  textAlign: TextAlign.center,
  maxLines: 2,
  overflow: TextOverflow.ellipsis,
);

常用属性

属性描述默认值
data文本内容必填
style文本样式null
textAlign文本对齐方式TextAlign.start
maxLines最大行数null
overflow文本溢出处理TextOverflow.clip
textDirection文本方向null
softWrap是否自动换行true
textScaleFactor文本缩放因子1.0

文本样式(TextStyle)

dart
TextStyle(
  fontSize: 16,          // 字体大小
  fontWeight: FontWeight.w500, // 字体粗细
  color: Colors.black,    // 字体颜色
  fontFamily: 'Roboto',   // 字体
  fontStyle: FontStyle.italic, // 字体样式
  letterSpacing: 1.0,     // 字间距
  wordSpacing: 2.0,       // 词间距
  height: 1.5,            // 行高
  decoration: TextDecoration.underline, // 文本装饰
  decorationColor: Colors.red, // 装饰颜色
  decorationStyle: TextDecorationStyle.dashed, // 装饰样式
);

富文本组件(RichText)

RichText 组件用于显示多种样式的文本:

dart
RichText(
  text: TextSpan(
    text: 'Hello ',
    style: DefaultTextStyle.of(context).style,
    children: <TextSpan>[
      TextSpan(
        text: 'Flutter',
        style: const TextStyle(
          fontWeight: FontWeight.bold,
          color: Colors.blue,
        ),
      ),
      TextSpan(
        text: ' World!',
        style: const TextStyle(
          fontStyle: FontStyle.italic,
          color: Colors.green,
        ),
      ),
    ],
  ),
);

5.2 图片组件(Image)

图片加载方式

Flutter 支持多种图片加载方式:

1. 网络图片

dart
Image.network(
  'https://example.com/image.jpg',
  width: 200,
  height: 200,
  fit: BoxFit.cover,
  loadingBuilder: (context, child, loadingProgress) {
    if (loadingProgress == null) return child;
    return const Center(child: CircularProgressIndicator());
  },
  errorBuilder: (context, error, stackTrace) {
    return const Center(child: Icon(Icons.error));
  },
);

2. 本地图片

首先在 pubspec.yaml 中配置资源:

yaml
flutter:
  assets:
    - assets/images/

然后加载本地图片:

dart
Image.asset(
  'assets/images/flutter_logo.png',
  width: 100,
  height: 100,
);

3. 内存图片

dart
Image.memory(
  Uint8List.fromList(imageBytes),
  width: 200,
  height: 200,
);

4. 文件图片

dart
Image.file(
  File('/path/to/image.jpg'),
  width: 200,
  height: 200,
);

常用属性

属性描述默认值
width图片宽度null
height图片高度null
fit图片缩放方式BoxFit.contain
alignment图片对齐方式Alignment.center
repeat图片重复方式ImageRepeat.noRepeat
color图片颜色滤镜null
colorBlendMode颜色混合模式null

图标组件(Icon)

Flutter 内置了大量图标:

dart
Icon(
  Icons.home,         // 图标名称
  size: 24,           // 图标大小
  color: Colors.blue,  // 图标颜色
);

常用图标:

  • Icons.home - 首页
  • Icons.search - 搜索
  • Icons.add - 添加
  • Icons.delete - 删除
  • Icons.settings - 设置
  • Icons.share - 分享
  • Icons.favorite - 收藏
  • Icons.email - 邮件

5.3 按钮组件

ElevatedButton(悬浮按钮,最常用)

dart
ElevatedButton(
  onPressed: () {
    // 按钮点击事件
    print('Button clicked!');
  },
  onLongPress: () {
    // 长按事件
    print('Button long pressed!');
  },
  style: ElevatedButton.styleFrom(
    backgroundColor: Colors.blue,         // 按钮颜色
    foregroundColor: Colors.white,        // 文字颜色
    elevation: 5,                        // 阴影
    padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), // 内边距
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(8), // 圆角
    ),
    textStyle: const TextStyle(
      fontSize: 16,
      fontWeight: FontWeight.bold,
    ),
  ),
  child: const Text('Click Me'),
);

TextButton(文本按钮)

dart
TextButton(
  onPressed: () {
    print('Text button clicked!');
  },
  style: TextButton.styleFrom(
    foregroundColor: Colors.blue,        // 文字颜色
    padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
  ),
  child: const Text('Text Button'),
);

OutlinedButton(边框按钮)

dart
OutlinedButton(
  onPressed: () {
    print('Outlined button clicked!');
  },
  style: OutlinedButton.styleFrom(
    foregroundColor: Colors.blue,        // 文字颜色
    side: const BorderSide(color: Colors.blue), // 边框颜色
    padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(8),
    ),
  ),
  child: const Text('Outlined Button'),
);

图标按钮(IconButton)

dart
IconButton(
  onPressed: () {
    print('Icon button clicked!');
  },
  icon: const Icon(Icons.favorite),
  iconSize: 24,
  color: Colors.red,
  tooltip: 'Favorite', // 长按提示
);

5.4 输入组件(TextField)

基本用法

dart
TextField(
  decoration: InputDecoration(
    labelText: 'Username',        // 标签文本
    hintText: 'Enter your username', // 提示文本
    prefixIcon: const Icon(Icons.person), // 前缀图标
    suffixIcon: const Icon(Icons.clear), // 后缀图标
    border: OutlineInputBorder(
      borderRadius: BorderRadius.circular(8),
    ),
    filled: true,
    fillColor: Colors.grey[100],
  ),
  keyboardType: TextInputType.text, // 键盘类型
  textInputAction: TextInputAction.next, // 键盘操作按钮
  autofocus: false, // 是否自动聚焦
  obscureText: false, // 是否隐藏文本(密码)
  maxLength: 20, // 最大长度
  onChanged: (value) {
    // 输入变化回调
    print('Input: $value');
  },
  onSubmitted: (value) {
    // 提交回调
    print('Submitted: $value');
  },
);

常用属性

属性描述默认值
decoration输入框装饰null
controller文本控制器null
keyboardType键盘类型TextInputType.text
textInputAction键盘操作按钮TextInputAction.done
autofocus是否自动聚焦false
obscureText是否隐藏文本false
maxLength最大长度null
maxLines最大行数1
onChanged输入变化回调null
onSubmitted提交回调null
enabled是否启用true

控制器(TextEditingController)

使用控制器可以更灵活地控制输入框:

dart
final TextEditingController _controller = TextEditingController();

@override
void dispose() {
  _controller.dispose();
  super.dispose();
}

// 使用
TextField(
  controller: _controller,
  // ...
);

// 读取值
String value = _controller.text;

// 设置值
_controller.text = 'Hello';

// 清空
_controller.clear();

5.5 其他基础组件

Container(容器组件)

Container 是一个多功能的容器组件,可以设置宽高、背景、padding、margin等:

dart
Container(
  width: 200,
  height: 100,
  decoration: BoxDecoration(
    color: Colors.blue,
    borderRadius: BorderRadius.circular(8),
    boxShadow: [
      BoxShadow(
        color: Colors.grey.withOpacity(0.5),
        spreadRadius: 2,
        blurRadius: 5,
        offset: const Offset(0, 2),
      ),
    ],
  ),
  padding: const EdgeInsets.all(16),
  margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
  alignment: Alignment.center,
  child: const Text('Container', style: TextStyle(color: Colors.white)),
);

SizedBox(尺寸盒子)

SizedBox 用于控制组件间距或固定宽高:

dart
// 控制间距
const SizedBox(height: 20);

// 固定宽高
SizedBox(
  width: 100,
  height: 100,
  child: const Text('Fixed size'),
);

Card(卡片组件)

Card 组件用于创建带阴影的卡片效果:

dart
Card(
  elevation: 5,
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.circular(10),
  ),
  child: Padding(
    padding: const EdgeInsets.all(16),
    child: Column(
      children: [
        const Text('Card Title', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
        const SizedBox(height: 8),
        const Text('This is a card content'),
      ],
    ),
  ),
);

Divider(分割线)

dart
const Divider(
  height: 20,
  thickness: 2,
  color: Colors.grey,
  indent: 20,
  endIndent: 20,
);

SnackBar(提示条)

dart
ScaffoldMessenger.of(context).showSnackBar(
  SnackBar(
    content: const Text('This is a snackbar'),
    duration: const Duration(seconds: 3),
    action: SnackBarAction(
      label: 'Undo',
      onPressed: () {
        // 撤销操作
      },
    ),
  ),
);

5.6 实操案例:搭建简单登录页面

目标

使用基础组件搭建一个简单的登录页面,包含文本、图片、输入框和按钮。

步骤 1:创建项目

使用 VS Code 或 Android Studio 创建一个新的 Flutter 项目。

步骤 2:创建登录页面

修改 lib/main.dart 文件:

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 MaterialApp(
      title: 'Login Page',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const LoginPage(),
    );
  }
}

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

  @override
  State<LoginPage> createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  final TextEditingController _usernameController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();
  bool _obscurePassword = true;

  @override
  void dispose() {
    _usernameController.dispose();
    _passwordController.dispose();
    super.dispose();
  }

  void _login() {
    String username = _usernameController.text;
    String password = _passwordController.text;
    
    if (username.isEmpty || password.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Please fill in all fields')),
      );
      return;
    }

    // 模拟登录
    print('Login with $username');
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('Login successful')),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey[100],
      body: SafeArea(
        child: Center(
          child: SingleChildScrollView(
            padding: const EdgeInsets.all(20),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                //  Logo
                Container(
                  width: 100,
                  height: 100,
                  decoration: const BoxDecoration(
                    shape: BoxShape.circle,
                    color: Colors.blue,
                  ),
                  child: const Icon(
                    Icons.lock,
                    size: 50,
                    color: Colors.white,
                  ),
                ),
                const SizedBox(height: 40),

                //  Title
                const Text(
                  'Welcome Back',
                  style:
                      TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
                ),
                const SizedBox(height: 8),
                const Text(
                  'Sign in to continue',
                  style: TextStyle(fontSize: 16, color: Colors.grey),
                ),
                const SizedBox(height: 40),

                //  Username field
                TextField(
                  controller: _usernameController,
                  decoration: InputDecoration(
                    labelText: 'Username',
                    hintText: 'Enter your username',
                    prefixIcon: const Icon(Icons.person),
                    border: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(10),
                    ),
                    filled: true,
                    fillColor: Colors.white,
                  ),
                ),
                const SizedBox(height: 20),

                //  Password field
                TextField(
                  controller: _passwordController,
                  obscureText: _obscurePassword,
                  decoration: InputDecoration(
                    labelText: 'Password',
                    hintText: 'Enter your password',
                    prefixIcon: const Icon(Icons.lock),
                    suffixIcon: IconButton(
                      icon: Icon(
                        _obscurePassword
                            ? Icons.visibility
                            : Icons.visibility_off,
                      ),
                      onPressed: () {
                        setState(() {
                          _obscurePassword = !_obscurePassword;
                        });
                      },
                    ),
                    border: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(10),
                    ),
                    filled: true,
                    fillColor: Colors.white,
                  ),
                ),
                const SizedBox(height: 20),

                //  Forgot password
                Align(
                  alignment: Alignment.centerRight,
                  child: TextButton(
                    onPressed: () {
                      print('Forgot password');
                    },
                    child: const Text('Forgot password?'),
                  ),
                ),
                const SizedBox(height: 30),

                //  Login button
                SizedBox(
                  width: double.infinity,
                  height: 50,
                  child: ElevatedButton(
                    onPressed: _login,
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.blue,
                      foregroundColor: Colors.white,
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(10),
                      ),
                      textStyle: const TextStyle(
                        fontSize: 16,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    child: const Text('Sign In'),
                  ),
                ),
                const SizedBox(height: 30),

                //  Register link
                Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    const Text('Don\'t have an account?'),
                    TextButton(
                      onPressed: () {
                        print('Register');
                      },
                      child: const Text('Sign Up'),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

步骤 3:运行应用

  1. 启动模拟器或连接真机
  2. 运行项目
  3. 观察登录页面效果

步骤 4:测试功能

  1. 尝试输入用户名和密码
  2. 点击登录按钮,观察提示
  3. 点击忘记密码链接
  4. 点击注册链接
  5. 测试密码显示/隐藏功能

5.7 小结

本章介绍了 Flutter 中常用的基础组件,包括文本组件、图片组件、按钮组件、输入组件以及其他基础组件。这些组件是构建 Flutter 应用界面的基础,掌握它们的使用方法对于 Flutter 开发至关重要。

通过实操案例,我们使用这些基础组件搭建了一个简单的登录页面,体验了组件的组合和交互。在实际开发中,你可以根据需要组合这些组件,创建更加复杂和美观的用户界面。

在接下来的章节中,我们将学习 Flutter 的布局开发,掌握如何使用布局组件来组织和排列这些基础组件,创建更加复杂的页面布局。

© 2026 编程马·菜鸟教程 版权所有