[disclaimer]


This is a personal blog. The opinions expressed here represent my own and not those of any of my employers or customers.

Except if stated otherwise, all the code shared is reusable under a MIT/X11 licence. If a picture is missing a copyright notice, it's probably because I'm owning it.

Friday, April 26, 2013

Decorating your Xamarin.iOS code with Behaviors

Note: this is the post in which I'm getting out of the closet and make it clear that I had an affair with Silverlight. I'm still thinking about it sometimes, and when I do, this is what happens...

Every time you have to ask your user "What's your favourite colour" or "What is the air-speed velocity of an unladen swallow?" from within your iOS application, you have to ask yourself "Wait, will the field still be visible with the virtual keyboard displayed ?"

I don't know how you do it (experience sharing is welcome), but me, I do it this way:

public override void ViewDidLoad ()
{
 base.ViewDidLoad ();

 //Set Bindings and Commands
 placeField.Bind (ViewModel, "Place");
 sendButton.Command (ViewModel.SendCommand);
 busyIndicator.Bind (ViewModel, "IsBusy");

 //Slide the view on keyboard show/hide
 placeField.EditingDidBegin += (sender, e) => {
  UIView.BeginAnimations ("keyboardslide");
  UIView.SetAnimationCurve (UIViewAnimationCurve.EaseInOut);
  UIView.SetAnimationDuration (.3f);
  var frame = View.Frame;
  frame.Y = -100;
  View.Frame = frame;
  UIView.CommitAnimations();
 };

 placeField.EditingDidEnd += (sender, e) => {
  UIView.BeginAnimations ("keyboardslide");
  UIView.SetAnimationCurve (UIViewAnimationCurve.EaseInOut);
  UIView.SetAnimationDuration (.3f);
  var frame = View.Frame;
  frame.Y = 20;
  View.Frame = frame;
  UIView.CommitAnimations();
 };

}



It works fine, but looks messy next to readable code setting bindings or commands (those come from a very light Binding library I'm working on). Then yesterday evening, I had a realisation. It looks very similar to Silverlight Behaviors, so this code could just be like:

 placeField.Attach (new SlideOnEditBehavior (View, defaultPosition:20, alternatePosition:-100));

And the SlideOnEditBehavior is kept aside (OnDetaching implementation left out for clarity):

public class SlideOnEditBehavior : Behavior
{
 UIView view;
 int defaultPosition;
 int alternatePosition;

 public SlideOnEditBehavior (UIView view, int defaultPosition, int alternatePosition)
 {
  this.view = view;
  this.defaultPosition = defaultPosition;
  this.alternatePosition = alternatePosition;
 }

 protected override void OnAttached ()
 {
  base.OnAttached ();
  AssociatedObject.EditingDidBegin += (sender, e) => {
   UIView.BeginAnimations ("keyboardslide");
   UIView.SetAnimationCurve (UIViewAnimationCurve.EaseInOut);
   UIView.SetAnimationDuration (.3f);
   var frame = view.Frame;
   frame.Y = alternatePosition;
   view.Frame = frame;
   UIView.CommitAnimations();
  };

  AssociatedObject.EditingDidEnd += (sender, e) => {
   UIView.BeginAnimations ("keyboardslide");
   UIView.SetAnimationCurve (UIViewAnimationCurve.EaseInOut);
   UIView.SetAnimationDuration (.3f);
   var frame = view.Frame;
   frame.Y = defaultPosition;
   view.Frame = frame;
   UIView.CommitAnimations();
  };
 }
}

Cleaner. Simpler. Reusable. And it also supports BehaviorCollections:

 placeField.Attach (new BehaviorCollection {
  new SlideOnEditBehavior (View, defaultPosition:20, alternatePosition:-100),
  //Any other behavior here
 });

As expected, the code for all of this is trivial, but if you like the idea and save yourself the 30 minutes it takes to write it, it's on Github.

[UPDATE: 2013-04-26] I updated the code as per Stuart Lodge suggestion (of MvvmCross) to use WeakReference to NSObjects. Doesn't change the API at all.


3 comments:

  1. Looks great. Thanks for that.

    Is there anywhere the code available of you Bind and Command Implementation ?

    ReplyDelete
    Replies
    1. those Bind() and Command() are very trivial, but as you're not the first to ask for it, I guess I'll have to release that in the wild. Probably with my lightweight Mvvm as well

      Delete
  2. Thanks for this, saved me some big headaches. Thought I was going to have to rewrite a buttload of code, but this was an easy solution.
    Cheers

    ReplyDelete