Building Beautiful UI Interfaces with Flutter-Basic Components

In this post we are going to design the Simple Layout with Flutter-Basic Components

1.1 Preparation-Data Type


Based on the contents of the above card, we can define some fields. In order to standardize the development process, we first define a data type class for the card, so that the data can be better mocked and managed in the subsequent development process:

class BookViewModel {
  final String coverUrl;

  final String authorImgUrl;

  final String authorName;

  final String description;

  final String topic;

  final String publishTime;

  final String publishContent;

  final int replies;

  final int likes;

  final int shares;

  const BookViewModel({
    this.coverUrl,
    this.authorImgUrl,
    this.authorName,
    this.description,
    this.topic,
    this.publishTime,
    this.publishContent,
    this.replies,
    this.likes,
    this.shares,
  });
}

 

1.2 Build the skeleton and split the layout

Based on above Figure, we can split the whole, is divided into a total of four parts: Cover, AuthorInfo, PublishContent and InteractionArea. To do this, we can build the basic skeleton of the code:

class BookView extends StatelessWidget {
  final BookViewModel data;

  const BookView({
    Key key,
    this.data,
  }) : super(key: key);

  Widget renderCover() {
    
  }

  Widget renderAuthorInfo() {
    
  }

  Widget renderPublishContent() {
  
  }

  Widget renderInteractionArea() {
   
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(8),
        boxShadow: [
          BoxShadow(
            blurRadius: 6,
            spreadRadius: 4,
            color: Color.fromARGB(20, 0, 0, 0),
          ),
        ],
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
         renderCover(),
          renderAuthorInfo(),
          renderPublishContent(),
         renderInteractionArea(),
        ],
      ),
    );
  }
}

 

 

1.3 Cover area

In order to better highlight the effect of the picture, a mask layer is added here, so it can be used here Stack/ Positioned layout and LinearGradientgradient.

Widget renderCover() {
  return Stack(
    fit: StackFit.passthrough,
    children: <Widget>[
      ClipRRect(
        borderRadius: BorderRadius.only(
          topLeft: Radius.circular(8),
          topRight: Radius.circular(8),
        ),
        child: Image.network(
          data.coverUrl,
          height: 200,
          fit: BoxFit.fitWidth,
        ),
      ),
      Positioned(
        left: 0,
        top: 100,
        right: 0,
        bottom: 0,
        child: Container(
          decoration: BoxDecoration(
            gradient: LinearGradient(
              begin: Alignment.topCenter,
              end: Alignment.bottomCenter,
              colors: [
                Color.fromARGB(0, 0, 0, 0),
                Color.fromARGB(80, 0, 0, 0),
              ],
            ),
          ),
        ),
      ),
    ],
  );
}

 

1.4 Author Information Area

The Author information area is very suitable for layout using components Row and Column components.

Widget renderUserInfo() {
  return Container(
    margin: EdgeInsets.only(top: 16),
    padding: EdgeInsets.symmetric(horizontal: 16),
    child: Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: <Widget>[
        Row(
          children: <Widget>[
            CircleAvatar(
              radius: 20,
              backgroundColor: Color(0xFFCCCCCC),
              backgroundImage: NetworkImage(data.authorImgUrl),
            ),
            Padding(padding: EdgeInsets.only(left: 8)),
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Text(
                  data.userName,
                  style: TextStyle(
                    fontSize: 15,
                    fontWeight: FontWeight.bold,
                    color: Color(0xFF333333),
                  ),
                ),
                Padding(padding: EdgeInsets.only(top: 2)),
                Text(
                  data.description,
                  style: TextStyle(
                    fontSize: 12,
                    color: Color(0xFF999999),
                  ),
                ),
              ],
            ),
          ],
        ),
        Text(
          data.publishTime,
          style: TextStyle(
            fontSize: 13,
            color: Color(0xFF999999),
          ),
        ),
      ],
    ),
  );
}

 

1.5 Publishing Content Area

Through the UI exercises in this area, we can practice Container different component settings borderRadius and Text truncation processing when the component text content is exceeded. 
Widget renderPublishContent() {
  return Container(
    margin: EdgeInsets.only(top: 16),
    padding: EdgeInsets.symmetric(horizontal: 16),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        Container(
          margin: EdgeInsets.only(bottom: 14),
          padding: EdgeInsets.symmetric(horizontal: 8, vertical: 2),
          decoration: BoxDecoration(
            color: Color(0xFFFFC600),
            borderRadius: BorderRadius.only(
              topRight: Radius.circular(8),
              bottomLeft: Radius.circular(8),
              bottomRight: Radius.circular(8),
            ),
          ),
          child: Text(
            '# ${data.topic}',
            style: TextStyle(
              fontSize: 12,
              color: Colors.white,
            ),
          ),
        ),
        Text(
          data.publishContent,
          maxLines: 2,
          overflow: TextOverflow.ellipsis,
          style: TextStyle(
            fontSize: 15,
            fontWeight: FontWeight.bold,
            color: Color(0xFF333333),
          ),
        ),
      ],
    ),
  );
}

 

1.6 Interactive Area

In this module, we will use the Icon  component, which can control its size and color and other attributes

Widget renderInteractionArea() {
  return Container(
    margin: EdgeInsets.symmetric(vertical: 16),
    padding: EdgeInsets.symmetric(horizontal: 16),
    child: Row(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: <Widget>[
        Row(
          children: <Widget>[
            Icon(
              Icons.message,
              size: 16,
              color: Color(0xFF999999),
            ),
            Padding(padding: EdgeInsets.only(left: 6)),
            Text(
              data.replies.toString(),
              style: TextStyle(
                fontSize: 15,
                color: Color(0xFF999999),
              ),
            ),
          ],
        ),
        Row(
          children: <Widget>[
            Icon(
              Icons.favorite,
              size: 16,
              color: Color(0xFFFFC600),
            ),
            Padding(padding: EdgeInsets.only(left: 6)),
            Text(
              data.likes.toString(),
              style: TextStyle(
                fontSize: 15,
                color: Color(0xFF999999),
              ),
            ),
          ],
        ),
        Row(
          children: <Widget>[
            Icon(
              Icons.share,
              size: 16,
              color: Color(0xFF999999),
            ),
            Padding(padding: EdgeInsets.only(left: 6)),
            Text(
              data.shares.toString(),
              style: TextStyle(
                fontSize: 15,
                color: Color(0xFF999999),
              ),
            ),
          ],
        ),
      ],
    ),
  );
}

 

1.7 Summary


Through the above example, we successfully dismantled a seemingly complex UI interface step by step