September 27, 2015

Sliding menu in Xamarin.iOS using GestureRecognizer,CATransition and Animation

In Brief:  Here I'm going through the steps involved in the Implementation of Sliding or Fly in-out menu or How to  making use of Gesture-recognizer, CATransition and Animation in Xamarin.iOS.


In my previous post shared my thought about How to implement sliding menu in Xamarin android, Best Practice and issues with ListView in Android XamarinHow to avoid ImageBitmap OutOfMemoryException and Rounded corner Image in android Xamarin,Drawing path between two location in xamarin android.

In detail:
Left to right menu is the basic feature in the most of the mobile application. Here I will show you one of the such implementation by using the basic
coding and not by using any components[You can also see some of the components supporting sliding menu in component store]
I have implemented by using UISwipeGestureRecognizer,CATransition and UIView Animate. As we know touch/swipe interaction is most user friendly interaction in
any application and in the same way animation is the key to designing a most pleasant user experience.

In steps:
1. Edit the story board
TableView is used to bind the menu item. Buttonview is used to show the expandable description window. Here left menu window should have the higher z-index value,
to get this add the tableview in the lower order in the view controller scene as shown in the below Xcode interface builder screen.



2.Create new xib for custom tableviewcell for menu window.




3.1.Write the tableview source class as follows,
//MenuTableSourceClass.cs
using System;
using UIKit;
namespace iOSSlidingMenu
{
 public class MenuTableSourceClass :UITableViewSource
 {
  readonly string[] arrMenuText;
  readonly string[] arrMenuIcon;
  internal event Action<string> MenuSelected;

  public MenuTableSourceClass ()
  {
   arrMenuText=ConstantsClass.arrMenuText;
   arrMenuIcon = ConstantsClass.arrMenuIcon;
  }

  public override nint RowsInSection (UITableView tableview, nint section)
  {
   return arrMenuText.Length;
  }

  public override UITableViewCell GetCell (UITableView tableView, Foundation.NSIndexPath indexPath)
  {
   MenuTableViewCell cell = tableView.DequeueReusableCell ( MenuTableViewCell.Key ) as MenuTableViewCell ?? MenuTableViewCell.Create ();
   cell.BindData (arrMenuText[indexPath.Row],arrMenuIcon[indexPath.Row]);
   return cell; 
  }

  public override void RowSelected (UITableView tableView, Foundation.NSIndexPath indexPath)
  {
   if ( MenuSelected != null )
    MenuSelected (arrMenuText[indexPath.Row]);

   tableView.DeselectRow (indexPath,true);
  }

  public override UIView GetViewForFooter (UITableView tableView, nint section)
  {
   return new UIView ();
  }

 }
}

3.2. Edit the MenuTableViewCell class as follows,
//MenuTableViewCell.cs
using System;
using Foundation;
using UIKit;

namespace iOSSlidingMenu
{
 public partial class MenuTableViewCell : UITableViewCell
 {
  public static readonly UINib Nib = UINib.FromName ( "MenuTableViewCell" , NSBundle.MainBundle );

  public static readonly NSString Key = new NSString ( "MenuTableViewCell" );

  public MenuTableViewCell ( IntPtr handle ) : base ( handle )
  {
  }

  public static MenuTableViewCell Create ()
  {
   return ( MenuTableViewCell ) Nib.Instantiate ( null , null ) [0];
  }
  internal void BindData(string strLabel,string strIconPath)
  { 
   lblMenuText.Text =strLabel;
   imgViewMenuIcon.Image = UIImage.FromBundle ( strIconPath ); 
  }

 }
}

4. Edit the viewcontroller
4.1. Bind the menu items.
4.2. Define UISwipeGestureRecognizer to detect onscreen swipe
4.2. CATransition is used to give transition effect to left menu.
4.3. UIView.Animate is used to give up and down movement to description window.

//ViewController.cs
using System; 
using CoreAnimation;
using CoreGraphics;
using UIKit; 
namespace iOSSlidingMenu
{
 public partial class ViewController : UIViewController
 {
  MenuTableSourceClass objMenuTableSource;
  nfloat flViewShiftUpY;
  nfloat flViewBringDownY;
  public ViewController ( IntPtr handle ) : base ( handle )
  {
  }
  public override void ViewDidLoad ()
  {
   base.ViewDidLoad (); 
   FnInitializeView();
   tableViewLeftMenu.Hidden = true;
   FnBindMenu ();
  }
  void FnInitializeView()
  {
   CGRect rectBounds= UIScreen.MainScreen.Bounds;
   flViewBringDownY = rectBounds.Height - 30f; //complete collapse description viewContainer
   flViewShiftUpY = rectBounds.Height - 120f;//200 is the height of description viewContainer
   
            // Define custom  UISwipeGestureRecognizer 
   var recognizerRight = new UISwipeGestureRecognizer (FnSwipeLeftToRight);
   recognizerRight.Direction = UISwipeGestureRecognizerDirection.Right;
   View.AddGestureRecognizer ( recognizerRight );

   var recognizerLeft = new UISwipeGestureRecognizer (FnSwipeRightToLeft);
   recognizerLeft.Direction = UISwipeGestureRecognizerDirection.Left;
   View.AddGestureRecognizer ( recognizerLeft );

   viewDecriptionContainer.Hidden = true;

   btnIcon.SetBackgroundImage ( UIImage.FromBundle ( "Images/menu_icon" ) , UIControlState.Normal );
   btnBottom.SetBackgroundImage ( UIImage.FromBundle ( "Images/down_arrow" ) , UIControlState.Selected );

   btnBottom.TouchUpInside+= delegate(object sender , EventArgs e )
   {
    if(viewDecriptionContainer.Hidden)
     viewDecriptionContainer.Hidden=false;
    
    if(!btnBottom.Selected)
     FnAnimateView(flViewShiftUpY,viewDecriptionContainer);
     else
     FnAnimateView(flViewBringDownY,viewDecriptionContainer); 
    
    btnBottom.Selected = !btnBottom.Selected;
   };
   btnIcon.TouchUpInside += delegate(object sender , EventArgs e )
   {
    FnPerformTableTransition();
   };
  }
  void FnSwipeLeftToRight()
  {
   if ( tableViewLeftMenu.Hidden )
    FnPerformTableTransition ();
    
  }
  void FnSwipeRightToLeft()
  {
   if ( !tableViewLeftMenu.Hidden )
    FnPerformTableTransition ();
  }
  void FnPerformTableTransition()
  {
   tableViewLeftMenu.Hidden = !tableViewLeftMenu.Hidden;
   //transition effect to left menu.
   var transition = new CATransition ();
   transition.Duration = 0.25f;
   transition.Type = CAAnimation.TransitionPush;
   if ( tableViewLeftMenu.Hidden )
   {
    transition.TimingFunction = CAMediaTimingFunction.FromName ( new Foundation.NSString ("easeOut") );
    transition.Subtype = CAAnimation.TransitionFromRight;
   }
   else
   {
    transition.TimingFunction = CAMediaTimingFunction.FromName ( new Foundation.NSString ("easeIn") );
    transition.Subtype = CAAnimation.TransitionFromLeft;
   }
   tableViewLeftMenu.Layer.AddAnimation ( transition , null );
  } 
  //up and down movement to description window.
  void FnAnimateView(nfloat frameY,UIView view)
  {
   UIView.Animate ( 0.2f , 0.1f , UIViewAnimationOptions.CurveEaseIn , delegate
   {
    var frame = View.Frame; 
    frame.Y = frameY;
    view.Frame = frame;
   } , null );
  }
  void FnBindMenu()
  {
   if(objMenuTableSource!=null)
   {
    objMenuTableSource.MenuSelected -= FnMenuSelected;
    objMenuTableSource = null;
   }
   objMenuTableSource = new MenuTableSourceClass ();
   objMenuTableSource.MenuSelected += FnMenuSelected;
   tableViewLeftMenu.Source = objMenuTableSource; 
  }
  void FnMenuSelected(string strMenuSeleted)
  {
   txtActionBarText.Text = strMenuSeleted;
   FnSwipeRightToLeft ();
  }
  public override void DidReceiveMemoryWarning ()
  {
   base.DidReceiveMemoryWarning ();
   // Release any cached data, images, etc that aren't in use.
  }
 }
}

ConstantsClass.cs
using System;
namespace iOSSlidingMenu
{
 public static class ConstantsClass
 {
  public static string[] arrMenuText=new string[]{"Home","AboutUs","Products","Events","Serivce","Clients","Help","Solution","ContactUs",""};
  public static string[] arrMenuIcon= new string[]{"Images/icon_home","Images/icon_aboutus","Images/icon_product","Images/icon_event","Images/icon_service","Images/icon_client","Images/icon_help","Images/icon_solution","Images/icon_contactus",""};
 }
}

Explore the code at github: https://github.com/suchithm/SlidingMenu_Xamarin.iOS

Screen recording:




Final touch:
This is all about the implementation of GestureRecognizer,CATransition and UIView Animation in Xamarin.iOS,rest is the regular coding.
Thanks for your time here. Comment your suggestion/thought,report the bug if any...
Visit again.