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

1. The macro definition

We use some common classes in our project, such as our iOS macro definition, and have similar ones in Flutter. We create a file directly, similar to our iOS header file, and then define some common classes, such as colors, title styles, etc. When using option+ Enter automatically import error can be

Color ThemeColor = const Color.fromRGBO(220.220.220.1.0);
TextStyle TitleStyle = const TextStyle(fontSize: 16,fontWeight: FontWeight.bold,color: Colors.black);
Copy the code

2. The navigation bar

appBar: AppBar(
    title: const Text('Contacts Page'),
    centerTitle: true,
    elevation: 0.0,
    backgroundColor: ThemeColor,
  actions: [
    GestureDetector(
      onTap: (){
        Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => DiscoverChildPage("Add a friend")));

      },
      child:Container(
        padding: EdgeInsets.only(right: 15),
        child:  Image.asset('images/icon_friends_add.png',width: 30,),
      )
    ),
  ],
  leading: IconButton(onPressed: (){
    Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => DiscoverChildPage("More")));


  }, icon: Icon(Icons.menu)) ,


),
Copy the code

Mainly introduce actions and leading

  • actionsIs aAn array ofElement is a controlwidget

We’re adding one

Equivalent to rightButtonItems in the iOS navigation bar we can add multiple Widege

  • leading

Equivalent to the navigation bar left control returns a widget

leading:  IconButton(onPressed: (){
  Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => DiscoverChildPage("More")));


}, icon: Icon(Icons.menu)) ,
Copy the code

If you add 2, you need to pay attention to the size. Here I directly use IconButton size error report

3. Data processing

We define the data

class Friends {
  Friends({this.imageUrl, this.name, this.indexLetter, this.imageAssets});
  final String? imageAssets;
  final String? imageUrl;
  final String? name;
  final String? indexLetter;
}

List<Friends> datas = [
  Friends(
      imageUrl: 'https://randomuser.me/api/portraits/women/27.jpg',
      name: 'Lina',
      indexLetter: 'L'),
  Friends(
      imageUrl: 'https://randomuser.me/api/portraits/women/17.jpg',
      name: 'and',
      indexLetter: 'F'),
  Friends(
      imageUrl: 'https://randomuser.me/api/portraits/women/16.jpg',
      name: 'AnLi',
      indexLetter: 'A'),
  Friends(
      imageUrl: 'https://randomuser.me/api/portraits/men/31.jpg',
      name: 'pell',
      indexLetter: 'A'),
  Friends(
      imageUrl: 'https://randomuser.me/api/portraits/women/22.jpg',
      name: 'Bella',
      indexLetter: 'B'),
  Friends(
      imageUrl: 'https://randomuser.me/api/portraits/women/37.jpg',
      name: 'Lina',
      indexLetter: 'L'),
  Friends(
      imageUrl: 'https://randomuser.me/api/portraits/women/18.jpg',
      name: 'Nancy',
      indexLetter: 'N'),
  Friends(
      imageUrl: 'https://randomuser.me/api/portraits/men/47.jpg',
      name: '扣扣',
      indexLetter: 'K'),
  Friends(
      imageUrl: 'https://randomuser.me/api/portraits/men/3.jpg',
      name: 'Jack',
      indexLetter: 'J'),
  Friends(
      imageUrl: 'https://randomuser.me/api/portraits/women/5.jpg',
      name: 'Emma',
      indexLetter: 'E'),
  Friends(
      imageUrl: 'https://randomuser.me/api/portraits/women/24.jpg',
      name: 'Abby',
      indexLetter: 'A'),
  Friends(
      imageUrl: 'https://randomuser.me/api/portraits/men/15.jpg',
      name: 'Betty',
      indexLetter: 'B'),
  Friends(
      imageUrl: 'https://randomuser.me/api/portraits/men/13.jpg',
      name: 'Tony',
      indexLetter: 'T'),
  Friends(
      imageUrl: 'https://randomuser.me/api/portraits/men/26.jpg',
      name: 'Jerry',
      indexLetter: 'J'),
  Friends(
      imageUrl: 'https://randomuser.me/api/portraits/men/36.jpg',
      name: 'Colin',
      indexLetter: 'C'),
  Friends(
      imageUrl: 'https://randomuser.me/api/portraits/women/12.jpg',
      name: 'Haha',
      indexLetter: 'H'),
  Friends(
      imageUrl: 'https://randomuser.me/api/portraits/women/11.jpg',
      name: 'Ketty',
      indexLetter: 'K'),
  Friends(
      imageUrl: 'https://randomuser.me/api/portraits/women/13.jpg',
      name: 'Lina',
      indexLetter: 'L'),
  Friends(
      imageUrl: 'https://randomuser.me/api/portraits/women/23.jpg',
      name: 'Lina',
      indexLetter: 'L')];Copy the code

The data contains a fixed header of the top 4 and the following contacts

final List<Friends> _headerData = [
  Friends(imageAssets: 'Images/new friend.png', name: 'New friends'),
  Friends(imageAssets: 'images/group chat. PNG', name: 'chatting'),
  Friends(imageAssets: 'images/tag. PNG', name: 'tags'),
  Friends(imageAssets: 'images/ public number.png ', name: 'Public Account')];Copy the code

4. Create a Cell

Cell is a header view that contains an avatar, a title, an underscore, and a group

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(

      child: Column(

        children: [
          // The header is not displayed without a headerContainer( child: groupTitle ! =null? Text(groupTitle! ,style: TextStyle(color: Colors.grey),) :null, height: groupTitle ! =null ?30:0,
            color: ThemeColor,
            alignment: Alignment.centerLeft,
            padding: EdgeInsets.only(left: 15),
          ),
          Container(/ / cell content
            child: Row(
              mainAxisAlignment: MainAxisAlignment.start,
              children: [
                Container(margin: EdgeInsets.all(10),child:imageAssets == null? Image.network(imageUrl! ,width:34,height: 34,) : Image.asset(imageAssets!) ,height:34,width: 34,),/ / avatar
                Container(

                  alignment: Alignment.centerLeft,
                  width: screenWidth(context) - 54,
                  child: Column(

                    children: [
                  Container(alignment: Alignment.centerLeft,padding: EdgeInsets.only(left: 15),child: Text(name! ,style: TitleStyle,),height:54,),/ / name
                  Container(color: ThemeColor,height: 0.5() [() [() [() [() [() [() [() [() }}Copy the code

We define the listView and use the listView. builder form to handle it, similar to our iOS cell reuse representation rather than static cells

  • itemBuilder

We define the header array and the contact number group, and the data is the one we defined before

final List<Friends> _headerData = [
  Friends(imageAssets: 'Images/new friend.png', name: 'New friends'),
  Friends(imageAssets: 'images/group chat. PNG', name: 'chatting'),
  Friends(imageAssets: 'images/tag. PNG', name: 'tags'),
  Friends(imageAssets: 'images/ public number.png ', name: 'Public Account')];final List<Friends> _listDatas = [];

Widget _itemBuilder(BuildContext context, int index) {
  if (index < _headerData.length) {
    / / before four
   return FriendCell(imageAssets: _headerData[index].imageAssets,
      name: _headerData[index].name,);
  } else {
   returnFriendCell(imageAssets: _listDatas[index - _headerData.length].imageAssets, name: _listDatas[index - _headerData.length].name,); }}Copy the code

Here’s the distinction, the first four and the last. In a listView display

child: ListView.builder(itemBuilder: _itemBuilder,
itemCount: _headerData.length+_listDatas.length,
Copy the code

The effect is roughly as follows

Let’s add the _listDatas data

@override
void initState() {
  // TODO: implement initState
  super.initState(); _listDatas .. addAll(datas) .. addAll(datas);/ / sorting
  _listDatas.sort((Friends a, Friends b) {
    returna.indexLetter! .compareTo(b.indexLetter!) ; }); }Copy the code

When we initialize the state, we add and process the data, sort the array using the sort method, compare their first letters and sort them in order.

  • Grouping title

Our cell will only be displayed when the group title is passed in, so we only need to compare each element of the current array with the next one. If the first letter is the same, we will not display it

bool isHideGroupTitle = (index -_headerData.length>0 &&_listDatas[index-_headerData.length].indexLetter == _listDatas[index-_headerData.length- 1].indexLetter);
Copy the code

The header group is fixed. If index =4, then index – _headerdata. length>0 is false. So the show head

Widget _itemBuilder(BuildContext context, int index) {
  bool isHideGroupTitle = (index -_headerData.length>0 &&_listDatas[index-_headerData.length].indexLetter == _listDatas[index-_headerData.length- 1].indexLetter);
  if (index < _headerData.length) {
    / / before four
   return FriendCell(imageAssets: _headerData[index].imageAssets,
      name: _headerData[index].name,);
  } else {

   return FriendCell(
      imageUrl: _listDatas[index - _headerData.length].imageUrl,
      name: _listDatas[index - _headerData.length].name,
      groupTitle: isHideGroupTitle?null: _listDatas[index - _headerData.length ].indexLetter,); }}Copy the code

The next article realizes the right indicator bar, and the linkage of the indicator bar.