从零开始的Flutter之旅: StatelessWidget

Flutter - Beautiful native apps in record time.png

此次要展现的是什么是Flutter的Widget,即小部件;以及如何在Flutter中使用StatelessWidget,即无状态小部件。html

至于Flutter,通俗的讲是开发者能够通一套简单的代码来同时构建Android与IOS应用程序。git

特性

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

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

stateless_widget_1.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中使用该无状态部件app

@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的使用你们都会了,那它是如何调用的呢?less

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

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

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

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

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

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

stateless_widget_2.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。项目正在持续更新中,感兴趣的能够关注一下。

flutter_github.png

固然若是你想了解Android原生,相信flutter_github的纯Android版本AwesomeGithub是一个不错的选择。

下期预告

从零开始的Flutter之旅: StatefulWidget

若是你喜欢个人文章模式,或者对我接下来的文章感兴趣,建议您关注个人微信公众号:【Android补给站】

或者扫描下方二维码,与我创建有效的沟通,同时更快更准的收到个人更新推送。

Android补给站.jpg

相关文章
相关标签/搜索