该文已受权公众号 「码个蛋」,转载请指明出处android
上一节介绍了 Dart
的一些语法,以及配置环境的网址,这节咱们就能够开始了解下 Flutter
了git
主要包括 MaterialApp
、Scaffold
、Text
、Image
、Icon
、Button
以及 AppBar
部份内容,准备出发~github
新建 flutter 项目后,能够看到 lib 下的 main.dart 中 void main() => runApp(MyApp());
这句就是程序的入口了。这里能够简单看下源码数据库
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..attachRootWidget(app)
..scheduleWarmUpFrame();
}
///....
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null)
WidgetsFlutterBinding();
return WidgetsBinding.instance;
}
///....
void attachRootWidget(Widget rootWidget) {
_renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
container: renderView,
debugShortDescription: '[root]',
child: rootWidget
).attachToRenderTree(buildOwner, renderViewElement);
}
复制代码
首先会建立一个 WidgetsBinding
单例对象,而后把传入的 App 添加到 rootWidget
中,scheduleWarmUpFrame
方法比较长,这边看下对该方法的注释第一句就能了解方法的主要功能了markdown
Schedule a frame to run as soon as possible网络
「安排框架尽快运行起来」(原谅我这渣英语,只能看懂不会翻译..大概就是「快速启动框架」的意思吧)app
接着看下 MyApp
这个类,继承自 StatelessWidget
并在 build
方法返回一个 MaterialApp
实例,(偷偷讲下,其实这边还能够返回 CupertinoApp
,这是一个 iOS 风格的 widget,基本上你看到部件带 「Cupertino」的都是 iOS 风格的 widget,这里先不讲 iOS 风格的部件,目前 flutter 对 Cupertino 系列的 widget 支持不是很好,包括部件的广度,多语言的支持等等方面都不是很友好,因此咱们仍是继续看 MD 风格的 Android 部件吧~),这里先看下 MaterialApp
的构造函数,介绍一些经常使用的参数框架
const MaterialApp({
Key key,
this.navigatorKey,
this.home, // 主界面的内容 widget
this.routes = const <String, WidgetBuilder>{}, // 带 router 和路由跳转有关
this.initialRoute,
this.onGenerateRoute,
this.onUnknownRoute,
this.navigatorObservers = const <NavigatorObserver>[],
this.builder,
this.title = '', // *相似标题
this.onGenerateTitle, // 主要用于多语言状况下,须要根据当前语言替换 title,须要使用该值
this.color, // 主题色,若是该值未设置,取 theme.primaryColor,未设置 theme 则取蓝色
this.theme, // App 的主题风格,包括主题色,按钮默认颜色等等
this.locale, // 带 locale 的和多语言适配相关
this.localizationsDelegates,
this.localeListResolutionCallback,
this.localeResolutionCallback,
this.supportedLocales = const <Locale>[Locale('en', 'US')],
this.debugShowMaterialGrid = false,
this.showPerformanceOverlay = false,
this.checkerboardRasterCacheImages = false,
this.checkerboardOffscreenLayers = false,
this.showSemanticsDebugger = false,
this.debugShowCheckedModeBanner = true, // debug 模式下,是否显示 DEBUG 标示横幅
})
复制代码
MaterialApp
继承自 StatefulWidget
,它和 MyApp
所继承的类 StatelessWidget
,就是平常开发中,自定义部件一般继承的抽象类了。less
StatelessWidget
是状态不可变部件,经过其构建的部件通常用来展现固定内容,例如须要展现固定的功能按钮列表,不须要根据不一样界面状态进行修改其展现内容StatefulWidget
是可改变状态的部件,好比咱们须要经过网络或者数据库获取数据,而后修改部件锁展现的数据内容,则须要经过 StatefulWidget
来构建。固然,不是说 StatelessWidget
不能实现修改界面数据的功能,这就须要涉及到 状态管理 的概念了,后面有机会再讲,这边先埋坑【坑1】进入 App
后就须要构建界面了,Flutter
提供了 Scaffold
来快速构建一个 MaterialDesign
风格的界面,仍是先看下 Scaffold
的构造函数吧,了解几个比较经常使用的部分。ide
const Scaffold({
Key key,
this.appBar, // 界面顶部的那条栏,这边须要返回一个 AppBar 实例
this.body, // 界面的内容部分
this.floatingActionButton, // 悬浮部分,能够经过 floatingActionButtonLocation 设置位置
this.floatingActionButtonLocation,
this.floatingActionButtonAnimator,
this.persistentFooterButtons,
this.drawer, // 侧滑抽屉部分,从左侧滑出(应该和语言有关,和文字方向同向)
this.endDrawer, // 侧滑抽屉部分,从右侧滑出
this.bottomNavigationBar, // 底部导航栏,就是一般看到的底部 TAB 切换部件
this.bottomSheet, // 展现从底部弹出的,起到提示做用的,经过 showModalBottomSheet 展现
this.backgroundColor, // 界面的背景色
this.resizeToAvoidBottomPadding = true, // 避免 body 被底部弹出部件填充,例如输入法键盘
this.primary = true, // 当前的 Scaffold 是否须要被展现在屏幕最上层
})
复制代码
来张图吧,简洁明了
了解完 Scaffold
的总体构造后,咱们从上到下,经过构造函数来了解下各个 Widget
的使用方法
AppBar({
Key key,
this.leading, // 用于设置 AppBar 前置的按钮,例如设置返回咱们须要的返回按钮等
this.automaticallyImplyLeading = true, // 是否使用系统默认生成的按钮,若是替换 leading 的默认按钮,最好将该属性设置成 false
this.title, // AppBar 所须要展现的组件,传入一个 Widget 实例,一般使用 Text 展现一个标题
this.actions, // AppBar 末尾悬浮的一些操做组件,例如常见的会在末尾设置一个「...」按钮,点击弹出一个 menue 提供给用户操做选择
this.flexibleSpace, // AppBar 的背景,能够设置颜色,背景图等等
this.bottom, // bottom 用于展现顶部导航 TAB
this.elevation = 4.0,
this.backgroundColor, // AppBar 的背景色,若是只须要修改颜色,能够不经过 flexibleSpace 修改
this.brightness,
this.iconTheme, // 按钮的默认样式
this.textTheme, // 文字的默认样式
this.primary = true,
this.centerTitle, // 是否将展现的 title 居中
this.titleSpacing = NavigationToolbar.kMiddleSpacing, // AppBar title 两侧的空白间隔
this.toolbarOpacity = 1.0,
this.bottomOpacity = 1.0,
})
复制代码
在展现 AppBar
的 demo
以前,咱们先学习几个基本的组件 Text
、Image
、Icon
、Button
分布用于展现文字,图片,图标,按钮
const Text(this.data, { // Text 须要展现的文字
Key key,
this.style, // 文字的样式,包括颜色,大小,间距等等属性,这边就不继续展现 TextStyle 构造函数了,否则我怕你们都不想继续看了,稍后经过例子来讲明
this.textAlign, // 文字的对齐方式,包括左对齐,右对齐,居中等,详见 TextAlign 类
this.textDirection, // 文字方向,ltr(left to right) 或者 rtl(right to left)
this.locale,
this.softWrap, // 当文字一行显示不完是否换行
this.overflow, // 若是超出限制的行数,以哪一种方式省略未展现的内容
this.textScaleFactor, // 文字缩放比例
this.maxLines, // 最多展现的行数
this.semanticsLabel,
})
复制代码
说了那么多,相信不少小伙伴都要急着撸代码了吧,接着来展现一些 Text
的示例,接下来的例子都会直接替换 HomePage
内的展现内容,其他都是相同的,接下来请关注 Text
别的部件先忽略,后面会介绍,这边先埋坑【坑2】
import 'package:flutter/material.dart';
void main() => runApp(DemoApp());
class DemoApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(primarySwatch: Colors.lightBlue),
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
padding: const EdgeInsets.only(top: 10.0),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('绿色背景黑色文字展现',
style: TextStyle(
color: Colors.black, // 设置文字颜色,不可和 foreground 同时设置
fontSize: 24.0, // 字体大小
letterSpacing: 2.0, // 每一个字符之间的间隔
background: Paint()..color = Colors.green)), // 背景色
Text('这是一个带红色下划线的文字展现',
style: TextStyle(
color: Colors.black,
fontSize: 24.0,
// 文字装饰线,除了 underline 还有 overline, lineThrough,
// 不一样的样式小伙伴能够经过本身修改代码来查看
decoration: TextDecoration.underline,
// 文字装饰线的类型,除了 solid 还有 double,dotted,dashed,wavy 可选
decorationStyle: TextDecorationStyle.solid,
// 装饰线的颜色
decorationColor: Colors.red))
],
)),
));
}
}
复制代码
该部分代码查看源码 text_main.dart
文件
最后的展现效果以下图:
/坏笑 按照惯例,咱们仍是先看下 Image
的构造函数吧
const Image({
Key key,
// 一个 ImageProvider 实例,可是 ImageProvider 是一个抽象类,Flutter 已经给咱们提供以下
// AssetImage,NetworkImage,FileImage,MemoryImage 这四种图片加载器,为了方便调用
// 咱们能够直接经过 Image.asset, Image.network, Image.file, Image.memory 简化,
// 经过方法名,能够看出分别从 asset 文件,网络,文件,内存中加载图片
@required this.image,
this.semanticLabel,
this.excludeFromSemantics = false,
this.width, // 图片宽度
this.height, // 图片高度
this.color, // 图片背景色
this.colorBlendMode, // color 和图片的混合模式(这个值比较多,能够一个个尝试)
this.fit, // 图片填充方式 fill, cover, contain, fillWidth, fillHeight, scaleDown, none
this.alignment = Alignment.center, // 对齐方式
this.repeat = ImageRepeat.noRepeat, // 若未填充满空间,重复展现的方式
this.centerSlice,
this.matchTextDirection = false,
this.gaplessPlayback = false,
this.filterQuality = FilterQuality.low,
})
复制代码
好了好了,我知道大家又想本身写代码尝试下了,在这以前,须要你先准备一张本地图片,而后在项目的根目录,也就是 lib
文件夹同层,建立一个新的文件夹,命名为 images
,把你准备好的图片放到这个目录下。放好以后打开 pubspec.yaml
把图片资源文件注册下
# 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
# 这边注册资源文件,之后有图片文件也能够只注册 images 文件夹,会自动读取内部的文件
assets:
- images/ali.jpg
复制代码
注册完成后,就能够继续愉快的撸代码了~
class HomePage extends StatelessWidget {
final String _assetAli = 'images/ali.jpg';
final String _picUrl =
'https://timg05.bdimg.com/timg?wapbaike&quality=60&size=b1440_952&cut_x=143&cut_y=0&cut_w=1633&'
'cut_h=1080&sec=1349839550&di=cbbc175a45ccec5482ce2cff09a3ae34&'
'src=http://imgsrc.baidu.com/baike/pic/item/4afbfbedab64034f104872baa7c379310b551d80.jpg';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
padding: const EdgeInsets.only(top: 10.0),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// 这种展现图片方式和下一种会有相同的效果
Image(image: AssetImage(_assetAli), width: 80.0, height: 80.0),
// 接下来加载图片都会使用这些比较方便的方法
Image.asset(_assetAli, width: 80.0, height: 80.0),
// 加载一张网络图片
Image.network(_picUrl,
height: 80.0,
// 横向重复
repeat: ImageRepeat.repeatX,
// MediaQuery.of(context).size 获取到的为上层容器的宽高
width: MediaQuery.of(context).size.width),
// 经过设置混合模式,能够看到图片展现的样式已经修改
Image.asset(_assetAli,
width: 80.0, height: 80.0, color: Colors.green, colorBlendMode: BlendMode.colorDodge),
// 会优先加载指定的 asset 图片,而后等网络图片读取成功后加载网络图片,会经过渐隐渐现方式展示
// cover 方式按照较小的边布满,较大的给切割
// contain 会按照最大的边布满,较小的会被留白
// fill 会把较大的一边压缩
// fitHeight, fitWidth 分别按照长宽来布满
FadeInImage.assetNetwork(
placeholder: _assetAli, image: _picUrl, width: 120.0, height: 120.0, fit: BoxFit.cover),
// Icon 相对属性少了不少,须要传入一个 IconData 实例,flutter 提供了不少图标,
// 可是实际状况咱们须要加入咱们本身的图标,这边再埋坑【坑3】
// size 为图标显示的大小,color 为图标的颜色,这边经过 Theme 获取主题色调
Icon(Icons.android, size: 40.0, color: Theme.of(context).primaryColorDark)
],
)),
));
}
}
复制代码
该部分代码查看源码 image_main.dart
文件
最后的效果以下:
Flutter
提供了各类类型的 Button
几乎是大同小异的,这边就抽取一些比较经常使用的展现下效果,经常使用的主要有 RaisedButton
、FlatButton
、IconButton
、OutlineButton
、MaterialButton
、FloatActionButton
、FloatingActionButton.extended
Button
都有一个 onPress
参数,是 VoidCallback
类型的参数,经过查看源码能够知道 VoidCallback
是无参无返回值的一种类型参数。若是该参数传入的值为 null
那么这个按钮的就不可点击状态,无点击效果,等会能够在例子中查看。还有就是 child
参数,这里就是传入你须要展现的内容,好比 Text
、Icon
等等。别的参数基本能够经过参数名了解,这边不扩展了(再看源码我怕大家都不想继续看下去了...)
Talk is cheap, show me the code
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
padding: const EdgeInsets.only(top: 10.0),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
onPressed: () {
print('This is a Rased Button can be clicked');
},
child: Text('Raised Enable'),
),
RaisedButton(onPressed: null, child: Text('Raised Disable')),
FlatButton(
onPressed: () => print('This is a Flat Button can be clicker'),
child: Text('Flat Enable'),
),
FlatButton(onPressed: null, child: Text('Flat Disable')),
IconButton(icon: Icon(Icons.android), onPressed: () {}),
IconButton(icon: Icon(Icons.android), onPressed: null),
MaterialButton(onPressed: () {}, child: Text('Material Enable')),
MaterialButton(onPressed: null, child: Text('Material Disable')),
OutlineButton(onPressed: () {}, child: Text('Outline Enable')),
OutlineButton(onPressed: null, child: Text('Outline Enable')),
],
)),
),
floatingActionButton:
FloatingActionButton.extended(onPressed: () {}, icon: Icon(Icons.android), label: Text('Android')),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
}
复制代码
该部分代码查看源码 button_main.dart
部分
最终的效果图:
这篇终于到末尾了,最后留了 3 个坑等之后解决
最后代码的地址仍是要的:
文章中涉及的代码:demos
基于郭神 cool weather
接口的一个项目,实现 BLoC
模式,实现状态管理:flutter_weather
一个课程(当时买了想看下代码规范的,代码更新会比较慢,虽然是跟着课上的一些写代码,可是仍是作了本身的修改,不少地方看着不舒服,而后就改为本身的实现方式了):flutter_shop
若是对你有帮助的话,记得给个 Star,先谢过,你的承认就是支持我继续写下去的动力~