Creating Google Hangouts Style Images in Xamarin iOS

If you haven’t seen it yet, there is this nifty style of thumbnail, icon, image, etc that Google does in their Hangouts app along with some of their others.

hangouts
Google Hangouts

Notice the second image and the last one where they take images from members of your hangout and lay  them together in an orderly fashion based on the number of people you have.

Here is the logic:

  1. One other person – Show the other user’s image
  2. Two other people – Show both other user’s images diagonally from each other
  3. Three other people – Show the three images in a triangle or pyramid shape
  4. Four or more people – Show 4 images in a square

This logic is straightforward with platforms like Windows and Android where you can create the layouts for each one and switch which one is visible based on the number of members. In this case, however, we are going to explore my favorite way to do it in iOS while still using the standard UITableViewCell.

This means rather than using multiple UIImageViews to display each one, we need to create the image in ONE UIImageView. Here is a simple method I use to do something like this:

  private UIImage GetHangoutImage(HangoutVM hangout, UIView container)
        {
            var members = hangout.Members
                    .Where(im => CurrentUser.FullName != im.Name)
                    .Where(im => !string.IsNullOrEmpty(im.ImageUrl))
                    .Take(4)
                    .ToList();
            if (!string.IsNullOrEmpty(hangout.ImageUrl))
            {
                //if the hangout has an image, use that url
                return Extensions.UIImageFromUrl(hangout.ImageUrl);
            }
            else if (members.Count == 0)
            {
                //if no other members, show self
                return Extensions.GetRoundImage(Extensions.UIImageFromUrl(CurrentUser.ImageUrl));
            }
            else if (members.Count == 1)
            {
                //show the one other member's image
                return Extensions.GetRoundImage(Extensions.UIImageFromUrl(members[0].ImageUrl));
            }
            else if (members.Count == 2)
            {
                //if 2 other members, show both their images diagonally
                UIGraphics.BeginImageContext(new CoreGraphics.CGSize(container.Frame.Height, container.Frame.Height));
                UIImage image1;
                UIImage image2;
                UIImage combinedImage;
                image1 = Extensions.GetRoundImage(Extensions.UIImageFromUrl(members[0].ImageUrl));
                image2 = Extensions.GetRoundImage(Extensions.UIImageFromUrl(members[1].ImageUrl));

                image1.Draw(new RectangleF(22, 0, 22, 22));
                image2.Draw(new RectangleF(0, 22, 22, 22));
                combinedImage = UIGraphics.GetImageFromCurrentImageContext();
                UIGraphics.EndImageContext();
                return combinedImage;
            }
            else if (members.Count == 3)
            {
                //if 3 other members, show all three images in a triangle
                UIGraphics.BeginImageContext(new CoreGraphics.CGSize(container.Frame.Height, container.Frame.Height));

                UIImage image1;
                UIImage image2;
                UIImage image3;
                UIImage combinedImage;
                image1 = Extensions.GetRoundImage(Extensions.UIImageFromUrl(members[0].ImageUrl));
                image2 = Extensions.GetRoundImage(Extensions.UIImageFromUrl(members[1].ImageUrl));
                image3 = Extensions.GetRoundImage(Extensions.UIImageFromUrl(members[2].ImageUrl));
                image1.Draw(new RectangleF(0, 0, 22, 22));
                image2.Draw(new RectangleF(22, 0, 22, 22));
                image3.Draw(new RectangleF(11, 22, 22, 22));
                combinedImage = UIGraphics.GetImageFromCurrentImageContext();

                UIGraphics.EndImageContext();
                return combinedImage;
            }
            else
            {
                //if 4 or more show first 4 in square
                UIGraphics.BeginImageContext(new CoreGraphics.CGSize(container.Frame.Height, container.Frame.Height));

                UIImage image1;
                UIImage image2;
                UIImage image3;
                UIImage image4;
                UIImage combinedImage;
                image1 = Extensions.GetRoundImage(Extensions.UIImageFromUrl(members[0].ImageUrl));
                image2 = Extensions.GetRoundImage(Extensions.UIImageFromUrl(members[1].ImageUrl));
                image3 = Extensions.GetRoundImage(Extensions.UIImageFromUrl(members[2].ImageUrl));
                image4 = Extensions.GetRoundImage(Extensions.UIImageFromUrl(members[3].ImageUrl));

                image1.Draw(new RectangleF(0, 0, 22, 22));
                image2.Draw(new RectangleF(22, 0, 22, 22));
                image3.Draw(new RectangleF(0, 22, 22, 22));
                image4.Draw(new RectangleF(22, 22, 22, 22));

                combinedImage = UIGraphics.GetImageFromCurrentImageContext();
                UIGraphics.EndImageContext();
                return combinedImage;
            }
        }

In this situation I’m using some hard coded values for the sake of readability. The height of my UITableViewCell is 44 (hence seeing the 22’s everywhere for splitting it in half).

Also, I use a static extensions class to get images from a url and also to create round images. I talked about these in previous blog posts here:

  1. Creating Round Images in Xamarin.iOS
  2. Creating a UIImage from a URL

So now that we have our means of getting the image, we can create it in our GetCell override method in our TableViewSource class we are using to populate our UITableView:

  public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
        {
            var cellIdentifier = _hangouts[indexPath.Row].ID.ToString();
            var currentHangout = _hangouts[indexPath.Row];

            UITableViewCell cell = tableView.DequeueReusableCell(cellIdentifier);

            //// if there are no cells to reuse, create a new one
            if (cell == null)
                cell = new InstanceTableViewCell(currentInstance);
            cell = new UITableViewCell(UITableViewCellStyle.Subtitle, cellIdentifier);
            cell.TextLabel.Text = currentHangout.DisplayName;
            cell.DetailTextLabel.Text = string.Format("{0}{1}", currentHangout.LastMessageMember, currentHangout.LastMessage);
            cell.ImageView.Image = GetHangoutImage(currentHangout, cell.ImageView); // Get the Hangout Style Image
            return cell;
        }

That’s really as far as it goes! Now using that, you’ll get something looking like this:
instancesscreenshotioscropped

The lack of spacing may be misleading, but you’ll notice the first cell has 2 other members, the second has one, the third has 4+, the 4th has 3, etc.

Feel free to comment if you have any questions or want more advice on how to make something like this more appealing!

Advertisements