preface

Really have a period of time did not write a blog, because in the past period of time work is really too busy ๐Ÿ˜…, but busy also have busy benefits, in the whole process of their own learning is also very fast, in the busy to enrich themselves, learn some new knowledge. Because I just implemented IM on the pure Flutter side (damn hard! ๐Ÿคฃ) blog about some of my understanding of the UI throughout the implementation process. Today! I would like to introduce my bubble family ๐Ÿ”ฎ, which is the chat bubble of Balbla ~ in wechat that you see.

Show Time

Plain and simple – text bubble ๐Ÿ“’

First is more normal, ๐Ÿณ but is the most important, text bubble, this bubble, in fact, does not need too many functions, practical, simple, accurate, can seize the heart, simply say is to let the user feel very comfortable. Let’s take a look at our finished product:





Don’t ask me why I have rounded corners, because that’s what our art team does. Some people think it’s pretty, some people think it’s ugly, but I think it’s ok. To introduce the key points, the most critical point is how we control the width and height of the bubble, so that the text reaches a certain length after the automatic wrapping ๐Ÿค”? Enter the protagonist —ConstrainedBox.ConstrainedBoxWhat is itWidget? As the name impliesConstrainedBoxYou can have itWidgetWith some restrictions, that would be great, but what we want to do is think about it differently is actually limit the maximum width of the bubble, but we don’t limit the height, right. So our text bubble was born ๐Ÿš€

Widget textBubble(String content,Color colors,Color txtColor,double bottomleft,double bottomRight){
  return ConstrainedBox(
    constraints: BoxConstraints(
        maxWidth: 500.w
    ),
    child: Container(
      margin: EdgeInsets.only(top: 10.h),
      padding: EdgeInsets.symmetric(
        horizontal: 34.w,
        vertical: 18.h,
      ),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.only(bottomLeft: Radius.circular(bottomleft), bottomRight: Radius.circular(bottomRight),topRight: Radius.circular(0.0),topLeft: Radius.circular(5.0)),
        color: colors,
      ),
      child: Text(content,style: TextStyle(color:txtColor,fontSize: 28.sp),),
    ),
  );
}
Copy the code

Ignoring some business values ๐Ÿ“ˆ, we use a ConstrainedBox to specify the maximum width and define the radians of the four corners that are key to the implementation ๐Ÿ‘€.

Details – voice bubbles ๐Ÿ”Š

Voice is an essential part of chat, some users like to send voice, if you just want to make a simple voice bubble, very simple, replace the text in the above text bubble with a voice picture, but you will find that the user experience is very poor, you do not want to use ๐Ÿ˜‘. I personally can’t accept such a product, so you can work with me to improve our bubble:

The animation

Since speaking of user experience, the playback of animation is essential. When users click the voice bubble to play the sound only, they do not know which bubble is clicked, and the user feels very bad ๐Ÿคจ. This animation often stumps many students. It’s not that hard. We have artists! Please refer to wechat or the finished product picture below and think about whether it is necessary for us to draw an animation by ourselves. In fact, there is no need, our horn, in fact, is three pictures of the non-stop replacement just ๐Ÿ’ก.



Such a voice picture to make it move โ›“, we actually only need ~ a white dot picture, a white dot and arc picture



Look, three pictures in turn is an animation! The implementation scheme is our timer โฐ, with a timer not half a second to switch the picture, the pro test effect is very nice ๐Ÿ‘

    _timer = new Timer.periodic(new Duration(milliseconds: 500), (timer) {
      if(i == 3)
        {
          i = 1;
        }
      else
        {
          i ++;
        }
     setState(() {
       if(i == 1)
         {
           _voiceImage = "assets/images/voice_point_right.png";
         }
       if(i == 2)
         {
           _voiceImage = "assets/images/voice_step_left.png";
         }
       if(i == 3)
         {
           _voiceImage = "assets/images/voice_left.png"; }}); });Copy the code

The length of the bubble

In fact in the user’s interaction and critical a small detail, is the length of the speech bubble ๐Ÿ“, we can write a little algorithm, make different speech, to control the length of the bubble, the small changes will greatly increase the page is beautiful, here give you mean, you to control the width of the bubble, Be sure to control the maximum length and minimum length, 1s voice and 100s voice can easily make your length too long ๐Ÿ•น

 double width = 0.0;
  width = timeLength * 2 * 20.w;
  if(width < 150.w)
  {
    width = 150.w;
  }
  if(width > 400.w)
  {
    width = 400.w;
  }
Copy the code

Finally, our voice bubble looks like this, plus the click animation, which is really love:

The source code

Widget voiceBubble(int timeLength,Color colors,double bottomleft,double bottomRight, String voiceImage){
  double width = 0.0;
  width = timeLength * 2 * 10.w;
  if(width < 150.w)
  {
    width = 150.w;
  }
  if(width > 400.w)
  {
    width = 400.w;
  }
  return   Container(
    margin: EdgeInsets.only(top: 10.h),
    width: width,
    padding: EdgeInsets.symmetric(
      horizontal: 34.w,
      vertical: 18.h,
    ),
    decoration: BoxDecoration(
      borderRadius: BorderRadius.only(bottomLeft: Radius.circular(bottomleft), bottomRight: Radius.circular(bottomRight),topRight: Radius.circular(0.0),topLeft: Radius.circular(5.0)),
      color: colors,
    ),
    child: Row(
      mainAxisAlignment: MainAxisAlignment.end,
      children: [
        Text((timeLength).toString() + "" '",style: TextStyle(color: Colors.white),),
        SizedBox(width: 20.w,),
        Image.asset(voiceImage,color: Colors.white,width: 24.w),
      ],
    ),
  );
}
Copy the code

Honest honest – picture bubble ๐Ÿ–ผ

Picture bubble is also an indispensable part of our daily chat, how to make pictures for users to display, next I will show you how to make a fantastic picture bubble! Image bubbles, you can also carefully think about which points need to pay attention to, you as a user, received a picture message, what do you care about the most? What is?

The Size of the picture

Open up your album, flip through a few photos, and you’ll find, in addition to the photos you took with your phone’s camera, you’ll also have, downloaded from a third-party platform, cropped. Your bubbles can’t be fixed in length and width, they need to be very dynamic. For the production of this point, the art team and I referred to some schemes of wechat ๐Ÿญ. We set the maximum width and height for the picture. Within this range, we will display the picture according to its size, but beyond this length and width, we will perform operations like compression and cutting โœ‚๏ธ to make the picture look as neat as possible. The vertical pictures still have a vertical composition, and the horizontal pictures do the same.

Display of pictures

Pictures certainly need to be further displayed to the user, so that the user can view the big picture ๐Ÿš , right, how to view the big picture, refer to the practice of most apps on the market – new page! At the same time, in order to maximize user experience, we also need to add jump animation to the interface. This animation is Hero animation provided by Flutter, which is very suitable for our business scenes, and is used to display large pictures ๐ŸŽฑ.

Zooming in and out

Now that we’ve reached the image display, we’re going for the ultimate user experience, and we’re making it zoom! Functions can be realized directly through plug-ins, familiar with the API, but to pay attention to the scaling limits, I directly refer to ๐ŸŽ Apple’s scaling limits, no other meaning, Apple’s user experience is unparalleled.

End result:

Source:

Widget imageBubble(BuildContext context,String url){
  final String imgUrl = "";
  return GestureDetector(
    onTap: (){
      Navigator.push(
        context,
        CupertinoPageRoute(
          builder: (context) => HeroPhotoViewRouteWrapper(
              url: url,
              minScale: 0.1,
              maxScale: 1.5,
              imageProvider: NetworkImage(
                  url
              )
          ),
        ),
      );
    },
    child: Hero(
      tag: "${url}",
      child: Container(
        margin: EdgeInsets.only(top: 10.h),
        padding: EdgeInsets.symmetric(
          vertical: 10.h,
        ),
        child: ConstrainedBox(
          constraints: BoxConstraints(maxHeight: 300.h,maxWidth: 400.w),
          child: Container(
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(10.0),
              color: Theme.of(context).brightness == Brightness.light ? Color.fromRGBO(237.237.237.1) : Color.fromRGBO(17.17.17.1), ), child: ClipRRect(! [](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e4fa8e3341974cf688fb2238394bda77~tplv-k3u1fbpfcp-watermark.image)
              borderRadius: BorderRadius.circular(10.0),
              child: CachedNetworkImage(
                imageUrl: url,
                placeholder: (context, url) => SizedBox(
                  width: 100.w,
                  height: 100.h,
                  child: Center(
                    child: LoadingIndicator(indicatorType: Indicator.ballClipRotateMultiple, color: Theme.of(context).brightness == Brightness.light ? Color.fromRGBO(61.93.237.1) : Color.fromRGBO(54.83.193.1),),
                  ),
                ),
                errorWidget: (context, url, error) => new Icon(Icons.error),
              ),
            ),
          ),
        ),
      ),
    ),
  );
}

Copy the code

At the end

The above is part of my bubble ๐Ÿงฝ that I introduced to you. If you are interested, I will share more beautiful and complex bubbles with you in the future. In the whole development process, we must pay attention to user experience and think ๐Ÿ”ซ from the user’s point of view.

๐Ÿณ Welcome to my ๐Ÿ”— Github