This is the 14th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

1. Address book page

Having done the Discover page and my page, I’m going to do the contacts page. Change _currentIndex to 1 for easy development. If the address book page still needs _themColor, extract _themColor for public use. Create a file to store the constants that need to be shared. After you add the theme color, import the file somewhere else and you can use it.

// theme Color const weChatThemColor = color.fromrgbo (220, 220, 220, 1.0);Copy the code

Then you can change the background color of the Appbar in the contacts page to weChatThemColor, and add the button in the upper right corner to use the Actions in the Appbar. Add an image to actions. You can have more than one image here, and they will be arranged from left to right.

 actions: [
          Container(
            margin: EdgeInsets.only(right: 10),
            child: Image(
              image: AssetImage("images/icon_friends_add.png"),
              height: 20,
              width: 20,
            ),
          ),
        ],
Copy the code

Then add a GestureDetector layer on the outside of the Container to add gesture responses.

If the address book cell is only used in the address book page, it can be placed in a file. Because it is in a file, you can use _ to make it private. After private, it can still be used in this file.

class _FriendCell extends StatelessWidget { _FriendCell({this.imageUrl, this.name, this.groupTitle, this.imageAssets}); final String? imageUrl; final String? name; final String? groupTitle; final String? imageAssets; @override Widget build(BuildContext context) { return Container(); }}Copy the code

Create the model based on the required content

class Friends {
  Friends({this.imageUrl, this.name, this.indexLetter,this.ImageAssets});
  final String? imageUrl;
  final String? name;
  final String? indexLetter;
  final String? ImageAssets;
}
Copy the code

The body of that address book scaffold could be set to:

	Container(
        child: ListView.builder(
          itemBuilder: _itemForRow,
          itemCount: datas.length + _headerData.length,
        ),
        color: weChatThemColor,
      ),`
Copy the code

Next add the data for the top four, here is the asset image so pass the ImageAssets.

Final List<Friends> _headerData = [Friends(ImageAssets: 'images/ new friends.png ', name: 'new Friends '), Friends(ImageAssets: 'images/ new friends.png ', name:' new Friends '), Friends(ImageAssets: PNG, name: 'ImageAssets '), Friends(ImageAssets: 'images/ tags.png ', name:' tag '), Friends(ImageAssets: 'images/ tags.png ', name: 'tag '), Friends(ImageAssets: 'images/ tags.png ', name:' tag '), Friends(ImageAssets: 'image.png ', name:' image.png '),];Copy the code

Then we build the _itemForRow method, which says in _itemForRow if it’s less than the length of _headerData, we pass in the imageAssets, otherwise it’s the imageUrl. Note that the index of the datas needs to be subtracted from _headerData, otherwise the previous data will be missing.

Widget _itemForRow(BuildContext context, int index) { if (index < _headerData.length) { return _FriendCell( imageAssets: _headerData[index].ImageAssets, name: _headerData[index].name); } else { return _FriendCell( imageUrl: datas[index - _headerData.length].imageUrl, name: datas[index - _headerData.length ].name); }}Copy the code

Then start writing the interface, which simply uses a Row to contain the image and nickname, ClipRRect to crop the image to a rounded rectangle, and determine if the imageUrl is empty. If not, use NetworkImage to load the NetworkImage, otherwise use AssetImage to load the local image.

Widget build(BuildContext context) { return Container( color: Colors.white, child: Row( children: [ Container( margin: EdgeInsets. All (10), width: 34, height: 34, child: ClipRRect(// Clipradius: borderRadius. Circular (5.0), child: Image( image: imageUrl != null ? NetworkImage(imageUrl!) : AssetImage(imageAssets ?? "") as ImageProvider, height: Container(child: Text(name?? "",style: const TextStyle(fontSize: 18),),);Copy the code

After running, we get:

If you find that the underscore is missing, you can see that the underscore starts with the nickname, and you can choose to make the nickname and underscore a whole.

Container( width: screenWidth(context) - 54, child: Column( children: [ Container( child: Text(name ?? "", style: const TextStyle(fontSize: 18)), alignment: Alignment.centerLeft, height: 54, ), Container( color: WeChatThemColor, height: 0.5,),),), //Copy the code

The next step to implement grouping display is to pass an extra groupTitle in _itemForRow, else because there is no title on it.

 Widget _itemForRow(BuildContext context, int index) {
    if (index < _headerData.length) {
      return _FriendCell(
          imageAssets: _headerData[index].ImageAssets,
          name: _headerData[index].name);
    } else {
      return _FriendCell(
        imageUrl: datas[index - _headerData.length].imageUrl,
        name: datas[index - _headerData.length].name,
        groupTitle: datas[index - _headerData.length].indexLetter,
      );
    }
Copy the code

Then go to _FriendCell and wrap the content in Column and add a header to the cell content.

In the header, set alignment to alignment. CenterLeft, give an inner margin of 10 to avoid text too far to the left, and determine whether to display the control based on groupTitle.

Container( alignment: Alignment.centerLeft, padding: EdgeInsets.only(left: 10), height: groupTitle ! = null ? 30 : 0, color: weChatThemColor, child: groupTitle ! = null ? Text(groupTitle! ,style: TextStyle(color: Colors.grey),) : null, ),Copy the code

We also need to sort the data, so we declare an _listDatas, then add the data to initState, and then sort the data according to the indexLetter.

  void initState() {
    // TODO: implement initState
    super.initState();
    //_listDatas = [];
    _listDatas.addAll(datas);
       _listDatas.sort((Friends a,Friends b)
        {
         return (a.indexLetter ?? "").compareTo(b.indexLetter ?? "");
        });
  }
Copy the code

GroupTitle = groupTitle = groupTitle = groupTitle = groupTitle = groupTitle = groupTitle = groupTitle = groupTitle = groupTitle

Widget _itemForRow(BuildContext context, int index) {
    if (index < _headerData.length) {
      return _FriendCell(
          imageAssets: _headerData[index].ImageAssets,
          name: _headerData[index].name);
    }
    bool _hiddenIndexLetter =  index - 4 > 0 &&
        _listDatas[index - _headerData.length].indexLetter ==
            _listDatas[index - _headerData.length - 1].indexLetter;

    return _FriendCell(
      imageUrl: _listDatas[index - _headerData.length].imageUrl,
      name: _listDatas[index - _headerData.length].name,
      groupTitle: _hiddenIndexLetter ? null : _listDatas[index - _headerData.length].indexLetter,
    );

  }
Copy the code