Flutter第三弹:常用的Widget

目标:

1)常用的Widget有哪些?有什么特征?

2)开发一个简单的登录页面。

一、Flutter常用Widget

对于Flutter来说,一切皆Widget.

常用的Widget,包括一些基础功能的Widget.

|-----------------|------------------|-------------------------------------|
| 控件名称 | 功能 | 备注 |
| Text | 文本小组件 | |
| Icon/IconButton | | |
| Row | 水平布局组件 | |
| Column | 竖直布局组件 | |
| Stack | | |
| Container | 容器小组件 | 类似层叠式布局 |
| EdgeInsets | 边框小组件 | 用于设置padding |
| Padding | 内边距 | 用于设置容器内边距 |
| Scaffold | 脚手架小组件 | 规划页面主要布局位置,包括AppBar,底部导航栏按钮,页面Body等 |
| MaterialApp | Material风格UI入口 | |
| AppBar | Material风格AppBar | |

Flutter Widget列表

https://flutter.cn/docs/reference/widgets

1.1 输入框 TextField

Flutter的输入框是常见的用户界面组件之一,用于接收用户的文本输入。对应的组件源码

text_field.dart

  • controller:控制输入框的文本内容,可以通过TextEditingController进行管理。
  • decoration:输入框的装饰,可以定义输入框的边框、背景、提示文本等样式。
  • obscureText:是否将输入内容隐藏,常用于密码输入框。
  • enabled:输入框是否可编辑。
  • maxLength:允许输入的最大字符数。
  • textInputAction:键盘操作按钮的类型,例如完成、继续等。
  • keyboardType:键盘的类型,如文本、数字、URL等。
  • onChanged:文本变化时的回调函数。
  • onSubmitted:用户提交输入时的回调函数。
  • focusNode:用于控制输入框的焦点获取和失去。
  • autofocus:是否自动获取焦点。
  • style:输入框文本的样式,如字体大小、颜色等。

1. controller属性

controller属性用于控制输入框的文本内容,可以通过TextEditingController进行管理。使用TextEditingController可以获取、设置和监听输入框的文本内容。

Dart 复制代码
TextEditingController _textController = TextEditingController();

TextField(
  controller: _textController,
);

通过_textController.text来获取或设置输入框中的文本内容。

2. decoration属性

decoration属性用于定义输入框的装饰,包括边框、背景、提示文本等样式。它使用InputDecoration类来配置输入框的外观。

Dart 复制代码
TextField(
  decoration: InputDecoration(
    border: OutlineInputBorder(),
    filled: true,
    fillColor: Colors.grey[200],
    hintText: 'Enter your name',
    hintStyle: TextStyle(color: Colors.grey),
    prefixIcon: Icon(Icons.person),
  ),
);

3. obscureText属性

obscureText属性用于指定输入框的文本是否应该被隐藏,常用于密码输入框。当设置为true时,输入的文本将以圆点或其他隐藏字符显示。掩码显示。

Dart 复制代码
TextField(
  obscureText: true,
);

4. enabled属性-是否可编辑

enabled属性用于指定输入框是否可编辑。当设置为false时,输入框将变为只读状态,用户无法编辑其中的文本。

5. maxLength属性

maxLength属性用于限制输入框可输入的最大字符数。设置此属性后,用户将无法输入超过指定字符数的文本。

Dart 复制代码
TextField(
  maxLength: 10,
);

6. textInputAction属性

textInputAction属性用于指定键盘操作按钮的类型,例如完成、继续等。它们用于控制键盘上右下角按钮的标签和功能。

Dart 复制代码
TextField(
  textInputAction: TextInputAction.done,
);

7. keyboardType属性

keyboardType属性用于指定键盘的类型,例如文本、数字、URL等。根据需要选择适合的键盘类型,以提供更好的用户体验。

Dart 复制代码
TextField(
  keyboardType: TextInputType.emailAddress,
);

8. onChangedonSubmitted属性

onChangedonSubmitted属性用于定义输入框文本变化和提交输入的回调函数。onChanged在输入框文本发生变化时被调用,而onSubmitted在用户提交输入时被调用。

Dart 复制代码
TextField(
  onChanged: (value) {
    // 处理文本变化
  },
  onSubmitted: (value) {
    // 处理提交输入
  },
);

9. style属性

style属性用于定义输入框文本的样式,如字体大小、颜色等。

Dart 复制代码
TextField(
  style: TextStyle(
    fontSize: 16.0,
    color: Colors.black,
  ),
);

1.2 文本框 Text

文本框是Flutter用于显示文本的小组件。

创建函数如下:

Dart 复制代码
  const Text(
    String this.data, {
    Key? key,
    this.style,
    this.strutStyle,
    this.textAlign,
    this.textDirection,
    this.locale,
    this.softWrap,
    this.overflow,
    this.textScaleFactor,
    this.maxLines,
    this.semanticsLabel,
    this.textWidthBasis,
    this.textHeightBehavior,
  }) : assert(
         data != null,
         'A non-null String must be provided to a Text widget.',
       ),
       textSpan = null,
       super(key: key);

创建函数存在一个非空必选参数String data,存储文本内容。其他是一些可选参数。

1. text属性

存储文本

2. key属性 用于识别组件的唯一键。

3. style属性

TextStyle对象,用于指定文本的样式,例如字体、颜色、大小等。常用的属性配置:

  • color: 文本颜色。
  • fontSize: 字体大小。
  • fontWeight: 字体粗细。
  • fontStyle: 字体样式,如斜体。
  • letterSpacing: 字母间距。
  • wordSpacing: 单词间距。
  • background: 文本背景颜色。
  • decoration: 文本修饰,如下划线、删除线等。
  • decorationColor: 文本修饰的颜色。
  • decorationStyle: 文本修饰的样式。
  • height: 行高。
  • textBaseline: 基线对齐方式。
  • shadows: 文本阴影效果。

4. textAlign属性

文本对齐方式,可以是左对齐(left)、右对齐(right)、居中对齐(center)或两端对齐(justify)。

5. textDirection属性

文本方向,可以是从左到右(ltr)或从右到左(rtl)。

6. softWrap属性

softWrap是否自动换行,默认为true。

7. overflow属性

文本溢出处理方式,可以是省略号(ellipsis)、截断(clip)或折叠(fade)

8. maxLines属性

最大显示行数,超过部分将根据overflow属性进行处理。

9. textScaleFactor属性

文本缩放因子,用于调整文本大小的比例。

10. locale属性

文本的本地化配置,用于支持多语言显示。

11. strutStyle属性

文本行高样式。

12. textWidthBasis属性

文本宽度计算基准,可以是parent(父容器宽度)或 longestLine(最长行宽度)。

13. textHeightBehavior属性

文本高度行为配置。

1.3 按钮 Button

常用的按钮分类

  • ElevatedButton: 凸起按钮,具有立体效果。
  • TextButton: 文本按钮,通常用于文字链接或简单的按钮。
  • OutlinedButton: 带边框的按钮,边框颜色可自定义。
  • IconButton: 图标按钮,使用图标作为按钮的内容。

1. onPressed属性

点击按钮时触发的回调函数

2. onLongPress属性

长按按钮时触发的回调函数

3. style属性

ButtonStyle对象,用于设置按钮的样式。常用属性如下:

  • backgroundColor:按钮的背景颜色。【常用】
  • foregroundColor:按钮的前景颜色,如文字颜色。【常用】
  • elevation:按钮的海拔高度,用于创建立体效果。
  • padding:按钮的内边距。【常用】
  • side:按钮的边框样式。
  • shape:按钮的形状。【常用】
  • minimumSize:按钮的最小尺寸。
  • alignment:按钮内容的对齐方式。
Dart 复制代码
              ElevatedButton(
                onPressed: () {
                  // 点击了按钮
                  print("ElevatedButton pressed");
                },
                style: ButtonStyle(
                  backgroundColor: MaterialStateProperty.all(Colors.blue),
                  foregroundColor: MaterialStateProperty.all(Colors.white),
                  padding: MaterialStateProperty.all(EdgeInsets.all(12.0)),
                ),
                child: Text("登录",
                    style: TextStyle(
                      fontSize: 26.0,
                      color: Colors.black,
                    )),
              ),

4. child属性

按钮的子组件,通常是一个TextIcon等用于显示按钮内容的组件

5. onHighlightChanged属性

当按钮被按下或释放时触发的回调函数

6. focusNode属性

控制按钮的焦点状态

7. autofocus属性

是否自动获取焦点

8. clipBehavior属性

内容溢出时的裁剪行为

9. enableFeedback属性

是否为按钮点击提供音频和触觉反馈

二、开发简单的登录页面

登录页比较简单,用户名+密码+登录按钮。采用Material风格脚手架。

Dart 复制代码
import 'package:flutter/material.dart';

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

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo', // 标题
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.

  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
  int _counter = 0;

  // 文本内容
  String textToShow = 'I love Flutter!';

  // 创建焦点节点对象
  FocusNode _nameFocusNode = FocusNode();
  FocusNode _passwordFocusNode = FocusNode();

  // 记录焦点状态
  bool _nameHasFocus = false;
  bool _passwordHasFocus = false;

  /**
   * 动画控制器
   */
  late AnimationController controller;

  /**
   * 角度动画
   */
  late CurvedAnimation curve;

  void _incrementCounter() {
    setState(() {
      // This call to setState tells the Flutter framework that something has
      // changed in this State, which causes it to rerun the build method below
      // so that the display can reflect the updated values. If we changed
      // _counter without calling setState(), then the build method would not be
      // called again, and so nothing would appear to happen.
      _counter++;
      // 更新文本内容
      if (_counter % 4 == 0) {
        textToShow = 'I Study Flutter now';
      } else if (_counter % 4 == 1) {
        textToShow = 'Flutter is so interesting';
      } else if (_counter % 4 == 2) {
        textToShow = 'I love it more';
      } else {
        textToShow = 'I learn it more funny';
      }
    });
    // 播放动画
    controller.forward();
  }

  /**
   * 监听输入框焦点变化,焦点变化时保存焦点状态
   */
  void _nameFocusChange() {
    // 存储状态变化
    setState(() {
      _nameHasFocus = _nameFocusNode.hasFocus;
    });
  }

  /**
   * 监听输入框焦点变化,焦点变化时保存焦点状态
   */
  void _passwdFocusChange() {
    // 存储状态变化
    setState(() {
      _passwordHasFocus = _passwordFocusNode.hasFocus;
    });
  }

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      duration: const Duration(milliseconds: 2000),
      vsync: this,
    );
    curve = CurvedAnimation(
      parent: controller,
      curve: Curves.easeIn,
    );
    // 监听输入框焦点变化
    _nameFocusNode.addListener(_nameFocusChange);
    _passwordFocusNode.addListener(_passwdFocusChange);
  }

  @override
  void dispose() {
    _nameFocusNode.removeListener(_nameFocusChange);
    _passwordFocusNode.removeListener(_passwdFocusChange);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // This method is rerun every time setState is called, for instance as done
    // by the _incrementCounter method above.
    //
    // The Flutter framework has been optimized to make rerunning build methods
    // fast, so that you can just rebuild anything that needs updating rather
    // than having to individually change instances of widgets.
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text(widget.title),
      ),
      body: Center(
        child: Padding(
          padding: EdgeInsets.all(12.0),
          child: Column(
            // Column is also a layout widget. It takes a list of children and
            // arranges them vertically. By default, it sizes itself to fit its
            // children horizontally, and tries to be as tall as its parent.
            //
            // Invoke "debug painting" (press "p" in the console, choose the
            // "Toggle Debug Paint" action from the Flutter Inspector in Android
            // Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
            // to see the wireframe for each widget.
            //
            // Column has various properties to control how it sizes itself and
            // how it positions its children. Here we use mainAxisAlignment to
            // center the children vertically; the main axis here is the vertical
            // axis because Columns are vertical (the cross axis would be
            // horizontal).
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const Text(
                '用户登录',
                style: TextStyle(
                    fontSize: 25.0,
                    color: Colors.black,
                    fontWeight: FontWeight.w200),
              ),
              SizedBox(height: 12.0),
              TextField(
                focusNode: _nameFocusNode,
                decoration: InputDecoration(
                  filled: true,
                  fillColor:
                  _nameHasFocus ? Colors.lightBlue[100] : Colors.grey[200],
                  border: OutlineInputBorder(),
                  hintText: '请输入姓名',
                  hintStyle: TextStyle(color: Colors.grey),
                  prefixIcon: Icon(Icons.person),
                ),
              ),
              SizedBox(height: 12.0),
              TextField(
                focusNode: _passwordFocusNode,
                obscureText: true, // 定输入框的文本是否应该被隐藏,常用于密码输入框
                decoration: InputDecoration(
                  filled: true,
                  fillColor:
                  _nameHasFocus ? Colors.lightBlue[100] : Colors.grey[200],
                  border: OutlineInputBorder(),
                  hintText: '请输入密码',
                  hintStyle: TextStyle(color: Colors.grey),
                  prefixIcon: Icon(Icons.lock),
                ),
              ),
              TextField(
                enabled: true,
                style: TextStyle(
                  fontSize: 20.0, color: Colors.black,
                  backgroundColor: Colors.cyan, // 文本输入颜色
                ),
              ),
              Text(
                'You have pushed the button this many times:',
              ),
              Text(
                '$_counter',
                style: Theme
                    .of(context)
                    .textTheme
                    .headline4,
              ),
              // 新增一个自定义的Text(在State中存储)
              Text(textToShow),
              Center(
                child: FadeTransition(
                  opacity: curve,
                  child: const FlutterLogo(
                    size: 100,
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

参考文献:

Flutter速来系列6: Flutter同学 输入框TextField就算了,还整个表单? - 掘金

相关推荐
君蓦2 小时前
Flutter 本地存储与数据库的使用和优化
flutter
problc11 小时前
Flutter中文字体设置指南:打造个性化的应用体验
android·javascript·flutter
lqj_本人20 小时前
鸿蒙next选择 Flutter 开发跨平台应用的原因
flutter·华为·harmonyos
lqj_本人1 天前
Flutter&鸿蒙next 状态管理框架对比分析
flutter·华为·harmonyos
起司锅仔1 天前
Flutter启动流程(2)
flutter
hello world smile1 天前
最全的Flutter中pubspec.yaml及其yaml 语法的使用说明
android·前端·javascript·flutter·dart·yaml·pubspec.yaml
lqj_本人1 天前
Flutter 的 Widget 概述与常用 Widgets 与鸿蒙 Next 的对比
flutter·harmonyos
iFlyCai1 天前
极简实现酷炫动效:Flutter隐式动画指南第二篇之一些酷炫的隐式动画效果
flutter
lqj_本人1 天前
Flutter&鸿蒙next 中使用 MobX 进行状态管理
flutter·华为·harmonyos