Flutter

二、Flutter之初识Widget

2019-02-21  本文已影响0人  夏_Leon

一、Dart学习

开始写Flutter项目前,建议先学一下Dart,尽管和java很相似,如果学过kotlin会更有帮助。但系统的学习更有利于后面项目的上手,推荐 https://www.jianshu.com/p/3d927a7bf020 系列。当然干读教程是枯燥且低效的,建议和Widget的学习同时进行。

二、flutter文件结构

如上图所示,我们在AS创建一个新的flutter application后生成的文件结构如图:
其中android、ios是对应android、ios平台的,暂时不用管;
我们写的主要代码在lib下,目前就一个main.dart;
图中的images是我自己新建的一个文件夹,用来放资源图片的;
pubspec.yaml是主要的配置文件。

三、flutter布局学习

参考:
官方英文版 https://flutter.io/docs/get-started/flutter-for/android-devs
中文版 https://flutterchina.club/flutter-for-android/
官方对Widget的介绍比较系统,可以慢慢学习。
以及别人的flutter学习教程 https://blog.csdn.net/duo_shine/article/category/7882610/2

import 'package:flutter/material.dart';

void main() {
  //runApp接受的widget将成为widget树的根容器
  runApp(
    //此处的Center即顶层容器,Text是它的子容器,这里就显示了一行text
    new Center(
      child: new Text(
        'Hello World',
        textDirection: TextDirection.ltr,//左对齐,必须
      ),
    ),
  );
}
  runApp(new MaterialApp(
    //title用于任务管理器切换时
    title: "我的应用",
    home: new Center(
      child: new Text(
        'Hello World',
        textDirection: TextDirection.ltr, //左对齐,必须
      ),
    ),
  ));
void main() {
  
  runApp(
    new MaterialApp(
      //title用于任务管理器切换时
      title: "我的应用",
      //使用主题更改Ui
      theme: new ThemeData(
        primaryColor: Colors.deepOrange,
      ),
      home: new Scaffold(
          appBar: new AppBar(
            title: new Text("It is Scaffold AppBar"),
          ),
          body: new Center(
            //Text控件显示各种文本
            child: new Text("Hello World"),
          )),
    ),
  );
  
}

生成了一个有状态栏,白色底,中间单行文字的页面。

import 'package:flutter/material.dart';

void main() {

  runApp(
    new MyApp()
  );

}

//封装app
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      //title用于任务管理器切换时
      title: "我的应用",
      //使用主题更改Ui
      theme: new ThemeData(
        primaryColor: Colors.orange,
      ),

      home: new MyHomeView(),
    );
  }
}

//封装home里的容器
class MyHomeView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Material(
      child: new Scaffold(
        appBar: new AppBar(
            title: new Text("It is Scaffold AppBar"),
          ),
          body: new Center(
            //Text控件显示各种文本
            child: new Text("Hello World 2"),
          )),
    );
  }
}

此时你去修改文字或修改主题色,再ctrl+s都可以热重载直接更新了。

四、Widget学习

Widget类似Android中的View,它是flutter中所有控件的基础,上面的Text、MaterialApp等都是Widget。官方的Widget目录:https://flutterchina.club/widgets/

class RowSample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new Row(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      crossAxisAlignment: CrossAxisAlignment.end,
      children: <Widget>[
        new Text('text 1', textAlign: TextAlign.center),
        new Text(  "text 2",
          textAlign: TextAlign.center,
          maxLines: 1,
          overflow: TextOverflow.ellipsis, // 溢出显示。。。
          style: TextStyle(fontSize: 30.0,// 文字大小
              color: Colors.yellow),// 文字颜色
        ),
        new RichText(
          text: TextSpan(
            text: 'textSpan ',
            style: DefaultTextStyle.of(context).style,
            children: <TextSpan>[
              TextSpan(text: 'bold', style: TextStyle(fontWeight: FontWeight.bold)),
              TextSpan(text: ' world!'),
            ],
          ),
        ),

      ],
    );
  }
}

这是自定义的Row布局,MainAxisAlignment.spaceAround设置为每个子widget都被空白包裹且空白间距一样;子Widget包括Text、RichText,相关属性见注释。
Column也差不多类似,只是排列方向为竖向的。一般可用Row、Column作为基本布局进行排列,像Android里的LinearLayout。

/**
 * demo TextFiled + RaiseButton
 */
//这是TextController,通过它可以从外部访问到该Text的值。下划线前缀标识符,会强制其变成私有的
final TextEditingController _controller =
    new TextEditingController.fromValue(new TextEditingValue(text: "Leon"));

//把TextFiled和RaiseButton控件放在Row里
class TextFieldSample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Row(
      children: <Widget>[
        new Container(
          //此处必须把TextField用Container包裹,否则会报错
          width: MediaQuery.of(context).size.width - 100.0,
          // Subtract sums of paddings and margins from actual width
          child: new TextField(
            //TextField的设置
            controller: _controller,
            decoration: new InputDecoration(
              labelText: '请你输入姓名',
              labelStyle:
                  new TextStyle(fontSize: 13.0, color: Colors.redAccent),
            ),
            textAlign: TextAlign.start,
          ),
        ),

        //自定义按钮
        new RaisedButton(
          onPressed: _printName,
          color: Colors.yellow,
          textColor: Colors.red,
          highlightElevation: 20,

          //Button里的文字也是需要自己构建一个Text
          child: new Text(
            "ClickMe",
            style: new TextStyle(
              color: Colors.red,
            ),
          ),
        ),
      ],
    );
  }
}

//自定义方法在Console输出。下划线前缀标识符,会强制其变成私有的
void _printName() {
  print("Your name is ${_controller.text}");
}

在一个Row里就放了一个文本输入框和一个按钮,具体属性后面再慢慢摸索,要注意:
a、flutter没有像Android的findViewById,要获取输入框的text值怎么办呢,用TextEditingController,并且得在布局前先声明好,在布局中设置controller: _controller,才行;
b、很多时候组件是不能直接放在布局里的,要先装在容器里,像这里的TextField就要先用Container包裹,很多时候布局报错是因为这个原因;
c、dart里没有private、public关键字,在变量、方法名加前缀"_'就表示强制性转为私有的;
d、dart是面向对象的语言,数值、变量、方法都是对象,我们的布局也是对一个个对象进行操作,所以像

        labelStyle:new TextStyle(fontSize: 13.0, color: Colors.redAccent),

是需要我们自己构建一个TextStyle对象。

          child: new Text(
            "ClickMe",
            style: new TextStyle(
              color: Colors.red,
            ),
          ),

不像android里text="ClickMe"就行了,而是要给它一个Text对象,Text对象要你自定义。

/**
 * demo ListView
 */
List _listItems = List.generate(20, (j) => j * j);

class ListViewSample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    if (null == _listItems || _listItems.length == 0) {
      return null;
    }
    return new Expanded(
      child: new ListView.builder(
        scrollDirection: Axis.vertical,
        itemCount: _listItems.length,
        itemBuilder: (context, index) {
          return new ListTile(
            title: new Text('${_listItems[index]}'),
          );
        },
      ),
    );
  }
}

这是一个最简单的ListView,代码量相对于Andoird里要设置Adapter等省了很多。注意这里ListViewSample我是装在Column里的,所以要用Expanded包裹,否则会报错Vertical viewport was given unbounded。而数组初始化用了lamada表达式写的闭包函数,非常简洁。

/**
 * 根页面
 */
class MyHomeView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Material(
        child: new Scaffold(
      appBar: new AppBar(
        title: new Text("It is Scaffold AppBar"),
      ),

      //主体
      body: new Column(
        children: <Widget>[
          new TextSample(), //Text
          new TextFieldSample(), //TextField输入框
        ],
      ),

      //FAB按钮
      floatingActionButton: new FloatingActionButton(
        tooltip: "跳转",
        child: new Icon(Icons.arrow_forward),
        onPressed: () {
          //跳转到第二页面
          Navigator.push(context,
              new MaterialPageRoute(builder: (context) => new SecondScreen()));
        },
        backgroundColor: Colors.pink,
      ),
    ));
  }
}

/**
 * 第二个页面
 */
class SecondScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Material(
        child: new Scaffold(
      appBar: new AppBar(
        title: new Text("It is SecondScreen"),
      ),

      //主体
      body: new Flex(
        direction: Axis.vertical,
        children: <Widget>[
          new ListViewSample(),
        ],
      ),

      //FAB按钮
      floatingActionButton: new FloatingActionButton(
        tooltip: "返回",
        child: new Icon(Icons.arrow_back),
        onPressed: () {
          //这里是返回到上一页
          Navigator.pop(context);
        },
        backgroundColor: Colors.pink,
      ),
    ));
  }
}

推荐一个Flutter快捷键汇总:https://react-juejin.foreversnsd.cn/post/5c5d970e6fb9a049af6db7cd 让开发事半功倍

上一篇下一篇

猜你喜欢

热点阅读