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.
Looks great. Thanks for that.
ReplyDeleteIs there anywhere the code available of you Bind and Command Implementation ?
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
DeleteThanks 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.
ReplyDeleteCheers