# 10.通过联系人Cell看断言

### 前言

我们在构建如微信联系人页类似的 Cell 时，主要有两种。一种是加载网络图片，用来现实我们的联系人；一种是本地图片，用来显示一些系统入口，如公众号等。那么如何优雅的完成这样对两种形式数据展示的 Cell 呢？借助这个场景，我们来了解一下 `断言` 。

![1](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MI8JgbGh3U6X_oedqkm%2Fuploads%2Fgit-blob-b0ea5045e3163581bfb5e95011ec4cabd29fde69%2F10-01.png?alt=media)

### 不使用断言

这样的代码，并没有什么明显问题。

* 普通联系人传入 avatarUrl 网络图片
* 系统入口传入 assetName 资源名称
* avatarUrl 和 assetName 都是可选字段，即均可为空

这样的隐患是无法保证至少有一个是有值的。下面我们使用断言进行优化，如果两者都为空就会抛出异常。

```
class _ContactCell extends StatelessWidget {
  const _ContactCell({
    required this.name,
    this.avatarUrl,
    this.assetName,
  });

  final String name;
  final String? avatarUrl;
  final String? assetName;

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 60,
      color: Colors.white,
      child: Stack(
        children: [
          Row(
            children: [
              Row(
                children: [
                  const SizedBox(
                    width: 12,
                  ),
                  avatarUrl != null
                      ? Container(
                          width: 48,
                          height: 48,
                          decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(4),
                            image: DecorationImage(
                              image: NetworkImage(avatarUrl!),
                            ),
                          ),
                        )
                      : Container(),
                  assetName != null
                      ? Container(
                          width: 48,
                          height: 48,
                          decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(4),
                            image: DecorationImage(
                              image: AssetImage(assetName!),
                            ),
                          ),
                        )
                      : Container(),
                  const SizedBox(
                    width: 12,
                  ),
                  Text(
                    name,
                    style: const TextStyle(
                      fontSize: 16,
                      fontWeight: FontWeight.w500,
                    ),
                  ),
                ],
              ),
            ],
          ),
          Positioned(
            left: 50,
            bottom: 0,
            child: Container(
              height: 1,
              color: Colors.grey,
            ),
          ),
        ],
      ),
    );
  }
}
```

### 使用断言进行优化

这里在构造方法加了断言： `assert((avatarUrl != null || assetName != null), '至少一张图片')`

如果两者都为空，那么就会抛出如图异常：

![2](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MI8JgbGh3U6X_oedqkm%2Fuploads%2Fgit-blob-34e3ecc7afce2491aca130b098ff5ab0466df049%2F10-02.png?alt=media)

```
class _ContactCell extends StatelessWidget {
  const _ContactCell({
    required this.name,
    this.avatarUrl,
    this.assetName,
  }) : assert((avatarUrl != null || assetName != null), '至少一张图片');

  final String name;
  final String? avatarUrl;
  final String? assetName;

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 60,
      color: Colors.white,
      child: Stack(
        children: [
          Row(
            children: [
              Row(
                children: [
                  const SizedBox(
                    width: 12,
                  ),
                  avatarUrl != null
                      ? Container(
                          width: 48,
                          height: 48,
                          decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(4),
                            image: DecorationImage(
                              image: NetworkImage(avatarUrl!),
                            ),
                          ),
                        )
                      : Container(),
                  assetName != null
                      ? Container(
                          width: 48,
                          height: 48,
                          decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(4),
                            image: DecorationImage(
                              image: AssetImage(assetName!),
                            ),
                          ),
                        )
                      : Container(),
                  const SizedBox(
                    width: 12,
                  ),
                  Text(
                    name,
                    style: const TextStyle(
                      fontSize: 16,
                      fontWeight: FontWeight.w500,
                    ),
                  ),
                ],
              ),
            ],
          ),
          Positioned(
            left: 50,
            bottom: 0,
            child: Container(
              height: 1,
              color: Colors.grey,
            ),
          ),
        ],
      ),
    );
  }
}
```
