三. 案例练习
3.1. 案例最终效果
我们先来看一下案例的最终展示效果:
- 这个效果中我们会使用很多没有接触的Widget;
- 没有关系,后面这些常用的Widget我会一个个讲解;
- 这个案例最主要的目的还是让大家更加熟悉Flutter的开发模式以及自定义Widget的封装过程;
3.2. 自定义Widget
在我们的案例中,很明显一个产品的展示就是一个大的Widget,这个Widget包含如下Widget:
- 标题的Widget:使用一个Text Widget完成;
- 描述的Widget:使用一个Text Widget完成;
- 图片的Widget:使用一个Image Widget完成;
- 上面三个Widget要垂直排列,我们可以使用一个Column的Widget(上一个章节中我们使用了一次Row是水平排列的)
另外,三个展示的标题、描述、图片都是不一样的,所以我们可以让Parent Widget来决定内容:
- 创建三个成员变量保存父Widget传入的数据
class ProductItem extends StatelessWidget { final String title; final String desc; final String imageURL; ProductItem(this.title, this.desc, this.imageURL); @override Widget build(BuildContext context) { return Column( children: <Widget>[ Text(title, style: TextStyle(fontSize: 24)), Text(desc, style: TextStyle(fontSize: 18)), Image.network(imageURL) ], ); } }
3.3. 列表数据展示
现在我们就可以创建三个ProductItem来让他们展示了:
- MyApp和上一个章节是一致的,没有任何改变;
- HomeContent中,我们使用了一个Column,因为我们创建的三个ProductItem是垂直排列的
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( primaryColor: Colors.blueAccent ), home: Scaffold( appBar: AppBar( title: Text("CODERWHY"), ), body: HomeContent(), ), ); } } class HomeContent extends StatelessWidget { @override Widget build(BuildContext context) { return Column( children: <Widget>[ ProductItem("Apple1", "Macbook Product1", "https://tva1.sinaimg.cn/large/006y8mN6gy1g72j6nk1d4j30u00k0n0j.jpg"), ProductItem("Apple2", "Macbook Product2", "https://tva1.sinaimg.cn/large/006y8mN6gy1g72imm9u5zj30u00k0adf.jpg"), ProductItem("Apple3", "Macbook Product3", "https://tva1.sinaimg.cn/large/006y8mN6gy1g72imqlouhj30u00k00v0.jpg"), ], ); } }
运行效果如下:
- 错误信息:下面出现了黄色的斑马线;
- 这是因为在Flutter的布局中,内容是不能超出屏幕范围的,当超出时不会自动变成滚动效果,而是会报下面的错误;
如何可以解决这个问题呢?
- 我们将Column换成ListView即可;
- ListView可以让自己的子Widget变成滚动的效果;
3.4. 案例细节调整
3.4.1. 界面整体边距
如果我们希望整个内容距离屏幕的边缘有一定的间距,怎么做呢?
- 我们需要使用另外一个Widget:Padding,它有一个padding属性用于设置边距大小;
- 没错,设置内边距也是使用Widget,这个Widget就是Padding;
3.4.2. 商品内边距和边框
我们现在希望给所有的商品也添加一个内边距,并且还有边框,怎么做呢?
- 我们可以使用一个Container的Widget,它里面有padding属性,并且可以通过decoration来设置边框;
- Container我们也会在后面详细来讲,我们先用起来;
3.4.3. 文字图片的间距
我们希望给图片和文字之间添加一些间距,怎么做呢?
- 方式一:给图片或者文字添加一个向上的内边距或者向下的内边距;
- 方式二:使用SizedBox的Widget,设置一个height属性,可以增加一些距离;
3.5. 最终实现代码
最后,我给出最终实现代码:
import 'package:flutter/material.dart'; main(List<String> args) { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( primaryColor: Colors.blueAccent ), home: Scaffold( appBar: AppBar( title: Text("CODERWHY"), ), body: HomeContent(), ), ); } } class HomeContent extends StatelessWidget { @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(8.0), child: ListView( children: <Widget>[ ProductItem("Apple1", "Macbook Product1", "https://tva1.sinaimg.cn/large/006y8mN6gy1g72j6nk1d4j30u00k0n0j.jpg"), ProductItem("Apple2", "Macbook Product2", "https://tva1.sinaimg.cn/large/006y8mN6gy1g72imm9u5zj30u00k0adf.jpg"), ProductItem("Apple3", "Macbook Product3", "https://tva1.sinaimg.cn/large/006y8mN6gy1g72imqlouhj30u00k00v0.jpg"), ], ), ); } } class ProductItem extends StatelessWidget { final String title; final String desc; final String imageURL; ProductItem(this.title, this.desc, this.imageURL); @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.all(20), decoration: BoxDecoration( border: Border.all() ), child: Column( children: <Widget>[ Text(title, style: TextStyle(fontSize: 24)), Text(desc, style: TextStyle(fontSize: 18)), SizedBox(height: 10,), Image.network(imageURL) ], ), ); } }