Flutter第三期 - 基础控件demo1

    开始学习一门全新的语言确实很慢,需要了解很多控件,个人的做法是大家都记不住这么多,所以就要做一个件事,那就是写博客,把你看到的情况都列出来,这样你遇到需求的时候就去翻翻控件那一篇,copycopy就记住了,也没有那么不想学了,可以去试试~这篇是我总结的各种前期遇到比较多的控件样式设置写法,以后会更新下去,这样每次记不住回来看一眼,跟API一样~

    1.Widget:多写几次你会发现越写越顺,其实不是很绕,一看上去有点小乱,后面由于google智能的换行,所以很好找~试试吧~

import 'package:flutter/material.dart';

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

//Stateless widgets 是不可变的, 这意味着它们的属性不能改变 - 所有的值都是最终的.
//Stateful widgets 持有的状态可能在widget生命周期中发生变化. 实现一个 stateful widget 至少需要两个类:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
//    final wordPair = new WordPair.random();
    return new MaterialApp(
      title: 'Welcome to Flutter',
      debugShowCheckedModeBanner: false,
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text('Welcome to Flutter'),
        ),
        body: new Center(
          child: new Text('Hello World'),
        ),
      ),
    );
  }
}

    

blob.png

    2.文本及样式:我总结了一些常用的后续会继续更新,直接拿去用,目前看应该够用~

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

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

//void main() {
//  runApp(new MaterialApp(
//    home: new MyApp(),
//  ));
//}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new MaterialApp(
      title: 'Flutter Demo1',
      debugShowCheckedModeBanner: false,
      theme: new ThemeData(
        primarySwatch: Colors.blue,
//        fontFamily: 'fontdemo1'
      ),
      home: new MyHomePage(title: '文本及样式'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return new _MyHomePageState();
  }
}

class _MyHomePageState extends State<MyHomePage> {
  final textStyleAssetFont1 = const TextStyle(
    fontFamily: 'fontdemo1',
  );
  final textStyleAssetFont2 = const TextStyle(
    fontFamily: 'fontdemo2',
  );
  final textStyleAssetFont3 = const TextStyle(
    letterSpacing: 2.0,
  );
  final textStyleAssetFont4 = const TextStyle(
    height: 2.0,
  );

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(
          widget.title,
          style: textStyleAssetFont2,
        ),
      ),
      body: new Center(
        child: new Column(
//          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            new Text(
              "1.hi yun~",
              textAlign: TextAlign.start,
              style: textStyleAssetFont3,
            ),
            new Text(
              "2.hi yun~" * 16,
              maxLines: 1,
              overflow: TextOverflow.ellipsis,
              style: textStyleAssetFont4,
//              style: Theme.of(context).textTheme.display1,
            ),
            new Text(
              "3.hi yun~",
              textScaleFactor: 1.5,
              style: textStyleAssetFont4,
            ),
            new Text(
              "4.hi yun~" * 16,
              textAlign: TextAlign.start,
              style: textStyleAssetFont4,
            ),
            new Text(
              "5.hi yun~",
              style: TextStyle(
                  color: Colors.blue,
                  fontSize: 18.0,
                  height: 2.0,
                  fontFamily: "Courier",
                  background: new Paint()..color = Colors.yellow,
                  decoration: TextDecoration.underline,
                  decorationStyle: TextDecorationStyle.dashed),
            ),
            new Text(
              "红色+黑色删除线+25号",
              style: new TextStyle(
                color: const Color(0xffff0000),
                decoration: TextDecoration.lineThrough,
                decorationColor: const Color(0xff000000),
                fontSize: 25.0,
              ),
            ),
            new Text.rich(TextSpan(children: [
              TextSpan(text: "6.Yun:"),
              TextSpan(
                text: "https://flutterchina.club",
                style: TextStyle(
                  color: Colors.blue,
                  height: 2.0,
                ),
//                  recognizer: _tapRecognizer
              ),
            ])),
            DefaultTextStyle(
              style: TextStyle(
                color: Colors.red,
                fontSize: 20.0,
                height: 2.0,
              ),
              textAlign: TextAlign.start,
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Text("7.hi yun1~"),
                  Text("7.hi yun2~"),
                  Text(
                    "7.hi yun3~",
                    style: TextStyle(
                      inherit: false,
                      color: Colors.grey,
                      height: 2.0,
                    ),
                  ),
                  Text(
                    "8.hi yun~",
                    style: textStyleAssetFont2,
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

    

blob.png

    需要注意的是路径要对:

name: p001_flutter_demo1
description: A new Flutter application.

# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# Read more about versioning at semver.org.
version: 1.0.0+1

environment:
  sdk: ">=2.0.0-dev.68.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.2
  english_words: ^3.1.5

dev_dependencies:
  flutter_test:
    sdk: flutter


# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec

# The following section is specific to Flutter.
flutter:

  # The following line ensures that the Material Icons font is
  # included with your application, so that you can use the icons in
  # the material Icons class.
  uses-material-design: true

  assets:
    - assets/demo.txt
    - assets/images/
  # To add assets to your application, add an assets section, like this:
  # assets:
  #  - images/a_dot_burr.jpeg
  #  - images/a_dot_ham.jpeg

  # An image asset can refer to one or more resolution-specific "variants", see
  # https://flutter.io/assets-and-images/#resolution-aware.

  # For details regarding adding assets from package dependencies, see
  # https://flutter.io/assets-and-images/#from-packages

  # To add custom fonts to your application, add a fonts section here,
  # in this "flutter" section. Each entry in this list should have a
  # "family" key with the font family name, and a "fonts" key with a
  # list giving the asset and other descriptors for the font. For
  # example:
  # fonts:
  #   - family: Schyler
  #     fonts:
  #       - asset: fonts/Schyler-Regular.ttf
  #       - asset: fonts/Schyler-Italic.ttf
  #         style: italic
  #   - family: Trajan Pro
  #     fonts:
  #       - asset: fonts/TrajanPro.ttf
  #       - asset: fonts/TrajanPro_Bold.ttf
  #         weight: 700
  #
  fonts:
    - family: fontdemo1
      fonts:
        - asset: assets/fonts/NotoSerifTC-Bold.otf
          style: italic
    - family: fontdemo2
      fonts:
        - asset: assets/fonts/ZCOOLKuaiLe-Regular.ttf
          weight: 500
    - family: iconfont
      fonts:
        - asset: assets/fonts/iconfont.ttf
          weight: 700
  # For details regarding fonts from package dependencies,
  # see https://flutter.io/custom-fonts/#from-packages

    

blob.png

    3.图片及icon:这里多了一个iconfont.cn的操作,大家可以了解一下

import 'package:flutter/material.dart';

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

//Stateless widgets 是不可变的, 这意味着它们的属性不能改变 - 所有的值都是最终的.
//Stateful widgets 持有的状态可能在widget生命周期中发生变化. 实现一个 stateful widget 至少需要两个类:

class MyApp extends StatelessWidget {
  final textStyleAssetFont1 = const TextStyle(
    height: 0.5,
  );

  @override
  Widget build(BuildContext context) {
//    final wordPair = new WordPair.random();
    return new MaterialApp(
      title: 'Welcome to Flutter',
      debugShowCheckedModeBanner: false,
      theme: new ThemeData(
        primarySwatch: Colors.blue,
//        fontFamily: 'fontdemo1'
      ),
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text('图片加载'),
        ),
        body: new Center(
          child: new Column(
            crossAxisAlignment: CrossAxisAlignment.center,
//            mainAxisAlignment: MainAxisAlignment.start,
            children: <Widget>[
//              CustomScrollView(
//                slivers: <Widget>[
//
//                ],
//              ),
              new Text(
                "",
                style: textStyleAssetFont1,
              ),
              new Image(
                image: AssetImage("assets/images/food01.jpeg"),
                fit: BoxFit.fill,
                width: 120.0,
              ),
              new Text(
                "",
                style: textStyleAssetFont1,
              ),
              new Image.asset(
                "assets/images/food02.jpeg",
                width: 120.0,
                fit: BoxFit.cover,
              ),
              new Text(
                "",
                style: textStyleAssetFont1,
              ),
              new Image(
                image: NetworkImage(
                    "http://www.icode9.com/i/li/?n=1&i=images/20190423/1556012017949570.png"),
                width: 120.0,
                fit: BoxFit.contain,
              ),
              new Text(
                "",
                style: textStyleAssetFont1,
              ),
              new Image.network(
                "http://www.icode9.com/i/li/?n=1&i=images/20190423/1556012017949570.png",
                width: 120.0,
                fit: BoxFit.fill,
              ),
              new Text(
                "",
                style: textStyleAssetFont1,
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Icon(
                    Icons.accessible,
                    color: Colors.green,
                  ),
                  Icon(
                    Icons.error,
                    color: Colors.green,
                  ),
                  Icon(
                    Icons.fingerprint,
                    color: Colors.green,
                  ),
                ],
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Icon(
                    MyIcons.qq,
                    color: Colors.red,
                  ),
                  Icon(
                    MyIcons.wechat,
                    color: Colors.green,
                  ),
                ],
              )
            ],
          ),
        ),
      ),
    );
  }
}

class MyIcons {
  // book 图标
  static const IconData qq =
      const IconData(0xe606, fontFamily: 'iconfont', matchTextDirection: true);

  // 微信图标
  static const IconData wechat =
      const IconData(0xe607, fontFamily: 'iconfont', matchTextDirection: true);
}

    

blob.png

blob.png

    

blob.png

    

blob.png

    

    

    4.单选开关和复选框:

import 'package:flutter/material.dart';

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

//Stateless widgets 是不可变的, 这意味着它们的属性不能改变 - 所有的值都是最终的.
//Stateful widgets 持有的状态可能在widget生命周期中发生变化. 实现一个 stateful widget 至少需要两个类:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new MaterialApp(
      title: "单选框和复选框",
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text("单选框和复选框"),
        ),
        body: new Center(
          child: new SwitchAndCheckBoxTestRoute(),
        ),
      ),
    );
  }
}

class SwitchAndCheckBoxTestRoute extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return new _SwitchAndCheckBoxTestRoute();
  }
}

class _SwitchAndCheckBoxTestRoute extends State<SwitchAndCheckBoxTestRoute> {
  bool _switchSelected = true;
  bool _checkboxSelected = true;

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new Column(
      children: <Widget>[
        Switch(
          value: _switchSelected,
          activeColor: Colors.blue,
          inactiveThumbColor: Colors.lightBlueAccent,
          onChanged: (value) {
            setState(() {
              _switchSelected = value;
            });
          },
        ),
        Checkbox(
          value: _checkboxSelected,
          activeColor: Colors.red,
          onChanged: (value) {
            setState(() {
              _checkboxSelected = value;
            });
          },
        ),
      ],
    );
  }
}

 

blob.png

    5.输入框和表单:这块比较复杂,我在学习过程中遇到很多问题,找到了一些方案,最常见的就是布局问题,键盘遮挡,目前找到的这个方案比较合适,希望能帮到你~

    解决遮挡的基类:

/**
 * 作者:Created by H on 2019/1/23 11:08.
 * 介绍: 解决输入框被遮挡问题
 */
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

///
/// Helper class that ensures a Widget is visible when it has the focus
/// For example, for a TextFormField when the keyboard is displayed
///
/// How to use it:
///
/// In the class that implements the Form,
///   Instantiate a FocusNode
///   FocusNode _focusNode = new FocusNode();
///
/// In the build(BuildContext context), wrap the TextFormField as follows:
///
///   new EnsureVisibleWhenFocused(
///     focusNode: _focusNode,
///     child: new TextFormField(
///       ...
///       focusNode: _focusNode,
///     ),
///   ),
///
/// Initial source code written by Collin Jackson.
/// Extended (see highlighting) to cover the case when the keyboard is dismissed and the
/// user clicks the TextFormField/TextField which still has the focus.
///
class EnsureVisibleWhenFocused extends StatefulWidget {
  const EnsureVisibleWhenFocused({
    Key key,
    @required this.child,
    @required this.focusNode,
    this.curve: Curves.ease,
    this.duration: const Duration(milliseconds: 100),
  }) : super(key: key);

  /// The node we will monitor to determine if the child is focused
  final FocusNode focusNode;

  /// The child widget that we are wrapping
  final Widget child;

  /// The curve we will use to scroll ourselves into view.
  ///
  /// Defaults to Curves.ease.
  final Curve curve;

  /// The duration we will use to scroll ourselves into view
  ///
  /// Defaults to 100 milliseconds.
  final Duration duration;

  @override
  _EnsureVisibleWhenFocusedState createState() => new _EnsureVisibleWhenFocusedState();
}

///
/// We implement the WidgetsBindingObserver to be notified of any change to the window metrics
///
class _EnsureVisibleWhenFocusedState extends State<EnsureVisibleWhenFocused> with WidgetsBindingObserver  {

  @override
  void initState(){
    super.initState();
    widget.focusNode.addListener(_ensureVisible);
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose(){
    WidgetsBinding.instance.removeObserver(this);
    widget.focusNode.removeListener(_ensureVisible);
    super.dispose();
  }

  ///
  /// This routine is invoked when the window metrics have changed.
  /// This happens when the keyboard is open or dismissed, among others.
  /// It is the opportunity to check if the field has the focus
  /// and to ensure it is fully visible in the viewport when
  /// the keyboard is displayed
  ///
  @override
  void didChangeMetrics(){
    if (widget.focusNode.hasFocus){
      _ensureVisible();
    }
  }

  ///
  /// This routine waits for the keyboard to come into view.
  /// In order to prevent some issues if the Widget is dismissed in the
  /// middle of the loop, we need to check the "mounted" property
  ///
  /// This method was suggested by Peter Yuen (see discussion).
  ///
  Future<Null> _keyboardToggled() async {
    if (mounted){
      EdgeInsets edgeInsets = MediaQuery.of(context).viewInsets;
      while (mounted && MediaQuery.of(context).viewInsets == edgeInsets) {
        await new Future.delayed(const Duration(milliseconds: 10));
      }
    }

    return;
  }

  Future<Null> _ensureVisible() async {
    // Wait for the keyboard to come into view
    await Future.any([new Future.delayed(const Duration(milliseconds: 300)), _keyboardToggled()]);

    // No need to go any further if the node has not the focus
    if (!widget.focusNode.hasFocus){
      return;
    }

    // Find the object which has the focus
    final RenderObject object = context.findRenderObject();
    final RenderAbstractViewport viewport = RenderAbstractViewport.of(object);
    assert(viewport != null);

    // Get the Scrollable state (in order to retrieve its offset)
    ScrollableState scrollableState = Scrollable.of(context);
    assert(scrollableState != null);

    // Get its offset
    ScrollPosition position = scrollableState.position;
    double alignment;

    if (position.pixels > viewport.getOffsetToReveal(object, 0.0).offset) {
      // Move down to the top of the viewport
      alignment = 0.0;
    } else if (position.pixels < viewport.getOffsetToReveal(object, 1.0).offset){
      // Move up to the bottom of the viewport
      alignment = 1.0;
    } else {
      // No scrolling is necessary to reveal the child
      return;
    }

    position.ensureVisible(
      object,
      alignment: alignment,
      duration: widget.duration,
      curve: widget.curve,
    );
  }

  @override
  Widget build(BuildContext context) {
    return widget.child;
  }
}

    如何使用:

import 'package:flutter/material.dart';

import 'main15.dart';

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

//Stateless widgets 是不可变的, 这意味着它们的属性不能改变 - 所有的值都是最终的.
//Stateful widgets 持有的状态可能在widget生命周期中发生变化. 实现一个 stateful widget 至少需要两个类:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new MaterialApp(
      title: "输入框及表单",
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text("输入框及表单"),
        ),
        body: new Center(
//          child: new FormTestRoute(),
          child: new TestPage(),
        ),
      ),
    );
  }
}

class TestPage extends StatefulWidget {
  @override
  _TestPageState createState() => new _TestPageState();
}

class _TestPageState extends State<TestPage> {
  final GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
  FocusNode _focusNodeFirstName = new FocusNode();
  FocusNode _focusNodeLastName = new FocusNode();
  FocusNode _focusNodeDescription = new FocusNode();
  static final TextEditingController _firstNameController =
      new TextEditingController();
  static final TextEditingController _lastNameController =
      new TextEditingController();
  static final TextEditingController _pwdController =
      new TextEditingController();
  static final TextEditingController _descriptionController =
      new TextEditingController();

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
//      appBar: new AppBar(
//        title: new Text('My Test Page'),
//      ),
      body: new SafeArea(
        top: false,
        bottom: false,
        child: new Form(
          key: _formKey, //设置globalKey,用于后面获取FormState
          autovalidate: true, //开启自动校验
          child: new SingleChildScrollView(
            padding: const EdgeInsets.symmetric(horizontal: 16.0),
            child: new Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: <Widget>[
                /* -- Something large -- */
                Container(
                  width: double.infinity,
                  height: 150.0,
                  color: Colors.red,
                ),

                /* -- First Name -- */
                new EnsureVisibleWhenFocused(
                  focusNode: _focusNodeFirstName,
                  child: new TextFormField(
                    decoration: const InputDecoration(
                      border: const UnderlineInputBorder(),
                      filled: true,
                      icon: const Icon(Icons.person),
                      labelText: "用户名",
                      hintText: "用户名或邮箱",
                    ),
                    // 校验用户名
                    validator: (v) {
                      return v.trim().length > 0 ? null : "用户名不能为空";
                    },
                    onSaved: (String value) {
                      //TODO
                    },
                    controller: _firstNameController,
                    focusNode: _focusNodeFirstName,
                  ),
                ),
                const SizedBox(height: 24.0),

                /* -- Last Name -- */
                new EnsureVisibleWhenFocused(
                  focusNode: _focusNodeLastName,
                  child: new TextFormField(
                    decoration: const InputDecoration(
                      border: const UnderlineInputBorder(),
                      filled: true,
                      icon: const Icon(Icons.lock),
                      labelText: "密码",
                      hintText: "您的登录密码",
                    ),
                    obscureText: true,
                    //校验密码
                    validator: (v) {
                      return v.trim().length > 5 ? null : "密码不能少于6位";
                    },
                    onSaved: (String value) {
                      //TODO
                    },
//                    controller: _lastNameController,
                    controller: _pwdController,
                    focusNode: _focusNodeLastName,
                  ),
                ),
                const SizedBox(height: 24.0),

                /* -- Some other fields -- */
                new Container(
                  width: double.infinity,
                  height: 250.0,
                  color: Colors.blue,
                ),

                /* -- Description -- */
                new EnsureVisibleWhenFocused(
                  focusNode: _focusNodeDescription,
                  child: new TextFormField(
                    decoration: const InputDecoration(
                      border: const OutlineInputBorder(),
                      hintText: '请介绍一下自己',
                      labelText: '简介',
                    ),
                    onSaved: (String value) {
                      //TODO
                    },
                    maxLines: 5,
                    controller: _descriptionController,
                    focusNode: _focusNodeDescription,
                  ),
                ),
                const SizedBox(height: 24.0),

                /* -- Save Button -- */
                new Center(
                  child: new RaisedButton(
                    child: const Text('确定'),
                    onPressed: () {
                      //TODO
                      if ((_formKey.currentState as FormState).validate()) {
                        //验证通过提交数据
                      }
                    },
                  ),
                ),
                const SizedBox(height: 24.0),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

//class FormTestRoute extends StatefulWidget {
//  @override
//  _FormTestRouteState createState() => new _FormTestRouteState();
//}
//
//class _FormTestRouteState extends State<FormTestRoute> {
//  TextEditingController _unameController = new TextEditingController();
//  TextEditingController _pwdController = new TextEditingController();
//  GlobalKey _formKey = new GlobalKey<FormState>();
//  FocusNode _focusNode = new FocusNode();
//
//  @override
//  Widget build(BuildContext context) {
//    return Scaffold(
////      title: "Form Test",
//
//      body: Padding(
//        padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 24.0),
//        child: Form(
//          key: _formKey, //设置globalKey,用于后面获取FormState
//          autovalidate: true, //开启自动校验
//          child: Column(
//            children: <Widget>[
//              new EnsureVisibleWhenFocused(
//                focusNode: _focusNode,
//                child: new TextFormField(
//                  autofocus: true,
//                  controller: _unameController,
//                  decoration: InputDecoration(
//                      labelText: "用户名",
//                      hintText: "用户名或邮箱",
//                      icon: Icon(Icons.person)),
//                  // 校验用户名
//                  validator: (v) {
//                    return v.trim().length > 0 ? null : "用户名不能为空";
//                  },
//                  focusNode: _focusNode,
//                ),
//              ),
//              new EnsureVisibleWhenFocused(
//                focusNode: _focusNode,
//                child: new TextFormField(
//                  controller: _pwdController,
//                  decoration: InputDecoration(
//                      labelText: "密码",
//                      hintText: "您的登录密码",
//                      icon: Icon(Icons.lock)),
//                  obscureText: true,
//                  //校验密码
//                  validator: (v) {
//                    return v.trim().length > 5 ? null : "密码不能少于6位";
//                  },
//                  focusNode: _focusNode,
//                ),
//              ),
////              TextFormField(
////                autofocus: true,
////                controller: _unameController,
////                decoration: InputDecoration(
////                    labelText: "用户名",
////                    hintText: "用户名或邮箱",
////                    icon: Icon(Icons.person)),
////                // 校验用户名
////                validator: (v) {
////                  return v.trim().length > 0 ? null : "用户名不能为空";
////                },
////              ),
////              TextFormField(
////                controller: _pwdController,
////                decoration: InputDecoration(
////                    labelText: "密码",
////                    hintText: "您的登录密码",
////                    icon: Icon(Icons.lock)),
////                obscureText: true,
////                //校验密码
////                validator: (v) {
////                  return v.trim().length > 5 ? null : "密码不能少于6位";
////                },
////              ),
//              // 登录按钮
//              Padding(
//                padding: const EdgeInsets.only(top: 28.0),
//                child: Row(
//                  children: <Widget>[
//                    Expanded(
//                      child: RaisedButton(
//                        padding: EdgeInsets.all(15.0),
//                        child: Text("登录"),
//                        color: Theme.of(context).primaryColor,
//                        textColor: Colors.white,
//                        onPressed: () {
//                          //在这里不能通过此方式获取FormState,context不对
//                          //print(Form.of(context));
//
//                          // 通过_formKey.currentState 获取FormState后,
//                          // 调用validate()方法校验用户名密码是否合法,校验
//                          // 通过后再提交数据。
//                          if ((_formKey.currentState as FormState).validate()) {
//                            //验证通过提交数据
//                          }
//                        },
//                      ),
//                    ),
//                  ],
//                ),
//              )
//            ],
//          ),
//        ),
//      ),
//    );
//  }
//}

    

blob.png

    需要注意的是自定义布局的时候要保证开启全局校验,还有就是官方的PageScaffold目前没找到,可能是官方废弃了吧,后续再看,可以用Scaffold替换,另外还有自定义样式的写法BoxDecoration是关键,可以查查资料结合下面的代码修改,基本可以搞定一般的不带动画的需求~

import 'package:flutter/material.dart';

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

//Stateless widgets 是不可变的, 这意味着它们的属性不能改变 - 所有的值都是最终的.
//Stateful widgets 持有的状态可能在widget生命周期中发生变化. 实现一个 stateful widget 至少需要两个类:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new MaterialApp(
      title: "输入框及表单",
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text("输入框及表单"),
        ),
        body: new Center(
          child: new FormTestRoute(),
        ),
      ),
    );
  }
}

class FormTestRoute extends StatefulWidget {
  @override
  _FormTestRouteState createState() => new _FormTestRouteState();
}

class _FormTestRouteState extends State<FormTestRoute> {
  TextEditingController _unameController = new TextEditingController();
  TextEditingController _pwdController = new TextEditingController();
  GlobalKey _formKey = new GlobalKey<FormState>();
  FocusNode _focusNode = new FocusNode();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
//      title: "Form Test",

      body: Container(
        padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 24.0),
        decoration: BoxDecoration(
            // 下滑线浅灰色,宽度1像素
            border: Border(
                bottom: BorderSide(color: Colors.grey[200], width: 1.0))),
        child: Form(
          key: _formKey, //设置globalKey,用于后面获取FormState
          autovalidate: true, //开启自动校验
          child: Column(
            children: <Widget>[
              TextFormField(
                autofocus: true,
                controller: _unameController,
                decoration: InputDecoration(
                  labelText: "用户名",
                  hintText: "用户名或邮箱",
                  icon: Icon(Icons.person),
                  border: InputBorder.none, //隐藏下划线
                ),
                // 校验用户名
                validator: (v) {
                  return v.trim().length > 0 ? null : "用户名不能为空";
                },
              ),
              TextFormField(
                controller: _pwdController,
                decoration: InputDecoration(
                    labelText: "密码",
                    hintText: "您的登录密码",
                    icon: Icon(Icons.lock)),
                obscureText: true,
                //校验密码
                validator: (v) {
                  return v.trim().length > 5 ? null : "密码不能少于6位";
                },
              ),
              // 登录按钮
              Padding(
                padding: const EdgeInsets.only(top: 28.0),
                child: Row(
                  children: <Widget>[
                    Expanded(
                      child: RaisedButton(
                        padding: EdgeInsets.all(15.0),
                        child: Text("登录"),
                        color: Theme.of(context).primaryColor,
                        textColor: Colors.white,
                        onPressed: () {
                          //在这里不能通过此方式获取FormState,context不对
                          //print(Form.of(context));

                          // 通过_formKey.currentState 获取FormState后,
                          // 调用validate()方法校验用户名密码是否合法,校验
                          // 通过后再提交数据。
                          if ((_formKey.currentState as FormState).validate()) {
                            //验证通过提交数据
                          }
                        },
                      ),
                    ),
                  ],
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}

    

blob.png

    总结:因为周末了,所以今天讲的有点多,可以慢慢敲一遍,你会发现dart是真心强,用的舒服~撸起袖子,继续更新ing~   

    

logo.jpg

    


原文地址:https://blog.51cto.com/liangxiao/2385077

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


这篇文章主要讲解了“FlutterComponent动画的显和隐怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究...
这篇文章主要讲解了“flutter微信聊天输入框功能如何实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“f...
本篇内容介绍了“Flutter之Navigator的高级用法有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处...
这篇文章主要介绍“Flutter怎么使用Android原生播放器”,在日常操作中,相信很多人在Flutter怎么使用Android原生播放器问题上存在疑惑,小编查阅了各式资料,整...
Flutter开发的android端如何修改APP名称,logo,版本号,具体的操作步骤:修改APP名称找到文件:android\\app\\src\\main\\AndroidManifest.xml
Flutter路由管理初识路由概念一.路由管理1.1.Route1.2.MaterialPageRoute1.3.Navigator1.4.路由传值1.5 命名路由1.6.命名路由参数传递1.7.适配二、路由钩子三、onUnknownRoute四、结尾初识路由概念路由的概念由来已久,包括网络路由、后端路由,到现在广为流行的前端路由。无论路由的概念如何应用,它的核心是一个路由映射表。比如:名字 detail 映射到 DetailPage 页面等。有了这个映射表之后,我们就可以方便的根据名字来完成路由的转发
前提:针对Android开发者(windows系统下),已安装Git,AndroidStudio(建议4.0+版本)一.下载Flutter SDK地址:https://flutter.dev/docs/development/tools/sdk/releases,在 Stable channel (Windows)里面下最新版本即可。Flutter的渠道版本会不停变动,请以Flutter官网为准。在中国,要想正常获取安装包列表或下载安装包,可能需要翻墙,也可以去Flutter github项目下去下载安
一、变量变量是一个引用,根据Dart中“万物皆对象”原则,即变量存储的都是对象的引用,或者说它们都是指向对象。1.1.声明变量://1.不指定类型var name = 'aaa';//2.明确指定类型String name = 'aaa';因为有类型推导,所以两种实现效果一样,官方推荐在函数内的本地变量尽量使用var声明。在变量类型并不明确的情况下,可以使用dynamic关键字//3.使用dynamic关键字dynamic name = 'aaa';1.2.默认值未初始化的变量
前言Flutter2.0发布不久,对web的支持刚刚进入stable阶段。初学几天,构建web应用时候碰到一些问题,比如中文显示成乱码,然后加载图片出现图片跨域问题:Failed to load network image...Trying to load an image from another domain?1.开启web端构建:使用下面这个命令才可以开启Web端构建的支持flutter config --enable-web提示我们:重新启动编辑器,以便它们读取新设置。2.重
一.Flutter打Android release包的步骤:1.为项目创建一个.jks签名文件(很简单,跳过)2.创建一个文件key.properties,直接复制下面key.properties位置如图:在里面输入一下内容:storePassword=iflytekkeyPassword=iflytekkeyAlias=teachingmachinestoreFile=E:/teacher/app/keys/TeachingMachine.jks输入你自己的passwork以及
1 问题Android原生向js发消息,并且可以携带数据2 实现原理Android原生可以使用RCTEventEmitter来注册事件,然后这里需要指定事件的名字,然后在js那端进行监听同样事件的名字监听,就可以收到消息得到数据Android注册关键代码reactContext.getJSModule(DeviceEventManagerModule.RCT...
1 Flexbox布局1) flexDirection 可以决定布局的主轴,子元素是应该沿着水平轴(row)方向排列,还是沿着竖直轴(column)方向排列2) justifyContent 决定其子元素沿着次轴(与主轴垂直的轴,比如若主轴方向为row,则次轴方向为column)的排列方式 有flex-start、center、flex-end、space-around...
1 实现的功能在网上看React Native文档,我特码就想实现一个页面到另外一个页面的跳转,然后另外一个页面怎么获取参数,特么没找到一个说清楚的,要么太复杂,要么说了不理解,下面是我自己写的一个App.js文件,实现一个Home页面跳到另外Details页面,并且携带了参数怎么在Details页面获取,就是这么简单粗暴.2 测试DemoApp.js文件如下...
1 问题在一个文件构建一个对象,然后在另外一个文件里面new这个对象,通过构造方法传递参数,然后再获取这个参数2 测试代码Student.js文件如下'use strict';import React from 'react'import {NativeModules, NativeEventEmitter, DeviceEventEmitter,Ale...
1 简单部分代码export default class App extends Component&amp;lt;Props&amp;gt; { render() { return ( &amp;lt;View {styles.container}&amp;gt; &amp;lt;View {styles.welcome}&amp;gt; &amp;l...
1 怎么实现发送和接收事件理论上封装了Android原生广播的代码,需要注册和反注册,这里用DeviceEventEmitter实现//增加监听DeviceEventEmitter.addListener//取消监听//this.emitter.remove();这里可也可以通过安卓原生向页面js发送消息,可以参考我的这篇博客React Native之Android原生通过Dev...
1、Component介绍一般Component需要被其它类进行继承,Component和Android一样,也有生命周期英文图片如下2 具体说明1)、挂载阶段constructor()//构造函数,声明之前先调用super(props)componentWillMount()//因为它发生在render()方法前,因此在该方法内同步设置状态...
1 触摸事件普通点击我们可以使用onPress方法,我们可以使用Touchable 系列控件设计我们的按钮TouchableHighlight 背景会在用户手指按下时变暗TouchableNativeFeedback用户手指按下时形成类似墨水涟漪的视觉效果TouchableOpacity指按下时降低按钮的透明度,而不会改变背景的颜色TouchableWithoutFeedbac...
1 问题部分代码如下class HomeScreen extends React.Component { render() { return ( &amp;lt;View {{ flex: 1, alignItems: 'center', justifyContent: 'center' }}&amp;gt; &amp;lt;Text&amp;gt;Home Scre...
1 Props(属性)和State(状态)和简单样式简单使用App.js代码如下/** * Sample React Native App * https://github.com/facebook/react-native * * @format * @flow */import React, {Component} from 'react';import {Pla...