iPhone Mail App’s Recipient Bubbles

new message screenshot

Notice how the recipient’s names are placed inside a bubble? Well, Apple wasn’t nice enough to provide this functionality out of the box. The three20 lib has a control that will provide this for you as part of the TTMessageController but good luck trying to get compatible up-to-date MonoTouch bindings for it.

So just do it  yourself! All you need is a class that inherits from UIView, let’s call it RecipientBubble. In that class you just need two subviews: a UILabel for the actual text that goes inside and a UIImageView for the background.

The only other thing you’ll need is the background image. How about this one? 

And now the code. Here’s the short version. For the more complete version see the gist on github.

public class RecipientBubble : UIView
{
  public const string IMAGES_PATH = "Content/Images";
  private static UIImage _backgroundImage;

  private UILabel _titleLabel;
  private UIImageView _backgroundView;

  static RecipientBubble()
  {
    _backgroundImage = UIImage.FromFile("recipientbackground.png").StretchableImage(11, 0);
  }

  public RecipientBubble(string title)
  {
    _titleLabel = new UILabel(new RectangleF(0, -100, 10, 23));
    _titleLabel.Font = UIFont.SystemFontOfSize(14);
    _titleLabel.TextAlignment = UITextAlignment.Center;
    _titleLabel.Text = title;
    _titleLabel.SizeToFit();
    _titleLabel.Frame = new RectangleF(0, 0, _titleLabel.Frame.Width + 20, 21);
    _titleLabel.TextColor = UIColor.White;
    _titleLabel.BackgroundColor = UIColor.Clear;
    AddSubview(_titleLabel);

    _backgroundView = new UIImageView(_backgroundImage);
    _backgroundView.Frame = new RectangleF(0, 0, _titleLabel.Frame.Width, 23);
    InsertSubviewBelow(_backgroundView, _titleLabel);

    SizeToFit();
  }
  ...
}

Your end result will look something like this.

Apple’s Push Notifications and Certificate Requests

A project i’ve been working on for several months now requires Apple’s Push Notifications (APNs) and we were stuck on a bug for nearly a week. Notifications were being sent through via the sandbox environment (gateway.sandbox.push.apple.com) but were not on the production environment (gateway.push.apple.com).

I had gone through all the documentation, generated my cert request, submitted it, downloaded it, installed it on our push provider service. Everything seemed right.

What’s more is that their production servers weren’t returning any error status. It was as if the notifications were going through just fine from our server’s side. The Feedback service wasn’t much help either because the tuples that were coming back were all zeros. But the fact that it was coming back with something told us there was something wrong. We just didn’t know what it was.

To make an already long story short, the fix was to create a new, separate, Certificate Request for your production environment. To reiterate, do not use the same Certificate Request go generate both sandbox and production certificates.

It was a painful week. But who knew right?

ZipArchive for MonoTouch

Compressing files in MonoTouch just got easier!

ZipArchive is taken from the Obj-C world. And it is by far one of the simplest, most elegant solutions I’ve seen for compressing files to an archive. Just open an archive, add files to compress and close it.

var zipFile = new LibZipArchive.ZipArchive();
zipFile.CreateZipFile2("/path/to/archive/file.zip");
zipFile.AddFile("/path/of/file/to/somefile.txt", "somefile.txt");
// add more files as needed
zipFile.CloseZipFile2();

The Obj-C library and bindings to C# can be found in the open source project monotouch-ziparchive on github.

Monotouch CLLocationManager AuthorizationStatus

The current release of MonoTouch (3.2.4) does not have bindings for CLLocationManager.AuthorizationStatus. Here is what you can use to get that value until they create that binding.

public static CLAuthorizationStatus AuthorizationStatus
{
  get
  {
    var classHandle = (new Class("CLLocationManager")).Handle;
    var selectorHandle = new Selector("authorizationStatus").Handle;
    return (CLAuthorizationStatus)Messaging
      .int_objc_msgSend(classHandle, selectorHandle);
  }
}

Modifying UIScrollView height when keyboard appears

When the keyboard appears over a UIScrollView (that includes the UITableView) the content underneath the keyboard isn’t accessible unless you change the height of the frame of the UIScrollView. Here’s how to do that in MonoTouch.

private NSObject _keyboardShowObserver;
private NSObject _keyboardHideObserver;

// this method assumes the height of a navigation bar on top
// hence the 44 pixels
public override void ViewWillAppear (bool animate)
{
  base.ViewWillAppear (animate);
  
  _keyboardShowObserver = NSNotificationCenter.DefaultCenter
    .AddObserver(UIKeyboard.WillShowNotification, (notification) => {
      var keyboardBounds = (NSValue)notification
        .UserInfo.ObjectForKey(UIKeyboard.BoundsUserInfoKey);
      var keyboardSize = keyboardBounds.RectangleFValue;
    
      UIView.BeginAnimations("k");
      UIView.SetAnimationBeginsFromCurrentState(true);
      _scrollView.Frame = new RectangleF(0, 44, View.Frame.Width, 
        View.Frame.Height - keyboardSize.Height - 44);
      UIView.CommitAnimations();
    });

  _keyboardHideObserver = NSNotificationCenter.DefaultCenter
    .AddObserver(UIKeyboard.WillHideNotification, (notification) => {
      UIView.BeginAnimations("k");
      UIView.SetAnimationBeginsFromCurrentState(true);
      _scrollView.Frame = new RectangleF(0, 44, 
        View.Frame.Width, View.Frame.Height - 44);
      UIView.CommitAnimations();
    });
}

// and don't forget to remove the observers on disappear
public override void ViewWillDisappear(bool animate)
{
  base.ViewWillDisappear(animate);
  NSNotificationCenter.DefaultCenter.RemoveObserver(_keyboardHideObserver);
  NSNotificationCenter.DefaultCenter.RemoveObserver(_keyboardShowObserver);
}

Generating Address Book Contacts on iPhone Simulator with MonoTouch

One of the things that I needed for testing my app was a list of contacts to play around with in the Contacts app on the iPhone simulator. The only way to do this is to either manually input contacts — which I am not willing to do for 50+ contacts — or programmatically add them in with a bit of random data.

I have done the latter. Check out the monotouch-generate-contacts project on github. This app, once run on the simulator, will add 50 contacts into the address book and generate some random phone numbers for each contact.

For those of you that don’t care about the project on git hub, here’s the main gist of how you add a contact to the address book.

var addressBook = new ABAddressBook();
var record = new ABPerson();
record.FirstName = "Marco";
record.LastName = "Polo";
var phones = new ABMutableStringMultiValue();
phones.Add("4566545555", ABPersonPhoneLabel.Mobile);
record.SetPhones(phones);
addressBook.Add(record);
addressBook.Save();