如何用flutter语言构建简单的Android应用程序

本篇文章重点讲到的是什么是Flutter的Widget,即小部件;以及如何在Flutter中使用StatelessWidget,即无状态小部件。

至于Flutter,通俗的讲是开发者可以通一套简单的代码来构建Android应用程序。

特性

小部件是Flutter应用程序的基本构建模块,每一个都是不可变的声明,也是用户界面的一部分。例如button,text,color以及布局所用到的padding等等。

下面我们来看flutter_github中的一个实例。

v2-7e3581ce746f3bbcb5820c1cfb0e73dc_720w.png

圈选中的item只有两个信息,头像与名称。为了避免代码的重复使用,将其抽离成一个独立的widget,具体代码如下

class FollowersItemView extends StatelessWidget {
  final GestureTapCallback tapCallback;
  final String avatarUrl;
  final String name;
 
  const FollowersItemView(
      {Key key, this.avatarUrl, this.name, this.tapCallback})
      : super(key: key);
 
  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.symmetric(horizontal: 15.0),
      child: GestureDetector(
        behavior: HitTestBehavior.opaque,
        onTap: tapCallback,
        child: Column(
          children: <Widget>[
            Row(
              children: <Widget>[
                FadeInImage.assetNetwork(
                  placeholder: 'images/app_welcome.png',
                  image: avatarUrl,
                  width: 80.0,
                  height: 80.0,
                ),
                Expanded(
                  child: Padding(
                    padding: EdgeInsets.only(left: 15.0),
                    child: Text(
                      name,
                      overflow: TextOverflow.ellipsis,
                      maxLines: 1,
                      style: TextStyle(
                        color: Colors.grey[600],
                        fontSize: 20.0,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                )
              ],
            ),
            Padding(
              padding: EdgeInsets.symmetric(vertical: 15.0),
              child: Divider(
                thickness: 1.0,
                color: colorEAEAEA,
                height: 1.0,
                endIndent: 0.0,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

它继承于StatelessWidget,StatelessWidget的特性是无状态,数据不可变化。这个性质正好符合我们将要抽离的部件。抽离的部件需要做头像与名称的展示,没有任何形式上的交互变化。唯一的一个交互也是点击,但它并没有涉及数据的改变。所以在代码中将这些数据定义成final类型。本质就如Text部件,并没有如输入文本或者带有动画的部件一样随着时间内部属性会有所变化。

既然没有任何变化,那么我们也可以将其构造函数定义为const类型。

有了上面的部件抽离,我们就可以直接在ListView中使用该无状态部件

 @override
  Widget createContentWidget() {
    return RefreshIndicator(
      onRefresh: vm.handlerRefresh,
      child: Scrollbar(
        child: ListView.builder(
            padding: EdgeInsets.only(top: 15.0),
            itemCount: vm.list?.length ?? 0,
            itemBuilder: (BuildContext context, int index) {
              final item = vm.list[index];
              return FollowersItemView(
                avatarUrl: item.avatar_url,
                name: item.login,
                tapCallback: () {
                  Navigator.push(context, MaterialPageRoute(builder: (_) {
                    return WebViewPage(title: item.login, url: item.html_url);
                  }));
                },
              );
            }),
      ),
    );
  }

在ListView中引用FollowItemView,并传入不变的数据即可。

呈现原理

现在StatelessWidget的使用大家都会了,那它是如何调用的呢?

下面我们来看下它的呈现原理。

正如开头所说的将小部件作为Flutter应用构建的基础,在Flutter中我们将小部件的构建称作为Widget Tree,即小部件树。它就像是应用程序的蓝图,我们将蓝图创建好,然后内部会通过蓝图去创建对应显示在屏幕上的element元素。它包含了蓝图上对应的小部件的配置信息。所以对应的还有一个Element Tree,即元素树。

每一个StatelWidget都有一个StatelessElement,内部会通过createElement()方法进行创建其实例

  @override
  StatelessElement createElement() => StatelessElement(this);

同时在StatelessElement中会通过buid()方法来获取StalessWidget中所构建的蓝图Widget,并将元素显示到屏幕上。

Widget Tree与Element Tree之间的交互如下

v2-702b5812274448ec0cbb3cc717bae6d1_720w.png

FollowerItemView中的StatelessElement会调用build方法来获取它是否有子部件,如果有的话对应的子部件也会创建它们自己的Element,并把它安装到元素树上。

所以我们的程序有两颗对应的树,其中一颗代表屏幕上显示的内容Element;另一颗树代表其展示的蓝图Widget,它们由许多的小部件组成。

而我们开发人员所做的就是将这些不同的小部件构建成我们所需要的应用程序。

最后,我们再来了解下最初的安装入口。

void main() {
  runApp(GithubApp());
}

在我们的main文件中,有一个main函数,其中调用了runApp方法,传入的是GithubApp。我们再来看下GithubApp是什么?

class GithubApp extends StatefulWidget {
  @override
  _GithubAppState createState() {
    return _GithubAppState();
  }
}
 
class _GithubAppState extends State<GithubApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Github',
      theme: ThemeData.light(),
      initialRoute: welcomeRoute.routeName,
      routes: {
        welcomeRoute.routeName: (BuildContext context) => WelcomePage(),
        loginRoute.routeName: (BuildContext context) => LoginPage(),
        homeRoute.routeName: (BuildContext context) => HomePage(),
        repositoryRoute.routeName: (BuildContext context) => RepositoryPage(),
        followersRoute.routeName: (BuildContext context) =>
            FollowersPage(followersRoute.pageType),
        followingRoute.routeName: (BuildContext context) =>
            FollowersPage(followingRoute.pageType),
        webViewRoute.routeName: (BuildContext context) => WebViewPage(title: '',),
      },
    );
  }
}

发现没它其实也是一个Widget,正如文章开头所说的,Flutter是由各个Widget组成。main是程序的入口,而其中的runApp中的Widget是整个程序挂载的起点。它会创建成一个具有与屏幕宽高一致的根元素,并把它装载到屏幕中。

所以在Flutter中一直都是通过创建Element,然后调用build方法来获取其后续的子Widget,最终构建成我们所看到的程序。

文中的代码都是来自于flutter_github,这是一个基于Flutter的Github客户端同时支持Android与IOS,支持账户密码与认证登陆。使用dart语言进行开发,项目架构是基于Model/State/ViewModel的MSVM;使用Navigator进行页面的跳转;网络框架使用了dio。项目正在持续更新中,感兴趣的可以关注一下。

v2-7e3581ce746f3bbcb5820c1cfb0e73dc_720w.png

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,667评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,361评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,700评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,027评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,988评论 5 361
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,230评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,705评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,366评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,496评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,405评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,453评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,126评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,725评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,803评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,015评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,514评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,111评论 2 341