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(
                    "https://s1.51cto.com/images/20190423/1556012017949570.png"),
                width: 120.0,
                fit: BoxFit.contain,
              ),
              new Text(
                "",
                style: textStyleAssetFont1,
              ),
              new Image.network(
                "https://s1.51cto.com/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.pngblob.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

    


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章