Flutter入门:组件Card、SafeArea、PageView、GridView

620 阅读3分钟

「这是我参与2022首次更文挑战的第20天,活动详情查看:2022首次更文挑战

Card

Card对应Material Design中的CardView,使用很简单

Card的两个特点就是阴影和圆角。

阴影:

elevation: 5,

圆角:

圆角需要通过shape实现,相对于android要麻烦一些

shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),

这里我们将四个角都设置成半径为5的圆角,当然也可以分别设置

shape: RoundedRectangleBorder(borderRadius: BorderRadius.only(
        topLeft: Radius.circular(15),
        bottomLeft: Radius.zero,
        topRight: Radius.zero,
        bottomRight: Radius.circular(15),
      )),

但是设置完发现不生效,比如card中放置一个图片,结果图片还是完整显示的。

这是因为还需要同时设置另外一个属性

clipBehavior: Clip.antiAlias,

这样圆角效果就生效了。

SafeArea

当我们做一个页面,发现展示效果是全屏的,内容顶到了通知栏里。比如使用Material样式,但是页面中没有加AppBar,那么内容就会顶进通知栏。

这时使用SafeArea即可。

它的作用就是将内容限制在通知栏下面,实际上是加了一个通知栏高度的padding。

所以我们最好将它放在最外层,如下:

@override
  Widget build(BuildContext context) {
    return SafeArea(
      child: GestureDetector(
        ...
      ),
    );
  }

PageView

PageView就是android中的ViewPager,它的用法于GridView类似,也有多种方式

Builder

builder方式是用于当item数不固定时使用,基本用法如下:

PageView.builder(
    itemBuilder: (context, index) {
      return getImage(index);
    },
    itemCount: _images.length,
    scrollDirection: Axis.horizontal,
    controller: _pageController,
    reverse: false,
    )
  • itemBuilder是一个函数,相当于Adapter的getView,用来返回每个item的widget
  • itemCount是item总数
  • scrollDirection是滚动方向,分为 Axis.horizontal 和 Axis.vertical
  • controller是控制器,后面会细说
  • reverse是否反向,如果true则从右向左,第一个在最右边。
  • physics滚动的方式,BouncingScrollPhysics阻尼效果;ClampingScrollPhysics水波纹效果
  • pageSnapping是否具有回弹效果,默认为 true
  • onPageChanged监听事件

PageController

PageView的控制器,可以通过它的几个函数进行切换 animateToPage jumpToPage nextPage previousPage

另外,通过它的构造函数可以设置初始位置等

PageController(
    initialPage: 0,
    viewportFraction: 1.0,
  )
  • initialPage初始位置
  • viewportFraction窗口大小,1.0就是全屏,如果设置0.8则当前页只占屏幕80%,所以上一页和下一页会在显示出一部分。

GridView

在flutter中GridView也有几种使用方式,可以根据自己的情况选择合适的方式

GridView.count

适用item数固定的情况,代码如下:

GridView.count(
  //水平子Widget之间间距
  crossAxisSpacing: 10.0,
  //垂直子Widget之间间距
  mainAxisSpacing: 10.0,
  //GridView内边距
  padding: EdgeInsets.all(10.0),
  //一行的Widget数量
  crossAxisCount: 3,
  //子Widget宽高比例
  childAspectRatio: 1.0,
  //子Widget列表
  children: items,
)

这里items就是一个List<Widget>

而且这种方式,单个item的宽高已经失效了,只根据屏幕宽度自行计算出宽高。

GridView.builder

builder的方式适用于item数不固定的情况

GridView.builder(
    gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
      crossAxisSpacing: 10.0,
      mainAxisSpacing: 10.0,
      crossAxisCount: 3,
      childAspectRatio: 1.0,
    ),
    padding: EdgeInsets.all(10.0),
    itemCount: imageDirs.length,
    itemBuilder: (context, index){
      return getItem(imageDirs[index]);
    })

上面的gridDelegate设置了一个SliverGridDelegateWithFixedCrossAxisCount对象,每行固定数目。

当然还有其他gridDelegate,比如SliverGridDelegateWithMaxCrossAxisExtent,可以实现不同的效果。

使用gridview报错

Cannot hit test a render box with no size

A RenderBox object must have an explicit size before it can be hit-tested

这是因为gridview没有明确的大小,可以用一个container去包裹它,并设置宽高