flutter上分之路2-人机练习(初识demo

flutter上分之路-人机练习(初识demo

前言

新手教学通过了,该打一场试试手了,不过先从人机开始吧。
上篇文章,已经能跑demo了,看了看代码,其实有点头大,怎么这么多括号????这么多嵌套有点像初学C语言的样子(当年有个同学嵌套了20层,那代码就像一幅抽象派大作。。)。
我上学的时候,就是不喜欢背东西,总觉得背下来的东西只是背下来而已,并不是真正的理解了其中的意义,所以作为一个资zhuang深bi程序员,先不着急把代码看懂,我们接着教程,先实实在在的把第一个APP写出来,写着写着,自然能明白一些。

代码

代码我就不啰嗦了 直接看教程就行了
https://flutterchina.club/get-started/codelab/

下面我就分布梳理一下

启动

//启动一个app
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
    // This widget is the root of your application.
    @override
    Widget build(BuildContext context) {
        //dart 自动省略 new 关键字
        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,
                primaryColor: Colors.white
            ),
            home: MyHomePage(title: 'Flutter Demo Home Page ' + WordPair
                .random()
                .asPascalCase)
        );
    }
}

可以看到,app入口就是一个main函数,里面new了一个MyApp类。这里和java版的不一样,java的入口在Application类里面,而flutter的app则是继承了StatelessWidget这么一个东西。这个东西是什么,稍后再说。
还有就是flutter完全省略了xml,theme和layout完全写在代码当中。当然,带来的问题就是嵌套太多,虽然AS自动加了一段注释,但感觉还是没什么帮助。但是这给flutter带来了一项很重要的特性 – 热重载!
在这里插入图片描述
然后就是属性,像其中的MaterialApp,就相当于原来的theme,里面的各种属性都是通过类似于方法参数的方式进行添加,比如添加一个app标题,叫“Flutter Demo”。
从这部分我们可以看出,flutter的UI层级基本就是Widget,从根儿上就是一个widget。其实原版的android本来也就是从View开始,只不过我们实际上比较少直接处理rootView。app的启动就是从main入口启动一个APP级别的Widget。

首页

class MyHomePage extends StatefulWidget {
    MyHomePage({Key key, 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
    _MyHomePageState createState() => _MyHomePageState();
}

// 类 方法前 加上"_"前缀 将其标记为私有 peivate
class _MyHomePageState extends State<MyHomePage> {
    int _counter = 0;

    ///文档注释用三个斜杠 比java简单多了
    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++;
        });
    }

    void gotoStatefulWidget() {
        Navigator.of(context).push(MaterialPageRoute(builder: (context) {
            return RandomWords();
        }
        )
        );
    }

    @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(
                // Center is a layout widget. It takes a single child and positions it
                // in the middle of the parent.
                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>[
                        Text(
                            'You have pushed the button this many times:',
                        ),
                        Text(
                            '$_counter',
                            style: Theme
                                .of(context)
                                .textTheme
                                .display1,
                        ),
                        IconButton(
                            icon: Icon(Icons.input),
                            tooltip: "Stateful widget",
                            onPressed: gotoStatefulWidget,
                        )
                    ],
                ),
            ),
            floatingActionButton: FloatingActionButton(
                onPressed: _incrementCounter,
                tooltip: 'Increment',
                child: Icon(Icons.add),
            ), // This trailing comma makes auto-formatting nicer for build methods.
        );
    }
}

这是初始demo的首页,我们可以看到两个类,一个继承了StatefulWidget,另一个继承了State
<T>。StatefulWidget就是一个壳,State才是真正的核心。而State的核心就在于build函数return了什么东西。
StatefulWidget表示了一个可更新的查件,用过调用setState通知Widget进行重绘。setState里面实现具体重绘的逻辑。
Scaffold大概就是了一个封装好的UI框架,里面可以添加appBar、drawer、bottomBar等东西。body则是里面的实际内容。
Text、Button这些控件的各种属性也都是直接写在构造函数里的,这个之前的方式完全不一样。
跳转事件是用Navigator去处理的,和之前的方式也大相径庭。
另外就是一些语法的东西了,比如三斜杠注释、构造函数省略new、下划线前缀表示私有等等。
我这里和教学里的demo不大一样,保留了初始demo的首页,添加了一个按钮跳转到教学demo里的首页。

列表页

class RandomWords extends StatefulWidget {
    @override
    State<StatefulWidget> createState() {
        return RandomWordsState();
    }
}

class RandomWordsState extends State<RandomWords> {

    final _suggestions = <WordPair>[];
    final _saved = Set<WordPair>();
    TextStyle _biggerFont = TextStyle(fontSize: 18);

    @override
    Widget build(BuildContext context) {
//        return Text(WordPair
//            .random()
//            .asPascalCase);
        return Scaffold(
            appBar: AppBar(title: Text("RandomWords"),
                actions: <Widget>[IconButton(icon: Icon(Icons.list), onPressed: _pushSaved)],),
            body: _buildSuggestions(),
//            body: Center(
//                child: Text(WordPair
//                    .random()
//                    .asPascalCase),

        );
    }

    Widget _buildSuggestions() {
        return ListView.builder(itemBuilder: (context, i) {
            if (i.isEven) {
                return Divider();
            }
            int index = i ~/ 2; // dart语法 做除法 取商数 但是向下取整 不加"~" 就变成了
            //下面报错 type 'double' is not a subtype of type 'int' in type cast
            //int index = (5 / 2) as int;
            if (index >= _suggestions.length) {
                _suggestions.addAll(generateWordPairs().take(10));
            }
            return _buildRow(_suggestions[index]);
        },
            padding: EdgeInsets.all(16),);
    }

    Widget _buildRow(WordPair pair) {
        bool b = _saved.contains(pair);
        return ListTile(
            title: new Text(
                pair.asPascalCase,
                style: _biggerFont,),
            trailing: Icon(
                b ? Icons.favorite : Icons.favorite_border),
            onTap: () {
                setState(() {
                    //方法调用也能放进三目
                    b ? _saved.remove(pair) : _saved.add(pair);
                });
            },);
    }

    void _pushSaved() {
        Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
            var tiles = _saved.map((pair) {
                return ListTile(title: new Text(pair.asPascalCase, style: _biggerFont));
            });
            var divided = ListTile.divideTiles(tiles: tiles, context: context).toList();
            return Scaffold(appBar: AppBar(title: Text("Saved Suggestions")),
                body: new ListView(children: divided));
        }));
    }
}

到了这个界面,看到列表就惊呆了。写一个列表,竟然只要区区几行代码,如果是java版,呵呵,至少三个类吧(xml,activity,adapter,我说的是常规写法,就别跟我拧了)。一个ListView.builder就搞定了,嗯,真香!
看到后面,哇!更香了!利用Scaffold+ListView竟然就能直接启动一个列表页!
ListTile代表了一个item,分别用ListView.builder(itemBuilder)和new ListView(children: ListTile.divideTiles())两种方式创建列表。
不知道还有个地方你们有没有注意到,在dart语言中,方法直接可以当做一个函数的参数,方法的实现不依赖于某个类,这个很像lambda表达式。

总结

1.flutter通过main入口,new一个app的widget来启动app。
2.flutter的嵌套是一个特点,java转型的话比较费劲。
3.flutter的UI是通过widget来嵌套封装的。widget有两种:
- StatelessWidget
 实现了一个不可变的控件,通过重写build函数实现。
- StatefulWidget
 实现了一个可变的控件,通过重写createState函数返回一个继承State的类来实现。在需要改变的时候,调用setState实现改变的逻辑。
4.控件的各种属性直接在构造函数里写就完了。
5.dart的语法还是很方便的:

//单行函数
void main() => runApp(MyApp());

//构造函数省略new关键字
return MaterialApp();

//下划线前缀表示private
int _counter = 0;

//方法(function)可以直接当做一个参数
setState(() { _counter++; });

// $ 引用变量进行打印
Text('$_counter')

// 无参无返回值的函数 调用可以省略最后的空括号。
IconButton(onPressed: gotoStatefulWidget,)
        
//方法调用也能放进三目
b ? _saved.remove(pair) : _saved.add(pair);

///文档注释用三个斜杠 比java简单多了
void _incrementCounter() {}

目前这些东西也算是开眼了,知道了flutter的大体是如何编码的。
下一篇还是不急着研究flutter,先熟悉熟悉语法,把java和dart不一样的东西整理整理,正所谓磨刀不误砍柴工。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值