diff --git a/.gitignore b/.gitignore index 93b58f7..1cfd7c3 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ bin obj .DS_Store +*.suo +*.csproj.user diff --git a/MTSplitViewController.sln b/MTSplitViewController.sln index 750cd4e..95130ea 100644 --- a/MTSplitViewController.sln +++ b/MTSplitViewController.sln @@ -1,34 +1,53 @@  -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MTSplitViewController", "MTSplitViewController\MTSplitViewController.csproj", "{F9F6FA20-0DBC-446B-BFC4-B0190D530F18}" +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MTSplitViewControllerDemo", "MTSplitViewControllerDemo\MTSplitViewControllerDemo.csproj", "{F9F6FA20-0DBC-446B-BFC4-B0190D530F18}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MTSplitViewLib", "MTSplitViewLib\MTSplitViewLib\MTSplitViewLib.csproj", "{86B4F178-F272-4404-8CF5-140A5A84CBC2}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MTSplitViewLib", "MTSplitViewLib\MTSplitViewLib.csproj", "{86B4F178-F272-4404-8CF5-140A5A84CBC2}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|iPhoneSimulator = Debug|iPhoneSimulator - Release|iPhoneSimulator = Release|iPhoneSimulator + Debug|Any CPU = Debug|Any CPU Debug|iPhone = Debug|iPhone + Debug|iPhoneSimulator = Debug|iPhoneSimulator + Debug|Mixed Platforms = Debug|Mixed Platforms + Release|Any CPU = Release|Any CPU Release|iPhone = Release|iPhone + Release|iPhoneSimulator = Release|iPhoneSimulator + Release|Mixed Platforms = Release|Mixed Platforms EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {86B4F178-F272-4404-8CF5-140A5A84CBC2}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {86B4F178-F272-4404-8CF5-140A5A84CBC2}.Debug|iPhone.Build.0 = Debug|Any CPU - {86B4F178-F272-4404-8CF5-140A5A84CBC2}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {86B4F178-F272-4404-8CF5-140A5A84CBC2}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {86B4F178-F272-4404-8CF5-140A5A84CBC2}.Release|iPhone.ActiveCfg = Release|Any CPU - {86B4F178-F272-4404-8CF5-140A5A84CBC2}.Release|iPhone.Build.0 = Release|Any CPU - {86B4F178-F272-4404-8CF5-140A5A84CBC2}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {86B4F178-F272-4404-8CF5-140A5A84CBC2}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {F9F6FA20-0DBC-446B-BFC4-B0190D530F18}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator {F9F6FA20-0DBC-446B-BFC4-B0190D530F18}.Debug|iPhone.ActiveCfg = Debug|iPhone {F9F6FA20-0DBC-446B-BFC4-B0190D530F18}.Debug|iPhone.Build.0 = Debug|iPhone {F9F6FA20-0DBC-446B-BFC4-B0190D530F18}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator {F9F6FA20-0DBC-446B-BFC4-B0190D530F18}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator + {F9F6FA20-0DBC-446B-BFC4-B0190D530F18}.Debug|Mixed Platforms.ActiveCfg = Debug|iPhone + {F9F6FA20-0DBC-446B-BFC4-B0190D530F18}.Debug|Mixed Platforms.Build.0 = Debug|iPhone + {F9F6FA20-0DBC-446B-BFC4-B0190D530F18}.Release|Any CPU.ActiveCfg = Release|iPhoneSimulator {F9F6FA20-0DBC-446B-BFC4-B0190D530F18}.Release|iPhone.ActiveCfg = Release|iPhone {F9F6FA20-0DBC-446B-BFC4-B0190D530F18}.Release|iPhone.Build.0 = Release|iPhone {F9F6FA20-0DBC-446B-BFC4-B0190D530F18}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator {F9F6FA20-0DBC-446B-BFC4-B0190D530F18}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator + {F9F6FA20-0DBC-446B-BFC4-B0190D530F18}.Release|Mixed Platforms.ActiveCfg = Release|iPhone + {F9F6FA20-0DBC-446B-BFC4-B0190D530F18}.Release|Mixed Platforms.Build.0 = Release|iPhone + {86B4F178-F272-4404-8CF5-140A5A84CBC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86B4F178-F272-4404-8CF5-140A5A84CBC2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86B4F178-F272-4404-8CF5-140A5A84CBC2}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {86B4F178-F272-4404-8CF5-140A5A84CBC2}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {86B4F178-F272-4404-8CF5-140A5A84CBC2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {86B4F178-F272-4404-8CF5-140A5A84CBC2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {86B4F178-F272-4404-8CF5-140A5A84CBC2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86B4F178-F272-4404-8CF5-140A5A84CBC2}.Release|Any CPU.Build.0 = Release|Any CPU + {86B4F178-F272-4404-8CF5-140A5A84CBC2}.Release|iPhone.ActiveCfg = Release|Any CPU + {86B4F178-F272-4404-8CF5-140A5A84CBC2}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {86B4F178-F272-4404-8CF5-140A5A84CBC2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {86B4F178-F272-4404-8CF5-140A5A84CBC2}.Release|Mixed Platforms.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = MTSplitViewController\MTSplitViewController.csproj diff --git a/MTSplitViewController/AppDelegate.cs b/MTSplitViewController/AppDelegate.cs deleted file mode 100644 index a684f3f..0000000 --- a/MTSplitViewController/AppDelegate.cs +++ /dev/null @@ -1,64 +0,0 @@ -// MTSplitViewController -// https://github.com/Krumelur/MTSplitViewController -// -// Ported to Monotouch by René Ruppert, October 2011 -// -// Based on code by Matt Gemmell on 26/07/2010. -// Copyright 2010 Instinctive Code. -// https://github.com/mattgemmell/MGSplitViewController - -using MonoTouch.Foundation; -using MonoTouch.UIKit; -using MTSplitViewLib; - -namespace MTSplitViewControllerDemo -{ - // The UIApplicationDelegate for the application. This class is responsible for launching the - // User Interface of the application, as well as listening (and optionally responding) to - // application events from iOS. - [Register ("AppDelegate")] - public partial class AppDelegate : UIApplicationDelegate - { - // class-level declarations - UIWindow window; - - MTSplitViewController oSplitViewController; - RootViewController oMasterController; - DetailViewController oDetailController; - UINavigationController oNavController; - public override bool FinishedLaunching (UIApplication app, NSDictionary options) - { - // create a new window instance based on the screen size - window = new UIWindow (UIScreen.MainScreen.Bounds); - - this.oSplitViewController = new MTSplitViewController (); - - this.oMasterController = new RootViewController(); - this.oDetailController = new DetailViewController(this.oSplitViewController); - this.oMasterController.DetailViewController = this.oDetailController; - this.oNavController = new UINavigationController(this.oMasterController); - - - this.oSplitViewController.ViewControllers = new UIViewController[] {this.oNavController, this.oDetailController }; - this.oSplitViewController.ShowsMasterInLandscape = true; - this.oSplitViewController.ShowsMasterInPortrait = true; - window.AddSubview(this.oSplitViewController.View); - - window.MakeKeyAndVisible (); - - if (false) - { - // whether to allow dragging the divider to move the split. - this.oSplitViewController.SplitWidth = 15.0f; // make it wide enough to actually drag! - this.oSplitViewController.AllowsDraggingDivider = true; - } - - this.oMasterController.SelectFirstRow(); - this.oDetailController.ConfigureView(); - - - return true; - } - } -} - diff --git a/MTSplitViewController/DetailViewController.cs b/MTSplitViewController/DetailViewController.cs deleted file mode 100644 index 17a5d87..0000000 --- a/MTSplitViewController/DetailViewController.cs +++ /dev/null @@ -1,160 +0,0 @@ -// MTSplitViewController -// https://github.com/Krumelur/MTSplitViewController -// -// Ported to Monotouch by René Ruppert, October 2011 -// -// Based on code by Matt Gemmell on 26/07/2010. -// Copyright 2010 Instinctive Code. -// https://github.com/mattgemmell/MGSplitViewController - -using System; -using System.Collections.Generic; -using System.Drawing; -using MonoTouch.UIKit; -using MTSplitViewLib; - -namespace MTSplitViewControllerDemo -{ - public class DetailViewController : UIViewController - { - public DetailViewController (MTSplitViewController oSplitViewController) : base() - { - this.oSplitViewController = oSplitViewController; - } - - public override void LoadView () - { - base.LoadView (); - this.View.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight; - this.View.BackgroundColor = UIColor.White; - this.oSplitViewController.WillHideViewController += HandleWillHideViewController; - this.oSplitViewController.WillShowViewController += HandleWillShowViewController; - this.oSplitViewController.WillPresentViewController += HandleWillPresentViewController; - this.oSplitViewController.WillChangeSplitOrientationToVertical += HandleWillChangeSplitOrientationToVertical; - this.oSplitViewController.WillMoveSplitToPosition += HandleWillMoveSplitToPosition; - this.oSplitViewController.ConstrainSplitPosition += HandleConstrainSplitPosition; - } - - public override void ViewWillAppear (bool animated) - { - base.ViewWillAppear (animated); - this.oToolbar = new UIToolbar (new RectangleF (0, 0, this.View.Bounds.Width, 44)); - this.oToolbar.AutoresizingMask = UIViewAutoresizing.FlexibleWidth; - this.View.AddSubview (this.oToolbar); - - this.oDetailDescriptionLabel = new UILabel (new RectangleF (0, 0, this.View.Bounds.Width, 30)); - this.oDetailDescriptionLabel.TextAlignment = UITextAlignment.Center; - this.oDetailDescriptionLabel.Center = new PointF (this.View.Bounds.Width / 2, this.View.Bounds.Height / 2); - Console.WriteLine(this.View.Bounds + "; " + this.oDetailDescriptionLabel.Center); - this.oDetailDescriptionLabel.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleRightMargin | UIViewAutoresizing.FlexibleLeftMargin; - this.View.AddSubview (this.oDetailDescriptionLabel); - - this.oToggleItem = new UIBarButtonItem ("Show", UIBarButtonItemStyle.Bordered, delegate(object sender, EventArgs e) { - this.oSplitViewController.ToggleMasterView (); - this.ConfigureView (); - }); - - this.oVerticalItem = new UIBarButtonItem ("Horizontal", UIBarButtonItemStyle.Bordered, delegate(object sender, EventArgs e) { - this.oSplitViewController.ToggleSplitOrientation (); - this.ConfigureView (); - }); - - this.oDividerStyleItem = new UIBarButtonItem ("Dragging", UIBarButtonItemStyle.Bordered, delegate(object sender, EventArgs e) { - MTSplitDividerView.DIVIDER_STYLE eNewStyle = this.oSplitViewController.DividerStyle == MTSplitDividerView.DIVIDER_STYLE.Thin ? MTSplitDividerView.DIVIDER_STYLE.PaneSplitter : MTSplitDividerView.DIVIDER_STYLE.Thin; - this.oSplitViewController.SetDividerStyleAnimated (eNewStyle); - this.ConfigureView (); - }); - - this.oMasterBeforeDetailItem = new UIBarButtonItem ("Detail First", UIBarButtonItemStyle.Bordered, delegate(object sender, EventArgs e) { - this.oSplitViewController.ToggleMasterBeforeDetail (); - this.ConfigureView (); - }); - - this.oToolbar.SetItems (new UIBarButtonItem[] {this.oToggleItem, this.oVerticalItem, this.oDividerStyleItem, this.oMasterBeforeDetailItem }, false); - } - - private void HandleWillHideViewController (MTSplitViewController oSplitController, UIViewController oMasterControler, UIBarButtonItem oBarBtnItm, UIPopoverController oPopover) - { - Console.WriteLine("WillHideViewController()"); - if (oBarBtnItm!= null) - { - oBarBtnItm.Title = "Popover"; - List aItems = new List(this.oToolbar.Items); - aItems.Insert(0, oBarBtnItm); - this.oToolbar.SetItems(aItems.ToArray(), true); - } - this.oPopoverController = oPopover; - } - - private float HandleConstrainSplitPosition (MTSplitViewController oSplitController, float fProposedPosition, SizeF oViewSize) - { - Console.WriteLine("ConstrainSplitPosition(): " + fProposedPosition); - return fProposedPosition; - } - - private void HandleWillMoveSplitToPosition (MTSplitViewController oSplitControler, float fSplitPos) - { - Console.WriteLine("WillMoveSplitToPosition(): " + fSplitPos); - } - - private void HandleWillChangeSplitOrientationToVertical (MTSplitViewController oSplitController, bool bIsVertical) - { - Console.WriteLine("WillChangeSplitOrientationToVertical(): " + bIsVertical); - } - - private void HandleWillPresentViewController (MTSplitViewController oSplitController, UIPopoverController oPopoverController, UIViewController oMasterController) - { - Console.WriteLine("WillPresentViewController()"); - } - - private void HandleWillShowViewController (MTSplitViewController oSplitController, UIViewController oMasterController, UIBarButtonItem oBarBtnItm) - { - Console.WriteLine("WillShowViewController()"); - if (oBarBtnItm != null) - { - List aItems = new List(this.oToolbar.Items); - aItems.Remove(oBarBtnItm); - this.oToolbar.SetItems(aItems.ToArray(), true); - } - this.oPopoverController = null; - } - - public string DetailItem - { - get - { - return this.sDetailitem; - } - set - { - this.sDetailitem = value; - this.ConfigureView(); - if(this.oPopoverController != null) - { - this.oPopoverController.Dismiss(true); - } - } - } - private string sDetailitem; - - private MTSplitViewController oSplitViewController; - private UIBarButtonItem oToggleItem; - private UIBarButtonItem oVerticalItem; - private UIBarButtonItem oDividerStyleItem; - private UIBarButtonItem oMasterBeforeDetailItem; - private UIPopoverController oPopoverController; - private UILabel oDetailDescriptionLabel; - private UIToolbar oToolbar; - - public void ConfigureView() - { - // Update the user interface for the detail item. - this.oDetailDescriptionLabel.Text = this.sDetailitem; - this.oToggleItem.Title = this.oSplitViewController.IsShowingMaster ? "Hide Master" : "Show Master"; - this.oVerticalItem.Title = this.oSplitViewController.IsVertical ? "Horizontal Split" : "Vertical Split"; - this.oDividerStyleItem.Title = this.oSplitViewController.DividerStyle.ToString(); - this.oMasterBeforeDetailItem.Title = this.oSplitViewController.MasterBeforeDetail ? "Detail First" : "Master First"; - } - } -} - diff --git a/MTSplitViewController/RootViewController.cs b/MTSplitViewController/RootViewController.cs deleted file mode 100644 index 6ae53e7..0000000 --- a/MTSplitViewController/RootViewController.cs +++ /dev/null @@ -1,89 +0,0 @@ -// MTSplitViewController -// https://github.com/Krumelur/MTSplitViewController -// -// Ported to Monotouch by René Ruppert, October 2011 -// -// Based on code by Matt Gemmell on 26/07/2010. -// Copyright 2010 Instinctive Code. -// https://github.com/mattgemmell/MGSplitViewController - -using System.Drawing; -using MonoTouch.Foundation; -using MonoTouch.UIKit; - -namespace MTSplitViewControllerDemo -{ - public class RootViewController : UITableViewController - { - public RootViewController () : base() - { - } - - public RootViewController (UITableViewStyle withStyle) : base(withStyle) - { - } - - public DetailViewController DetailViewController; - - public override void ViewDidLoad () - { - base.ViewDidLoad (); - this.ClearsSelectionOnViewWillAppear = false; - this.ContentSizeForViewInPopover = new SizeF(320f, 600f); - this.TableView.Source = new Source(this); - } - - public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation) - { - return true; - } - - public void SelectFirstRow() - { - if(this.TableView.NumberOfSections() > 0 && this.TableView.NumberOfRowsInSection(0) > 0) - { - NSIndexPath oIndexPath = NSIndexPath.FromRowSection(0, 0); - this.TableView.SelectRow(oIndexPath, true, UITableViewScrollPosition.Top); - ((Source)(this.TableView.Source)).RowSelected(this.TableView, oIndexPath); - } - } - - public class Source : UITableViewSource - { - public Source(RootViewController oController) - { - this.oController = oController; - } - private RootViewController oController; - - public override int NumberOfSections (UITableView tableView) - { - return 1; - } - - public override int RowsInSection (UITableView tableview, int section) - { - return 10; - } - - public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath) - { - string sCellID = "CellID"; - UITableViewCell oCell = tableView.DequeueReusableCell(sCellID); - if(oCell == null) - { - oCell = new UITableViewCell(UITableViewCellStyle.Default, sCellID); - oCell.Accessory = UITableViewCellAccessory.None; - } - oCell.TextLabel.Text = "Row " + indexPath.Row; - return oCell; - } - - public override void RowSelected (UITableView tableView, NSIndexPath indexPath) - { - this.oController.DetailViewController.DetailItem = "Row " + indexPath.Row; - } - } - } -} - diff --git a/MTSplitViewControllerDemo/AppDelegate.cs b/MTSplitViewControllerDemo/AppDelegate.cs new file mode 100644 index 0000000..177d45e --- /dev/null +++ b/MTSplitViewControllerDemo/AppDelegate.cs @@ -0,0 +1,52 @@ +// MTSplitViewController +// https://github.com/Krumelur/MTSplitViewController +// +// Ported to Monotouch by René Ruppert, October 2011 +// Ported to Xamarin.iOS by infoMantis GmbH, April 2015 +// +// Based on code by Matt Gemmell on 26/07/2010. +// Copyright 2010 Instinctive Code. +// https://github.com/mattgemmell/MGSplitViewController + +using Foundation; +using MTSplitViewLib; +using UIKit; + +namespace MTSplitViewControllerDemo +{ + [Register("AppDelegate")] + public class AppDelegate : UIApplicationDelegate + { + private UIWindow _window; + private MTSplitViewController _splitViewController; + private RootViewController _masterController; + private DetailViewController _detailController; + private UINavigationController _navController; + + public override bool FinishedLaunching(UIApplication app, NSDictionary options) + { + // create a new window instance based on the screen size + _window = new UIWindow(UIScreen.MainScreen.Bounds); + + _splitViewController = new MTSplitViewController(); + + _masterController = new RootViewController(); + _detailController = new DetailViewController(_splitViewController); + _masterController.DetailViewController = _detailController; + _navController = new UINavigationController(_masterController); + + + _splitViewController.ViewControllers = new UIViewController[] {_navController, _detailController}; + _splitViewController.ShowsMasterInLandscape = true; + _splitViewController.ShowsMasterInPortrait = true; + _window.AddSubview(_splitViewController.View); + + _window.MakeKeyAndVisible(); + + _masterController.SelectFirstRow(); + _detailController.ConfigureView(); + + return true; + } + } +} diff --git a/MTSplitViewControllerDemo/DetailViewController.cs b/MTSplitViewControllerDemo/DetailViewController.cs new file mode 100644 index 0000000..228ab17 --- /dev/null +++ b/MTSplitViewControllerDemo/DetailViewController.cs @@ -0,0 +1,174 @@ +// MTSplitViewController +// https://github.com/Krumelur/MTSplitViewController +// +// Ported to Monotouch by René Ruppert, October 2011 +// Ported to Xamarin.iOS by infoMantis GmbH, April 2015 +// +// Based on code by Matt Gemmell on 26/07/2010. +// Copyright 2010 Instinctive Code. +// https://github.com/mattgemmell/MGSplitViewController + +using CoreGraphics; +using MTSplitViewLib; +using System; +using System.Collections.Generic; +using UIKit; + +namespace MTSplitViewControllerDemo +{ + public class DetailViewController : UIViewController + { + private readonly MTSplitViewController _splitViewController; + private string _detailitem; + private UIBarButtonItem _toggleItem; + private UIBarButtonItem _verticalItem; + private UIBarButtonItem _dividerStyleItem; + private UIBarButtonItem _masterBeforeDetailItem; + private UIPopoverController _popoverController; + private UILabel _detailDescriptionLabel; + private UIToolbar _toolbar; + + public DetailViewController(MTSplitViewController splitViewController) + { + _splitViewController = splitViewController; + } + + public override void LoadView() + { + base.LoadView(); + View.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight; + View.BackgroundColor = UIColor.White; + _splitViewController.WillHideViewController += HandleWillHideViewController; + _splitViewController.WillShowViewController += HandleWillShowViewController; + _splitViewController.WillPresentViewController += HandleWillPresentViewController; + _splitViewController.WillChangeSplitOrientationToVertical += HandleWillChangeSplitOrientationToVertical; + _splitViewController.WillMoveSplitToPosition += HandleWillMoveSplitToPosition; + _splitViewController.ConstrainSplitPosition += HandleConstrainSplitPosition; + } + + public override void ViewWillAppear(bool animated) + { + base.ViewWillAppear(animated); + _toolbar = new UIToolbar(new CGRect(0, 0, View.Bounds.Width, 44)) + { + AutoresizingMask = UIViewAutoresizing.FlexibleWidth + }; + View.AddSubview(_toolbar); + + _detailDescriptionLabel = new UILabel(new CGRect(0, 0, View.Bounds.Width, 30)) + { + TextAlignment = UITextAlignment.Center, + Center = new CGPoint(View.Bounds.Width/2, View.Bounds.Height/2) + }; + Console.WriteLine(View.Bounds + "; " + _detailDescriptionLabel.Center); + _detailDescriptionLabel.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleRightMargin | UIViewAutoresizing.FlexibleLeftMargin; + View.AddSubview(_detailDescriptionLabel); + + _toggleItem = new UIBarButtonItem("Show", UIBarButtonItemStyle.Bordered, delegate + { + _splitViewController.ToggleMasterView(); + ConfigureView(); + }); + + _verticalItem = new UIBarButtonItem("Horizontal", UIBarButtonItemStyle.Bordered, delegate + { + _splitViewController.ToggleSplitOrientation(); + ConfigureView(); + }); + + _dividerStyleItem = new UIBarButtonItem("Dragging", UIBarButtonItemStyle.Bordered, delegate + { + var eNewStyle = _splitViewController.DividerStyle == MTSplitDividerView.DividerStyle.Thin + ? MTSplitDividerView.DividerStyle.PaneSplitter + : MTSplitDividerView.DividerStyle.Thin; + _splitViewController.SetDividerStyleAnimated(eNewStyle); + ConfigureView(); + }); + + _masterBeforeDetailItem = new UIBarButtonItem("Detail First", UIBarButtonItemStyle.Bordered, delegate + { + _splitViewController.ToggleMasterBeforeDetail(); + ConfigureView(); + }); + + _toolbar.SetItems(new[] {_toggleItem, _verticalItem, _dividerStyleItem, _masterBeforeDetailItem}, false); + } + + private void HandleWillHideViewController( + MTSplitViewController oSplitController, + UIViewController oMasterControler, + UIBarButtonItem oBarBtnItm, + UIPopoverController oPopover) + { + Console.WriteLine("WillHideViewController()"); + if (oBarBtnItm != null) + { + oBarBtnItm.Title = "Popover"; + var aItems = new List(_toolbar.Items); + aItems.Insert(0, oBarBtnItm); + _toolbar.SetItems(aItems.ToArray(), true); + } + _popoverController = oPopover; + } + + private nfloat HandleConstrainSplitPosition(MTSplitViewController oSplitController, nfloat fProposedPosition, CGSize oViewSize) + { + Console.WriteLine("ConstrainSplitPosition(): " + fProposedPosition); + return fProposedPosition; + } + + private void HandleWillMoveSplitToPosition(MTSplitViewController oSplitControler, nfloat fSplitPos) + { + Console.WriteLine("WillMoveSplitToPosition(): " + fSplitPos); + } + + private void HandleWillChangeSplitOrientationToVertical(MTSplitViewController oSplitController, bool bIsVertical) + { + Console.WriteLine("WillChangeSplitOrientationToVertical(): " + bIsVertical); + } + + private void HandleWillPresentViewController( + MTSplitViewController oSplitController, + UIPopoverController oPopoverController, + UIViewController oMasterController) + { + Console.WriteLine("WillPresentViewController()"); + } + + private void HandleWillShowViewController(MTSplitViewController oSplitController, UIViewController oMasterController, UIBarButtonItem oBarBtnItm) + { + Console.WriteLine("WillShowViewController()"); + if (oBarBtnItm != null) + { + var aItems = new List(_toolbar.Items); + aItems.Remove(oBarBtnItm); + _toolbar.SetItems(aItems.ToArray(), true); + } + _popoverController = null; + } + + public string DetailItem + { + get { return _detailitem; } + set + { + _detailitem = value; + ConfigureView(); + if (_popoverController != null) + { + _popoverController.Dismiss(true); + } + } + } + + public void ConfigureView() + { + // Update the user interface for the detail item. + _detailDescriptionLabel.Text = _detailitem; + _toggleItem.Title = _splitViewController.IsShowingMaster ? "Hide Master" : "Show Master"; + _verticalItem.Title = _splitViewController.IsVertical ? "Horizontal Split" : "Vertical Split"; + _dividerStyleItem.Title = _splitViewController.DividerStyle.ToString(); + _masterBeforeDetailItem.Title = _splitViewController.MasterBeforeDetail ? "Detail First" : "Master First"; + } + } +} diff --git a/MTSplitViewController/Info.plist b/MTSplitViewControllerDemo/Info.plist similarity index 97% rename from MTSplitViewController/Info.plist rename to MTSplitViewControllerDemo/Info.plist index de97952..940db57 100644 --- a/MTSplitViewController/Info.plist +++ b/MTSplitViewControllerDemo/Info.plist @@ -3,7 +3,7 @@ MinimumOSVersion - 4.3 + 5.1.1 UIDeviceFamily 2 diff --git a/MTSplitViewController/MTSplitViewController.csproj b/MTSplitViewControllerDemo/MTSplitViewControllerDemo.csproj similarity index 79% rename from MTSplitViewController/MTSplitViewController.csproj rename to MTSplitViewControllerDemo/MTSplitViewControllerDemo.csproj index 3251fff..01a1e7b 100644 --- a/MTSplitViewController/MTSplitViewController.csproj +++ b/MTSplitViewControllerDemo/MTSplitViewControllerDemo.csproj @@ -1,4 +1,4 @@ - + Debug @@ -6,10 +6,11 @@ 10.0.0 2.0 {F9F6FA20-0DBC-446B-BFC4-B0190D530F18} - {6BC8ED88-2882-458C-8E55-DFD12B67127B};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} Exe - MTSplitViewController - MTSplitViewController + MTSplitViewControllerDemo + MTSplitViewControllerDemo + Xamarin.iOS true @@ -44,6 +45,7 @@ true iPhone Developer + ARMv7 none @@ -53,12 +55,13 @@ 4 false iPhone Developer + ARMv7, ARM64 - + @@ -69,11 +72,13 @@ - - - {86B4F178-F272-4404-8CF5-140A5A84CBC2} + + {86b4f178-f272-4404-8cf5-140a5a84cbc2} MTSplitViewLib + false + false + \ No newline at end of file diff --git a/MTSplitViewController/Main.cs b/MTSplitViewControllerDemo/Main.cs similarity index 56% rename from MTSplitViewController/Main.cs rename to MTSplitViewControllerDemo/Main.cs index 81a33d2..49a6429 100644 --- a/MTSplitViewController/Main.cs +++ b/MTSplitViewControllerDemo/Main.cs @@ -2,23 +2,21 @@ // https://github.com/Krumelur/MTSplitViewController // // Ported to Monotouch by René Ruppert, October 2011 +// Ported to Xamarin.iOS by infoMantis GmbH, April 2015 // // Based on code by Matt Gemmell on 26/07/2010. // Copyright 2010 Instinctive Code. // https://github.com/mattgemmell/MGSplitViewController -using MonoTouch.UIKit; +using UIKit; namespace MTSplitViewControllerDemo { public class Application { - // This is the main entry point of the application. - static void Main (string[] args) + public static void Main(string[] args) { - // if you want to use a different Application Delegate class from "AppDelegate" - // you can specify it here. - UIApplication.Main (args, null, "AppDelegate"); + UIApplication.Main(args, null, typeof (AppDelegate).Name); } } } diff --git a/MTSplitViewControllerDemo/RootViewController.cs b/MTSplitViewControllerDemo/RootViewController.cs new file mode 100644 index 0000000..8146b93 --- /dev/null +++ b/MTSplitViewControllerDemo/RootViewController.cs @@ -0,0 +1,86 @@ +// MTSplitViewController +// https://github.com/Krumelur/MTSplitViewController +// +// Ported to Monotouch by René Ruppert, October 2011 +// Ported to Xamarin.iOS by infoMantis GmbH, April 2015 +// +// Based on code by Matt Gemmell on 26/07/2010. +// Copyright 2010 Instinctive Code. +// https://github.com/mattgemmell/MGSplitViewController + +using CoreGraphics; +using Foundation; +using System; +using UIKit; + +namespace MTSplitViewControllerDemo +{ + public class RootViewController : UITableViewController + { + public DetailViewController DetailViewController { get; set; } + + public override void ViewDidLoad() + { + base.ViewDidLoad(); + ClearsSelectionOnViewWillAppear = false; + ContentSizeForViewInPopover = new CGSize(320f, 600f); + TableView.Source = new RowTableViewSource(this); + } + + public override bool ShouldAutorotateToInterfaceOrientation(UIInterfaceOrientation toInterfaceOrientation) + { + return true; + } + + public void SelectFirstRow() + { + if (TableView.NumberOfSections() > 0 && TableView.NumberOfRowsInSection(0) > 0) + { + var oIndexPath = NSIndexPath.FromRowSection(0, 0); + TableView.SelectRow(oIndexPath, true, UITableViewScrollPosition.Top); + TableView.Source.RowSelected(TableView, oIndexPath); + } + } + + private class RowTableViewSource : UITableViewSource + { + private const string CellId = "CellID"; + + public RowTableViewSource(RootViewController controller) + { + _controller = controller; + } + + private readonly RootViewController _controller; + + public override nint NumberOfSections(UITableView tableView) + { + return 1; + } + + public override nint RowsInSection(UITableView tableview, nint section) + { + return 10; + } + + public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath) + { + var cell = tableView.DequeueReusableCell(CellId); + if (cell == null) + { + cell = new UITableViewCell(UITableViewCellStyle.Default, CellId) + { + Accessory = UITableViewCellAccessory.None + }; + } + cell.TextLabel.Text = "Row " + indexPath.Row; + return cell; + } + + public override void RowSelected(UITableView tableView, NSIndexPath indexPath) + { + _controller.DetailViewController.DetailItem = "Row " + indexPath.Row; + } + } + } +} diff --git a/MTSplitViewLib/MTSplitCornersView.cs b/MTSplitViewLib/MTSplitCornersView.cs new file mode 100644 index 0000000..a132241 --- /dev/null +++ b/MTSplitViewLib/MTSplitCornersView.cs @@ -0,0 +1,245 @@ +// MTSplitViewController +// https://github.com/Krumelur/MTSplitViewController +// +// Ported to Monotouch by René Ruppert, October 2011 +// Ported to Xamarin.iOS by infoMantis GmbH, April 2015 +// +// Based on code by Matt Gemmell on 26/07/2010. +// Copyright 2010 Instinctive Code. +// https://github.com/mattgemmell/MGSplitViewController + +using System; +using CoreGraphics; +using Foundation; +using UIKit; + +namespace MTSplitViewLib +{ + public class MTSplitCornersView : UIView + { + public enum CornersPosition + { + LeadingVertical = 0, // top of screen for a left/right split. + TrailingVertical = 1, // bottom of screen for a left/right split. + LeadingHorizontal = 2, // left of screen for a top/bottom split. + TrailingHorizontal = 3 // right of screen for a top/bottom split. + } + + public MTSplitCornersView() : base() + { + } + + public MTSplitCornersView(NSCoder coder) : base(coder) + { + } + + public MTSplitCornersView(NSObjectFlag t) : base(t) + { + } + + public MTSplitCornersView(IntPtr handle) : base(handle) + { + } + + public MTSplitCornersView(CGRect frame) : base(frame) + { + ContentMode = UIViewContentMode.Redraw; + UserInteractionEnabled = false; + Opaque = false; + BackgroundColor = UIColor.Clear; + CornerRadius = 0.0f; // actual value is set by the splitViewController. + Position = CornersPosition.LeadingVertical; + } + + private nfloat Deg2Rad(nfloat fDegrees) + { + // Converts degrees to radians. + return fDegrees*((nfloat) Math.PI/180.0f); + } + + + private nfloat Rad2Deg(nfloat fRadians) + { + // Converts radians to degrees. + return fRadians*(180f/(float) Math.PI); + } + + public override void Draw(CGRect rect) + { + // Draw two appropriate corners, with cornerBackgroundColor behind them. + if (CornerRadius < 0) + { + return; + } + + var maxX = Bounds.GetMaxX(); + var maxY = Bounds.GetMaxY(); + var path = new UIBezierPath(); + var pt = CGPoint.Empty; + switch (Position) + { + case CornersPosition.LeadingVertical: // top of screen for a left/right split + path.MoveTo(pt); + pt.Y += CornerRadius; + path.AppendPath(UIBezierPath.FromArc(pt, CornerRadius, Deg2Rad(90), 0f, true)); + pt.X += CornerRadius; + pt.Y -= CornerRadius; + path.AddLineTo(pt); + path.AddLineTo(CGPoint.Empty); + path.ClosePath(); + + pt.X = maxX - CornerRadius; + pt.Y = 0; + path.MoveTo(pt); + pt.Y = maxY; + path.AddLineTo(pt); + pt.X += CornerRadius; + path.AppendPath(UIBezierPath.FromArc(pt, CornerRadius, Deg2Rad(180f), Deg2Rad(90), true)); + pt.Y -= CornerRadius; + path.AddLineTo(pt); + pt.X -= CornerRadius; + path.AddLineTo(pt); + path.ClosePath(); + break; + + case CornersPosition.TrailingVertical: // bottom of screen for a left/right split + pt.Y = maxY; + path.MoveTo(pt); + pt.Y -= CornerRadius; + path.AppendPath(UIBezierPath.FromArc(pt, CornerRadius, Deg2Rad(270f), Deg2Rad(360), false)); + pt.X += CornerRadius; + pt.Y += CornerRadius; + path.AddLineTo(pt); + pt.X -= CornerRadius; + path.AddLineTo(pt); + path.ClosePath(); + + pt.X = maxX - CornerRadius; + pt.Y = maxY; + path.MoveTo(pt); + pt.Y -= CornerRadius; + path.AddLineTo(pt); + pt.X += CornerRadius; + path.AppendPath(UIBezierPath.FromArc(pt, CornerRadius, Deg2Rad(180f), Deg2Rad(270f), false)); + pt.Y += CornerRadius; + path.AddLineTo(pt); + pt.X -= CornerRadius; + path.AddLineTo(pt); + path.ClosePath(); + break; + + case CornersPosition.LeadingHorizontal: // left of screen for a top/bottom split + pt.X = 0; + pt.Y = CornerRadius; + path.MoveTo(pt); + pt.Y -= CornerRadius; + path.AddLineTo(pt); + pt.X += CornerRadius; + path.AppendPath(UIBezierPath.FromArc(pt, CornerRadius, Deg2Rad(180), Deg2Rad(270), false)); + pt.Y += CornerRadius; + path.AddLineTo(pt); + pt.X -= CornerRadius; + path.AddLineTo(pt); + path.ClosePath(); + + pt.X = 0; + pt.Y = maxY - CornerRadius; + path.MoveTo(pt); + pt.Y = maxY; + path.AddLineTo(pt); + pt.X += CornerRadius; + path.AppendPath(UIBezierPath.FromArc(pt, CornerRadius, Deg2Rad(180f), Deg2Rad(90f), true)); + pt.Y -= CornerRadius; + path.AddLineTo(pt); + pt.X -= CornerRadius; + path.AddLineTo(pt); + path.ClosePath(); + break; + + case CornersPosition.TrailingHorizontal: // right of screen for a top/bottom split + pt.Y = CornerRadius; + path.MoveTo(pt); + pt.Y -= CornerRadius; + path.AppendPath(UIBezierPath.FromArc(pt, CornerRadius, Deg2Rad(270f), Deg2Rad(360f), false)); + pt.X += CornerRadius; + pt.Y += CornerRadius; + path.AddLineTo(pt); + pt.X -= CornerRadius; + path.AddLineTo(pt); + path.ClosePath(); + + pt.Y = maxY - CornerRadius; + path.MoveTo(pt); + pt.Y += CornerRadius; + path.AppendPath(UIBezierPath.FromArc(pt, CornerRadius, Deg2Rad(90), 0f, true)); + pt.X += CornerRadius; + pt.Y -= CornerRadius; + path.AddLineTo(pt); + pt.X -= CornerRadius; + path.AddLineTo(pt); + path.ClosePath(); + break; + } + + CornerBackgroundColor.SetFill(); + CornerBackgroundColor.SetStroke(); + path.Fill(); + } + + public nfloat CornerRadius + { + get { return _cornerRadius; } + set + { + if (value != _cornerRadius) + { + _cornerRadius = value; + SetNeedsDisplay(); + } + } + } + private nfloat _cornerRadius; + + public MTSplitViewController SplitViewController + { + get { return _splitViewController; } + set + { + if (_splitViewController != value) + { + _splitViewController = value; + SetNeedsDisplay(); + } + } + } + private MTSplitViewController _splitViewController; + + public CornersPosition Position + { + get { return _position; } + set + { + if (_position != value) + { + _position = value; + SetNeedsDisplay(); + } + } + } + private CornersPosition _position; + + public UIColor CornerBackgroundColor + { + get { return _cornerBackgroundColor; } + set + { + if (_cornerBackgroundColor != value) + { + _cornerBackgroundColor = value; + SetNeedsDisplay(); + } + } + } + private UIColor _cornerBackgroundColor; + } +} diff --git a/MTSplitViewLib/MTSplitDividerView.cs b/MTSplitViewLib/MTSplitDividerView.cs new file mode 100644 index 0000000..050eb70 --- /dev/null +++ b/MTSplitViewLib/MTSplitDividerView.cs @@ -0,0 +1,245 @@ +// MTSplitViewController +// https://github.com/Krumelur/MTSplitViewController +// +// Ported to Monotouch by René Ruppert, October 2011 +// Ported to Xamarin.iOS by infoMantis GmbH, April 2015 +// +// Based on code by Matt Gemmell on 26/07/2010. +// Copyright 2010 Instinctive Code. +// https://github.com/mattgemmell/MGSplitViewController + +using System; +using CoreGraphics; +using Foundation; +using UIKit; + +namespace MTSplitViewLib +{ + public class MTSplitDividerView : UIView + { + public enum DividerStyle + { + Thin = 0, // Thin divider, like UISplitViewController (default). + PaneSplitter = 1 // Thick divider, drawn with a grey gradient and a grab-strip. + } + + public MTSplitDividerView() : base() + { + } + + public MTSplitDividerView(NSCoder coder) : base(coder) + { + } + + public MTSplitDividerView(NSObjectFlag t) : base(t) + { + } + + public MTSplitDividerView(IntPtr handle) : base(handle) + { + } + + public MTSplitDividerView(CGRect frame) : base(frame) + { + UserInteractionEnabled = false; + AllowsDragging = false; + ContentMode = UIViewContentMode.Redraw; + } + + public override void Draw(CGRect rect) + { + if (SplitViewController.DividerStyle == DividerStyle.Thin) + { + base.Draw(rect); + } + else if (SplitViewController.DividerStyle == DividerStyle.PaneSplitter) + { + // Draw gradient background. + var bounds = Bounds; + var rgb = CGColorSpace.CreateDeviceRGB(); + var locations = new nfloat[] {0, 1}; + var components = new nfloat[] + { + // light + 0.988f, 0.988f, 0.988f, 1.0f, + // dark + 0.875f, 0.875f, 0.875f, 1.0f + }; + var gradient = new CGGradient(rgb, components, locations); + var context = UIGraphics.GetCurrentContext(); + CGPoint start; + CGPoint end; + if (SplitViewController.IsVertical) + { + // Light left to dark right. + start = new CGPoint(bounds.GetMinX(), bounds.GetMidY()); + end = new CGPoint(bounds.GetMaxX(), bounds.GetMidY()); + } + else + { + // Light top to dark bottom. + start = new CGPoint(bounds.GetMidX(), bounds.GetMinY()); + end = new CGPoint(bounds.GetMidX(), bounds.GetMaxY()); + } + context.DrawLinearGradient(gradient, start, end, CGGradientDrawingOptions.DrawsAfterEndLocation); + rgb.Dispose(); + gradient.Dispose(); + + // Draw borders. + var borderThickness = 1.0f; + UIColor.FromWhiteAlpha(0.7f, 1.0f).SetFill(); + UIColor.FromWhiteAlpha(0.7f, 1.0f).SetStroke(); + var borderRect = bounds; + if (SplitViewController.IsVertical) + { + borderRect.Width = borderThickness; + UIGraphics.RectFill(borderRect); + borderRect.X = bounds.GetMaxX() - borderThickness; + UIGraphics.RectFill(borderRect); + } + else + { + borderRect.Height = borderThickness; + UIGraphics.RectFill(borderRect); + borderRect.Y = bounds.GetMaxY() - borderThickness; + UIGraphics.RectFill(borderRect); + } + + // Draw grip. + DrawGripThumbInRect(bounds); + } + } + + private void DrawGripThumbInRect(CGRect rect) + { + nfloat width = 9.0f; + nfloat height; + if (SplitViewController.IsVertical) + { + height = 30.0f; + } + else + { + height = width; + width = 30.0f; + } + + // Draw grip in centred in rect. + var gripRect = new CGRect(0, 0, width, height); + gripRect.X = (rect.Width - gripRect.Width)/2.0f; + gripRect.Y = (rect.Height - gripRect.Height)/2.0f; + + nfloat stripThickness = 1.0f; + var stripColor = UIColor.FromWhiteAlpha(0.35f, 1.0f); + var lightColor = UIColor.FromWhiteAlpha(1.0f, 1.0f); + nfloat space = 3.0f; + if (SplitViewController.IsVertical) + { + gripRect.Width = stripThickness; + stripColor.SetFill(); + stripColor.SetStroke(); + UIGraphics.RectFill(gripRect); + + gripRect.X += stripThickness; + gripRect.Y += 1f; + lightColor.SetFill(); + lightColor.SetStroke(); + UIGraphics.RectFill(gripRect); + gripRect.X -= stripThickness; + gripRect.Y -= 1f; + + gripRect.X += space + stripThickness; + stripColor.SetFill(); + stripColor.SetStroke(); + UIGraphics.RectFill(gripRect); + + gripRect.X += stripThickness; + gripRect.Y += 1f; + lightColor.SetFill(); + lightColor.SetStroke(); + UIGraphics.RectFill(gripRect); + gripRect.X -= stripThickness; + gripRect.Y -= 1f; + + gripRect.X += space + stripThickness; + stripColor.SetFill(); + stripColor.SetStroke(); + UIGraphics.RectFill(gripRect); + + gripRect.X += stripThickness; + gripRect.Y += 1f; + lightColor.SetFill(); + lightColor.SetStroke(); + UIGraphics.RectFill(gripRect); + } + else + { + gripRect.Height = stripThickness; + stripColor.SetFill(); + stripColor.SetStroke(); + UIGraphics.RectFill(gripRect); + + gripRect.Y += stripThickness; + gripRect.X -= 1f; + lightColor.SetFill(); + lightColor.SetStroke(); + UIGraphics.RectFill(gripRect); + gripRect.Y -= stripThickness; + gripRect.X += 1f; + + gripRect.Y += space + stripThickness; + stripColor.SetFill(); + stripColor.SetStroke(); + UIGraphics.RectFill(gripRect); + + gripRect.Y += stripThickness; + gripRect.X -= 1f; + lightColor.SetFill(); + lightColor.SetStroke(); + UIGraphics.RectFill(gripRect); + gripRect.Y -= stripThickness; + gripRect.X += 1f; + + gripRect.Y += space + stripThickness; + stripColor.SetFill(); + stripColor.SetStroke(); + UIGraphics.RectFill(gripRect); + + gripRect.Y += stripThickness; + gripRect.X -= 1f; + lightColor.SetFill(); + lightColor.SetStroke(); + UIGraphics.RectFill(gripRect); + } + } + + public override void TouchesMoved(NSSet touches, UIEvent evt) + { + var touch = touches.AnyObject as UITouch; + if (touch == null) return; + + var lastPt = touch.PreviousLocationInView(this); + var pt = touch.LocationInView(this); + var offset = (SplitViewController.IsVertical) ? pt.X - lastPt.X : pt.Y - lastPt.Y; + if (!SplitViewController.MasterBeforeDetail) + { + offset = -offset; + } + SplitViewController.SplitPosition = SplitViewController.SplitPosition + offset; + } + + public virtual MTSplitViewLib.MTSplitViewController SplitViewController { get; set; } + + public virtual bool AllowsDragging + { + get { return _allowsDragging; } + set + { + _allowsDragging = value; + UserInteractionEnabled = value; + } + } + private bool _allowsDragging; + } + +} diff --git a/MTSplitViewLib/MTSplitViewController.cs b/MTSplitViewLib/MTSplitViewController.cs new file mode 100644 index 0000000..9549d28 --- /dev/null +++ b/MTSplitViewLib/MTSplitViewController.cs @@ -0,0 +1,1397 @@ +// MTSplitViewController +// https://github.com/Krumelur/MTSplitViewController +// +// Ported to Monotouch by René Ruppert, October 2011 +// Ported to Xamarin.iOS by infoMantis GmbH, April 2015 +// +// Based on code by Matt Gemmell on 26/07/2010. +// Copyright 2010 Instinctive Code. +// https://github.com/mattgemmell/MGSplitViewController + +using System; +using System.Diagnostics.CodeAnalysis; +using CoreGraphics; +using Foundation; +using UIKit; + +namespace MTSplitViewLib +{ + public class MTSplitViewController : UIViewController + { + // default width of master view in UISplitViewController. + private static readonly nfloat DefaultSplitPosition = 320.0f; + // default width of split-gutter in UISplitViewController. + private static readonly nfloat DefaultSplitWidth = 1.0f; + // default corner-radius of overlapping split-inner corners on the master and detail views. + private static readonly nfloat DefaultCornerRadius = 5.0f; + // default color of intruding inner corners (and divider background). + private static readonly UIColor DefaultCornerColor = UIColor.Black; + // corner-radius of split-inner corners for MGSplitViewDividerStylePaneSplitter style. + private static readonly nfloat PanesplitterCornerRadius = 0.0f; + // width of split-gutter for MGSplitViewDividerStylePaneSplitter style. + private static readonly nfloat PanesplitterSplitWidth = 25.0f; + // minimum width a view is allowed to become as a result of changing the splitPosition. + private static readonly nfloat MinViewWidth = 200.0f; + + public MTSplitViewController() + { + Setup(); + } + + public MTSplitViewController(NSCoder coder) : base(coder) + { + Setup(); + } + + public MTSplitViewController(NSObjectFlag t) : base(t) + { + Setup(); + } + + public MTSplitViewController(IntPtr handle) : base(handle) + { + Setup(); + } + + public MTSplitViewController(string nibName, NSBundle bundle) : base(nibName, bundle) + { + Setup(); + } + + /// + /// Will be triggered if the orientation of the panels changes. + /// + public event Action WillChangeSplitOrientationToVertical; + + /// + /// Will be triggered if the user wants to change the split position. + /// + public event Func ConstrainSplitPosition; + + /// + /// Will be triggered if the split position is moved. + /// + public event Action WillMoveSplitToPosition; + + /// + /// Will be triggered if the master view controller will be hidden. + /// + public event Action WillHideViewController; + + /// + /// Will be called if the master view controller will be shown. + /// + public event Action WillShowViewController; + + /// + /// Will be called if the master view controller will be shown in a popove. + /// + public event Action WillPresentViewController; + + // Indicates if the popover has to be reconfigured. + private bool _reconfigurePopup; + + /// + /// Gets or sets the hidden popover controller used to display the master view controller. + /// + public UIPopoverController HiddenPopoverController { get; set; } + + /// + /// If TRUE, the controller provides a popover and a bar button item for the master controller if the master is hidden. Default is TRUE. + /// + public bool AutoProvidePopoverAndBarItem = true; + + /// + /// Gets or sets the bar button item used to present the master view controller from. + /// + /// + /// The bar button item. + /// + public UIBarButtonItem BarButtonItem { get; set; } + + /// + /// Gets or sets a value indicating whether the master controller is shown in portrait mode. + /// master in portrait. + /// + /// + /// true if shows master in portrait; otherwise, false. + /// + public bool ShowsMasterInPortrait + { + get { return _showsMasterInPortrait; } + set + { + if (value == ShowsMasterInPortrait) return; + + _showsMasterInPortrait = value; + + if (IsLandscape) return; + + // i.e. if this will cause a visual change. + if (HiddenPopoverController != null && HiddenPopoverController.PopoverVisible) + { + HiddenPopoverController.Dismiss(false); + } + + // Rearrange views. + _reconfigurePopup = true; + LayoutSubviews(); + } + } + private bool _showsMasterInPortrait; + + /// + /// Gets or sets a value indicating whether the master controller is visible in landscape mode. + /// master in landscape. + /// + /// + /// true if shows master in landscape; otherwise, false. + /// + public bool ShowsMasterInLandscape + { + get { return _showsMasterInLandscape; } + set + { + _showsMasterInLandscape = value; + if (!IsLandscape) return; + + // i.e. if this will cause a visual change. + if (HiddenPopoverController != null && HiddenPopoverController.PopoverVisible) + { + HiddenPopoverController.Dismiss(false); + } + + // Rearrange views. + _reconfigurePopup = true; + LayoutSubviews(); + } + } + private bool _showsMasterInLandscape; + + /// + /// If FALSE, split is horizontal, i.e. master above detail. If TRUE, split is vertical, i.e. master left of detail. + /// + /// + /// true if this instance is vertical; otherwise, false. + /// + public bool IsVertical + { + get { return _isVertical; } + set + { + if (value == IsVertical) return; + + if (HiddenPopoverController != null && HiddenPopoverController.PopoverVisible) + { + HiddenPopoverController.Dismiss(false); + } + + _isVertical = value; + + // Inform delegate. + if (WillChangeSplitOrientationToVertical != null) + { + WillChangeSplitOrientationToVertical(this, _isVertical); + } + + LayoutSubviews(); + } + } + private bool _isVertical; + + /// + /// If FALSE, master view is below/right of detail. Otherwise master view is above/left of detail. + /// before detail. + /// + /// + /// true if master before detail; otherwise, false. + /// + public bool MasterBeforeDetail + { + get { return _masterBeforeDetail; } + set + { + if (value == MasterBeforeDetail) return; + + if (HiddenPopoverController != null && HiddenPopoverController.PopoverVisible) + { + HiddenPopoverController.Dismiss(false); + } + + _masterBeforeDetail = value; + + if (IsShowingMaster) + { + LayoutSubviews(); + } + } + } + private bool _masterBeforeDetail; + + /// + /// Starting position of split in units, relative to top/left (depending on IsVertical setting) if MasterBeforeDetail is TRUE, + /// else relative to bottom/right. + /// + /// + /// The split position. + /// + public nfloat SplitPosition + { + get { return _splitPosition; } + set + { + // Check to see if delegate wishes to constrain the position. + bool constrained; + var fullSize = SplitViewRectangleForOrientation(InterfaceOrientation).Size; + var newPos = value; + if (ConstrainSplitPosition != null) + { + newPos = ConstrainSplitPosition(this, value, fullSize); + constrained = true; // implicitly trust delegate's response. + } + else + { + // Apply default constraints if delegate doesn't wish to participate. + var minPos = MinViewWidth; + var maxPos = (IsVertical ? fullSize.Width : fullSize.Height) - (MinViewWidth + SplitWidth); + constrained = (newPos != SplitPosition && newPos >= minPos && newPos <= maxPos); + } + + if (!constrained) return; + + if (HiddenPopoverController != null && HiddenPopoverController.PopoverVisible) + { + HiddenPopoverController.Dismiss(false); + } + + _splitPosition = newPos; + + // Inform delegate. + if (WillMoveSplitToPosition != null) + { + WillMoveSplitToPosition(this, SplitPosition); + } + + if (IsShowingMaster) + { + LayoutSubviews(); + } + } + } + + /// + /// Sets the split position animated. + /// Note: split position is the width (in a left/right split, or height in a top/bottom split) of the master view. + /// It is relative to the appropriate side of the splitView, which can be any of the four sides depending on the values + /// in IsMasterBeforeDetail and IsVertical: + /// IsVertical = YES, isMasterBeforeDetail = YES: splitPosition is relative to the LEFT edge. (Default) + /// IsVertical = YES, isMasterBeforeDetail = FALSE: split position is relative to the RIGHT edge. + /// IsVertical = NO, isMasterBeforeDetail = TRUE: split position is relative to the TOP edge. + /// IsVertical = NO, isMasterBeforeDetail = FALSE: split position is relative to the BOTTOM edge. + /// This implementation was chosen so you don't need to recalculate equivalent splitPositions if the user toggles masterBeforeDetail themselves. + /// + /// the new position in units + public void SetSplitPositionAnimated(float fNewPos) + { + var animate = IsShowingMaster; + if (animate) + { + UIView.BeginAnimations("SplitPosition"); + } + SplitPosition = fNewPos; + if (animate) + { + UIView.CommitAnimations(); + } + } + + private nfloat _splitPosition; + + /// + /// Gets or sets the width of the split. + /// + /// + /// The width of the split. + /// + public nfloat SplitWidth + { + get { return _splitWidth; } + set + { + if (value != SplitWidth && value >= 0) + { + _splitWidth = value; + if (IsShowingMaster) + { + LayoutSubviews(); + } + } + } + } + + private nfloat _splitWidth; + + /// + /// Whether to let the user drag the divider to alter the split position. + /// dragging divider. + /// + /// + /// true if allows dragging divider; otherwise, false. + /// + public bool AllowsDraggingDivider + { + get { return DividerView != null && DividerView.AllowsDragging; } + set + { + if (DividerView != null) + { + DividerView.AllowsDragging = value; + } + } + } + + /// + /// Array of UIViewControllers; master is at index 0, detail is at index 1. + /// + /// + /// The view controllers. + /// + /// + /// Is thrown when an argument passed to a method is invalid. + /// + public virtual UIViewController[] ViewControllers + { + get { return _viewControllers; } + set + { + if (_viewControllers != null) + { + foreach (var oController in _viewControllers) + { + if (oController == null) + { + continue; + } + oController.View.RemoveFromSuperview(); + } + } + + _viewControllers = new UIViewController[2]; + if (value != null && value.Length >= 2) + { + MasterViewController = value[0]; + DetailViewController = value[1]; + } + else + { + throw new ArgumentException("Error: This component requires 2 view-controllers"); + } + + LayoutSubviews(); + } + } + + private UIViewController[] _viewControllers; + + /// + /// Gets or sets the master view controller. + /// + /// + /// The master view controller. + /// + public virtual UIViewController MasterViewController + { + get + { + if (ViewControllers != null && ViewControllers.Length > 0) + { + return ViewControllers[0]; + } + return null; + } + set + { + if (ViewControllers == null) + { + ViewControllers = new UIViewController[2]; + ViewControllers[1] = null; + } + + if (ViewControllers[0] == value) + { + return; + } + + // We need to remove the controller's view, otherwise it will float around as a zombie. + if (ViewControllers[0] != null && ViewControllers[0].View != null) + { + ViewControllers[0].View.RemoveFromSuperview(); + } + + ViewControllers[0] = value; + LayoutSubviews(); + } + } + + /// + /// Gets or sets the detail view controller. + /// + /// + /// The detail view controller. + /// + public virtual UIViewController DetailViewController + { + get + { + if (ViewControllers != null && ViewControllers.Length >= 2) + { + return ViewControllers[1]; + } + return null; + } + set + { + if (ViewControllers == null) + { + ViewControllers = new UIViewController[2]; + ViewControllers[0] = null; + } + + if (ViewControllers[1] == value) + { + return; + } + + // We need to remove the controller's view, otherwise it will float around as a zombie. + if (ViewControllers[1] != null && ViewControllers[1].View != null) + { + ViewControllers[1].View.RemoveFromSuperview(); + } + + ViewControllers[1] = value; + LayoutSubviews(); + } + } + + /// + /// Gets or sets the divider view. + /// + /// + /// The divider view. + /// + public MTSplitDividerView DividerView + { + get { return _dividerView; } + set + { + if (value == _dividerView) + { + return; + } + if (_dividerView != null) + { + _dividerView.Dispose(); + } + _dividerView = value; + _dividerView.SplitViewController = this; + _dividerView.BackgroundColor = DefaultCornerColor; + if (IsShowingMaster) + { + LayoutSubviews(); + } + } + } + + private MTSplitDividerView _dividerView; + + /// + /// Gets or sets the divider style. + /// + /// + /// The divider style. + /// + public MTSplitDividerView.DividerStyle DividerStyle + { + get { return _dividerStyle; } + set + { + if (HiddenPopoverController != null && HiddenPopoverController.PopoverVisible) + { + HiddenPopoverController.Dismiss(false); + } + + // We don't check to see if newStyle equals _dividerStyle, because it's a meta-setting. + // Aspects could have been changed since it was set. + _dividerStyle = value; + + // Reconfigure general appearance and behaviour. + nfloat cornerRadius = 0f; + if (_dividerStyle == MTSplitDividerView.DividerStyle.Thin) + { + cornerRadius = DefaultCornerRadius; + SplitWidth = DefaultSplitWidth; + AllowsDraggingDivider = false; + } + else if (_dividerStyle == MTSplitDividerView.DividerStyle.PaneSplitter) + { + cornerRadius = PanesplitterCornerRadius; + SplitWidth = PanesplitterSplitWidth; + AllowsDraggingDivider = true; + } + + // Update divider and corners. + if (DividerView != null) + { + DividerView.SetNeedsDisplay(); + } + if (CornerViews != null) + { + foreach (var corner in CornerViews) + { + corner.CornerRadius = cornerRadius; + } + } + // Layout all views. + LayoutSubviews(); + } + } + + private MTSplitDividerView.DividerStyle _dividerStyle; + + /// + /// Sets the divider style animated. + /// + public void SetDividerStyleAnimated(MTSplitDividerView.DividerStyle eStyle) + { + var animate = IsShowingMaster; + if (animate) + { + UIView.BeginAnimations("DividerStyle"); + } + DividerStyle = eStyle; + if (animate) + { + UIView.CommitAnimations(); + } + } + + + /// + /// Returns TRUE if this view controller is in either of the two Landscape orientations, else FALSE. + /// + public bool IsLandscape + { + get { return InterfaceOrientation == UIInterfaceOrientation.LandscapeLeft || InterfaceOrientation == UIInterfaceOrientation.LandscapeRight; } + } + + /// + /// Gets a value indicating whether the master controller is currently shown. + /// + public bool IsShowingMaster + { + get + { + return ShouldShowMaster + && MasterViewController != null + && MasterViewController.View != null + && MasterViewController.View.Superview == View; + } + } + + /// + /// Finds out if the master controller should be shown. + /// + /// + /// true if should show master; otherwise, false. + /// + private bool ShouldShowMaster + { + get { return ShouldShowMasterForInterfaceOrientation(InterfaceOrientation); } + } + + /// + /// Gets or sets the corner views. + /// Returns an array of two MGSplitCornersView objects, used to draw the inner corners. + /// The first view is the "leading" corners (top edge of screen for left/right split, left edge of screen for top/bottom split). + /// The second view is the "trailing" corners (bottom edge of screen for left/right split, right edge of screen for top/bottom split). + /// Do NOT modify them, except to: + /// 1. Change their background color + /// 2. Change their corner radius + /// + /// + /// The corner views. + /// + public MTSplitCornersView[] CornerViews { get; set; } + + /// + /// Gets a human readable name of the interface orientation. + /// + /// + /// The of interface orientation. + /// + /// + /// The orientation. + /// + public string NameOfInterfaceOrientation(UIInterfaceOrientation theOrientation) + { + string sOrientationName = null; + switch (theOrientation) + { + case UIInterfaceOrientation.Portrait: + sOrientationName = "Portrait"; // Home button at bottom + break; + case UIInterfaceOrientation.PortraitUpsideDown: + sOrientationName = "Portrait (Upside Down)"; // Home button at top + break; + case UIInterfaceOrientation.LandscapeLeft: + sOrientationName = "Landscape (Left)"; // Home button on left + break; + case UIInterfaceOrientation.LandscapeRight: + sOrientationName = "Landscape (Right)"; // Home button on right + break; + } + + return sOrientationName; + } + + /// + /// Returns TRUE if master view should be shown directly embedded in the splitview, instead of hidden in a popover. + /// + private bool ShouldShowMasterForInterfaceOrientation(UIInterfaceOrientation eOrientation) + { + if (eOrientation == UIInterfaceOrientation.LandscapeLeft || eOrientation == UIInterfaceOrientation.LandscapeRight) + { + return ShowsMasterInLandscape; + } + return ShowsMasterInPortrait; + } + + /// + /// Setup this instance's basic properties. + /// + private void Setup() + { + // Configure default behaviour. + SplitWidth = DefaultSplitWidth; + ShowsMasterInPortrait = false; + ShowsMasterInLandscape = true; + _reconfigurePopup = false; + IsVertical = true; + MasterBeforeDetail = true; + SplitPosition = DefaultSplitPosition; + var divRect = View.Bounds; + if (IsVertical) + { + divRect.Y = SplitPosition; + divRect.Height = SplitWidth; + } + else + { + divRect.X = SplitPosition; + divRect.Width = SplitWidth; + } + DividerView = new MTSplitDividerView(divRect) + { + SplitViewController = this, + BackgroundColor = DefaultCornerColor + }; + DividerStyle = MTSplitDividerView.DividerStyle.Thin; + } + + [Obsolete] +#pragma warning disable CS0809 // Obsolete member overrides non-obsolete member + public override bool ShouldAutorotateToInterfaceOrientation(UIInterfaceOrientation toInterfaceOrientation) +#pragma warning restore CS0809 // Obsolete member overrides non-obsolete member + { + return true; + } + + public override bool ShouldAutorotate() + { + return true; + } + + public override void WillRotate(UIInterfaceOrientation toInterfaceOrientation, double duration) + { + if (MasterViewController != null) + { + MasterViewController.WillRotate(toInterfaceOrientation, duration); + } + if (DetailViewController != null) + { + DetailViewController.WillRotate(toInterfaceOrientation, duration); + } + } + + public override void DidRotate(UIInterfaceOrientation fromInterfaceOrientation) + { + if (MasterViewController != null) + { + MasterViewController.DidRotate(fromInterfaceOrientation); + } + if (DetailViewController != null) + { + DetailViewController.DidRotate(fromInterfaceOrientation); + } + } + + public override void WillAnimateRotation(UIInterfaceOrientation toInterfaceOrientation, double duration) + { + if (MasterViewController != null) + { + MasterViewController.WillAnimateRotation(toInterfaceOrientation, duration); + } + if (DetailViewController != null) + { + DetailViewController.WillAnimateRotation(toInterfaceOrientation, duration); + } + + // Hide popover. + if (HiddenPopoverController != null && HiddenPopoverController.PopoverVisible) + { + HiddenPopoverController.Dismiss(false); + } + + // Re-tile views. + _reconfigurePopup = true; + LayoutSubviewsForInterfaceOrientation(toInterfaceOrientation, true); + } + + public override void WillAnimateFirstHalfOfRotation(UIInterfaceOrientation toInterfaceOrientation, double duration) + { + if (MasterViewController != null) + { + MasterViewController.WillAnimateFirstHalfOfRotation(toInterfaceOrientation, duration); + } + if (DetailViewController != null) + { + DetailViewController.WillAnimateFirstHalfOfRotation(toInterfaceOrientation, duration); + } + } + + public override void DidAnimateFirstHalfOfRotation(UIInterfaceOrientation toInterfaceOrientation) + { + if (MasterViewController != null) + { + MasterViewController.DidAnimateFirstHalfOfRotation(toInterfaceOrientation); + } + + if (DetailViewController != null) + { + DetailViewController.DidAnimateFirstHalfOfRotation(toInterfaceOrientation); + } + } + + public override void WillAnimateSecondHalfOfRotation(UIInterfaceOrientation fromInterfaceOrientation, double duration) + { + if (MasterViewController != null) + { + MasterViewController.WillAnimateSecondHalfOfRotation(fromInterfaceOrientation, duration); + } + if (DetailViewController != null) + { + DetailViewController.WillAnimateSecondHalfOfRotation(fromInterfaceOrientation, duration); + } + } + + protected virtual void LayoutSubviewsWithAnimation(bool animate) + { + LayoutSubviewsForInterfaceOrientation(InterfaceOrientation, animate); + } + + protected virtual void LayoutSubviews() + { + LayoutSubviewsForInterfaceOrientation(InterfaceOrientation, true); + } + + public override void ViewWillAppear(bool animated) + { + base.ViewWillAppear(animated); + + if (IsShowingMaster) + { + MasterViewController.ViewWillAppear(animated); + } + if (DetailViewController != null) + { + DetailViewController.ViewWillAppear(animated); + } + } + + public override void ViewDidAppear(bool animated) + { + base.ViewDidAppear(animated); + + if (IsShowingMaster) + { + MasterViewController.ViewDidAppear(animated); + } + if (DetailViewController != null) + { + DetailViewController.ViewDidAppear(animated); + } + _reconfigurePopup = true; + LayoutSubviews(); + } + + public override void ViewWillDisappear(bool animated) + { + base.ViewWillDisappear(animated); + + if (IsShowingMaster) + { + MasterViewController.ViewWillDisappear(animated); + } + if (DetailViewController != null) + { + DetailViewController.ViewWillDisappear(animated); + } + } + + public override void ViewDidDisappear(bool animated) + { + base.ViewDidDisappear(animated); + + if (IsShowingMaster) + { + MasterViewController.ViewDidDisappear(animated); + } + if (DetailViewController != null) + { + DetailViewController.ViewDidDisappear(animated); + } + } + + /// + /// Gets the rectangle that will be used to place the master and detail controller in for a sepcific orientation. + /// You can override this if you don't want to use the full screen to be used for the split controller. + /// + /// + /// The rectangle for the requested orientation. + /// + /// + /// The orientation. + /// + protected virtual CGRect SplitViewRectangleForOrientation(UIInterfaceOrientation theOrientation) + { + return View.Bounds; + } + + /// + /// Layouts the subviews. + /// + protected virtual void LayoutSubviewsForInterfaceOrientation(UIInterfaceOrientation eOrientation, bool animate) + { + if (_reconfigurePopup) + { + ReconfigureForMasterInPopover(!ShouldShowMasterForInterfaceOrientation(eOrientation)); + } + + // Layout the master, detail and divider views appropriately, adding/removing subviews as needed. + // First obtain relevant geometry. + var mainRect = SplitViewRectangleForOrientation(eOrientation); + var fullSize = mainRect.Size; + var width = fullSize.Width; + var height = fullSize.Height; + +#if DEBUG + //Console.WriteLine("Target orientation is " + this.NameOfInterfaceOrientation(eOrientation) + " dimensions will be " + width + " x " + height ); +#endif + + // Layout the master, divider and detail views. + var eNewFrame = mainRect; // new RectangleF (0, 0, width, height); + UIViewController oController; + UIView oView = null; + var bShouldShowMaster = ShouldShowMasterForInterfaceOrientation(eOrientation); + var bMasterFirst = MasterBeforeDetail; + if (IsVertical) + { + // Master on left, detail on right (or vice versa). + CGRect oMasterRect; + CGRect oDividerRect; + CGRect oDetailRect; + if (bMasterFirst) + { + if (!bShouldShowMaster) + { + // Move off-screen. + eNewFrame.X -= (SplitPosition + SplitWidth); + } + eNewFrame.Width = SplitPosition; + oMasterRect = eNewFrame; + + eNewFrame.X += eNewFrame.Width; + eNewFrame.Width = SplitWidth; + oDividerRect = eNewFrame; + + eNewFrame.X += eNewFrame.Width; + eNewFrame.Width = width - eNewFrame.X; + oDetailRect = eNewFrame; + } + else + { + if (!bShouldShowMaster) + { + // Move off-screen. + eNewFrame.Width += (SplitPosition + SplitWidth); + } + + eNewFrame.Width -= (SplitPosition + SplitWidth); + oDetailRect = eNewFrame; + + eNewFrame.X += eNewFrame.Width; + eNewFrame.Width = SplitWidth; + oDividerRect = eNewFrame; + + eNewFrame.X += eNewFrame.Width; + eNewFrame.Width = SplitPosition; + oMasterRect = eNewFrame; + } + + // Position master. + oController = MasterViewController; + if (oController != null) + { + oView = oController.View; + if (oView != null) + { + oView.Frame = oMasterRect; + if (oView.Superview == null) + { + oController.ViewWillAppear(false); + View.AddSubview(oView); + oController.ViewDidAppear(false); + } + } + } + + // Position divider. + if (oView != null) + { + oView = DividerView; + oView.Frame = oDividerRect; + if (oView.Superview == null) + { + View.AddSubview(oView); + } + } + + // Position detail. + oController = DetailViewController; + if (oController != null) + { + oView = oController.View; + if (oView != null) + { + oView.Frame = oDetailRect; + if (oView.Superview == null) + { + oController.ViewWillAppear(false); + View.InsertSubviewAbove(oView, MasterViewController.View); + oController.ViewDidAppear(false); + } + else + { + View.BringSubviewToFront(oView); + } + } + } + } + else + { + // Master above, detail below (or vice versa). + CGRect oMasterRect, oDividerRect, oDetailRect; + if (bMasterFirst) + { + if (!bShouldShowMaster) + { + // Move off-screen. + eNewFrame.Y -= (SplitPosition + SplitWidth); + } + + eNewFrame.Height = SplitPosition; + oMasterRect = eNewFrame; + + eNewFrame.Y += eNewFrame.Height; + eNewFrame.Height = SplitWidth; + oDividerRect = eNewFrame; + + eNewFrame.Y += eNewFrame.Height; + eNewFrame.Height = height - eNewFrame.Y; + oDetailRect = eNewFrame; + } + else + { + if (!bShouldShowMaster) + { + // Move off-screen. + eNewFrame.Height += (SplitPosition + SplitWidth); + } + + eNewFrame.Height -= (SplitPosition + SplitWidth); + oDetailRect = eNewFrame; + + eNewFrame.Y += eNewFrame.Height; + eNewFrame.Height = SplitWidth; + oDividerRect = eNewFrame; + + eNewFrame.Y += eNewFrame.Height; + eNewFrame.Height = SplitPosition; + oMasterRect = eNewFrame; + } + + // Position master. + oController = MasterViewController; + if (oController != null) + { + oView = oController.View; + if (oView != null) + { + oView.Frame = oMasterRect; + if (oView.Superview == null) + { + oController.ViewWillAppear(false); + View.AddSubview(oView); + oController.ViewDidAppear(false); + } + } + } + + // Position divider. + if (oView != null && DividerView != null) + { + oView = DividerView; + oView.Frame = oDividerRect; + if (oView.Superview == null) + { + View.AddSubview(oView); + } + } + + // Position detail. + oController = DetailViewController; + if (oController != null) + { + oView = oController.View; + if (oView != null) + { + oView.Frame = oDetailRect; + if (oView.Superview == null) + { + oController.ViewWillAppear(false); + View.InsertSubviewAbove(oView, MasterViewController.View); + oController.ViewDidAppear(false); + } + else + { + View.BringSubviewToFront(oView); + } + } + } + } + + // Create corner views if necessary. + MTSplitCornersView leadingCorners; // top/left of screen in vertical/horizontal split. + MTSplitCornersView trailingCorners; // bottom/right of screen in vertical/horizontal split. + if (CornerViews == null) + { + var cornerRect = new CGRect(0, 0, 10, 10); // arbitrary, will be resized below. + leadingCorners = new MTSplitCornersView(cornerRect) + { + SplitViewController = this, + CornerBackgroundColor = DefaultCornerColor, + CornerRadius = DefaultCornerRadius + }; + trailingCorners = new MTSplitCornersView(cornerRect) + { + SplitViewController = this, + CornerBackgroundColor = DefaultCornerColor, + CornerRadius = DefaultCornerRadius + }; + CornerViews = new[] {leadingCorners, trailingCorners}; + } + else + { + leadingCorners = CornerViews[0]; + trailingCorners = CornerViews[1]; + } + + // Configure and layout the corner-views. + leadingCorners.Position = IsVertical ? MTSplitCornersView.CornersPosition.LeadingVertical : MTSplitCornersView.CornersPosition.LeadingHorizontal; + trailingCorners.Position = IsVertical ? MTSplitCornersView.CornersPosition.TrailingVertical : MTSplitCornersView.CornersPosition.TrailingHorizontal; + leadingCorners.AutoresizingMask = IsVertical ? UIViewAutoresizing.FlexibleBottomMargin : UIViewAutoresizing.FlexibleRightMargin; + trailingCorners.AutoresizingMask = IsVertical ? UIViewAutoresizing.FlexibleTopMargin : UIViewAutoresizing.FlexibleLeftMargin; + + nfloat x; + nfloat y; + nfloat cornersWidth; + nfloat cornersHeight; + + CGRect leadingRect; + CGRect trailingRect; + + var radius = leadingCorners.CornerRadius; + if (IsVertical) + { + // left/right split + cornersWidth = (radius*2.0f) + SplitWidth; + cornersHeight = radius; + if (bShouldShowMaster) + { + if (bMasterFirst) + { + x = SplitPosition; + } + else + { + x = width - (SplitPosition + SplitWidth); + } + } + else + { + x = 0 - SplitWidth; + } + x -= radius; + y = mainRect.Top; + leadingRect = new CGRect(x, y, cornersWidth, cornersHeight); // top corners + trailingRect = new CGRect(x, (height - cornersHeight) + mainRect.Top, cornersWidth, cornersHeight); // bottom corners + + } + else + { + // top/bottom split + x = 0; + if (bShouldShowMaster) + { + if (bMasterFirst) + { + y = SplitPosition; + } + else + { + y = height - (SplitPosition + SplitWidth); + } + } + else + { + y = 0 - SplitWidth; + } + y -= radius; + y += mainRect.Top; + cornersWidth = radius; + cornersHeight = (radius*2.0f) + SplitWidth; + leadingRect = new CGRect(x, y, cornersWidth, cornersHeight); // left corners + trailingRect = new CGRect((width - cornersWidth), y, cornersWidth, cornersHeight); // right corners + } + + leadingCorners.Frame = leadingRect; + trailingCorners.Frame = trailingRect; + + // Ensure corners are visible and frontmost. + if (DetailViewController != null) + { + if (leadingCorners.Superview == null) + { + View.InsertSubviewAbove(leadingCorners, DetailViewController.View); + View.InsertSubviewAbove(trailingCorners, DetailViewController.View); + } + else + { + View.BringSubviewToFront(leadingCorners); + View.BringSubviewToFront(trailingCorners); + } + } + + if (DividerView != null && DividerView.Superview != null) + { + DividerView.Superview.BringSubviewToFront(DividerView); + } + } + + /// + /// Reconfigures the controller to show master controller in a popover or as a real pane. + /// + /// + /// B in popover. + /// + private void ReconfigureForMasterInPopover(bool bInPopover) + { + _reconfigurePopup = false; + + // Check if the user actually wants the master to be put into a popover. + if (!AutoProvidePopoverAndBarItem) + { + return; + } + + if (bInPopover && HiddenPopoverController != null || !bInPopover && HiddenPopoverController == null || MasterViewController == null) + { + // Nothing to do. + return; + } + + if (bInPopover && HiddenPopoverController == null && BarButtonItem == null) + { + // Create and configure popover for our masterViewController. + if (HiddenPopoverController != null) + { + HiddenPopoverController.Dispose(); + } + HiddenPopoverController = null; + + MasterViewController.ViewWillDisappear(false); + HiddenPopoverController = new UIPopoverController(MasterViewController); + MasterViewController.ViewDidDisappear(false); + + // Create and configure UIBarButtonItem. + BarButtonItem = new UIBarButtonItem("Master", UIBarButtonItemStyle.Bordered, ShowMasterPopover); + + // Inform delegate of this state of affairs. + if (WillHideViewController != null) + { + WillHideViewController(this, MasterViewController, BarButtonItem, HiddenPopoverController); + } + } + else if (!bInPopover && HiddenPopoverController != null && BarButtonItem != null) + { + // I know this looks strange, but it fixes a bizarre issue with UIPopoverController leaving masterViewController's views in disarray. + HiddenPopoverController.PresentFromRect(CGRect.Empty, View, UIPopoverArrowDirection.Any, false); + + // Remove master from popover and destroy popover, if it exists. + HiddenPopoverController.Dismiss(false); + HiddenPopoverController.Dispose(); + HiddenPopoverController = null; + + // Inform delegate that the _barButtonItem will become invalid. + if (WillShowViewController != null) + { + WillShowViewController(this, MasterViewController, BarButtonItem); + } + + // Destroy _barButtonItem. + if (BarButtonItem != null) + { + BarButtonItem.Dispose(); + } + BarButtonItem = null; + + // Move master view. + var masterView = MasterViewController.View; + if (masterView != null && masterView.Superview != View) + { + masterView.RemoveFromSuperview(); + } + } + } + + private void PopoverControllerDidDismissPopover(UIPopoverController popoverController) + { + ReconfigureForMasterInPopover(false); + } + + /// + /// Toggles the split orientation. + /// + public virtual void ToggleSplitOrientation() + { + if (!IsShowingMaster) return; + + if (CornerViews != null) + { + foreach (var corner in CornerViews) + { + corner.Hidden = true; + } + DividerView.Hidden = true; + } + UIView.Animate(0.1f, delegate + { + IsVertical = !IsVertical; + }, + delegate + { + foreach (var oCorner in CornerViews) + { + oCorner.Hidden = false; + } + DividerView.Hidden = false; + }); + } + + /// + /// Toggles the master before detail. + /// + public void ToggleMasterBeforeDetail() + { + if (!IsShowingMaster) return; + + if (CornerViews != null) + { + foreach (var oCorner in CornerViews) + { + oCorner.Hidden = true; + } + DividerView.Hidden = true; + } + UIView.Animate(0.1f, delegate + { + MasterBeforeDetail = !MasterBeforeDetail; + }, + delegate + { + foreach (var oCorner in CornerViews) + { + oCorner.Hidden = false; + } + DividerView.Hidden = false; + }); + } + + /// + /// Toggles the visibility of the master view. + /// + public virtual void ToggleMasterView() + { + if (HiddenPopoverController != null && HiddenPopoverController.PopoverVisible) + { + HiddenPopoverController.Dismiss(false); + } + + if (!IsShowingMaster) + { + // We're about to show the master view. Ensure it's in place off-screen to be animated in. + _reconfigurePopup = true; + ReconfigureForMasterInPopover(false); + LayoutSubviews(); + } + + // This action functions on the current primary orientation; it is independent of the other primary orientation. + UIView.BeginAnimations("toggleMaster"); + if (IsLandscape) + { + ShowsMasterInLandscape = !ShowsMasterInLandscape; + } + else + { + ShowsMasterInPortrait = !ShowsMasterInPortrait; + } + UIView.CommitAnimations(); + } + + /// + /// Called from the bar button item to show the master controller in a popover. + /// + public void ShowMasterPopover(object sender, EventArgs args) + { + if (HiddenPopoverController == null || HiddenPopoverController.PopoverVisible) return; + + // Inform delegate. + if (WillPresentViewController != null) + { + WillPresentViewController(this, HiddenPopoverController, MasterViewController); + } + // Show popover. + HiddenPopoverController.PresentFromBarButtonItem(BarButtonItem, UIPopoverArrowDirection.Any, true); + } + } +} diff --git a/MTSplitViewLib/MTSplitViewLib/MTSplitViewLib.csproj b/MTSplitViewLib/MTSplitViewLib.csproj similarity index 79% rename from MTSplitViewLib/MTSplitViewLib/MTSplitViewLib.csproj rename to MTSplitViewLib/MTSplitViewLib.csproj index 5a91bd3..cc09de1 100644 --- a/MTSplitViewLib/MTSplitViewLib/MTSplitViewLib.csproj +++ b/MTSplitViewLib/MTSplitViewLib.csproj @@ -1,4 +1,4 @@ - + Debug @@ -6,10 +6,11 @@ 10.0.0 2.0 {86B4F178-F272-4404-8CF5-140A5A84CBC2} - {6BC8ED88-2882-458C-8E55-DFD12B67127B};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} Library - MTSplitView - MTSplitView + MTSplitViewLib + MTSplitViewLib + Xamarin.iOS true @@ -33,12 +34,12 @@ - + - + \ No newline at end of file diff --git a/MTSplitViewLib/MTSplitViewLib.sln b/MTSplitViewLib/MTSplitViewLib.sln deleted file mode 100644 index baf0a0f..0000000 --- a/MTSplitViewLib/MTSplitViewLib.sln +++ /dev/null @@ -1,18 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "MTSplitViewLib", "MTSplitViewLib\MTSplitViewLib.csproj", "{B632AC61-5081-4617-9965-81F11EF37B70}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - EndGlobalSection - GlobalSection(MonoDevelopProperties) = preSolution - BaseDirectory = . - StartupItem = MTSplitViewLib\MTSplitViewLib.csproj - outputpath = MTSplitViewLib\build\bin - EndGlobalSection -EndGlobal diff --git a/MTSplitViewLib/MTSplitViewLib/MTSplitCornersView.cs b/MTSplitViewLib/MTSplitViewLib/MTSplitCornersView.cs deleted file mode 100644 index 62908d5..0000000 --- a/MTSplitViewLib/MTSplitViewLib/MTSplitCornersView.cs +++ /dev/null @@ -1,261 +0,0 @@ -// MTSplitViewController -// https://github.com/Krumelur/MTSplitViewController -// -// Ported to Monotouch by René Ruppert, October 2011 -// -// Based on code by Matt Gemmell on 26/07/2010. -// Copyright 2010 Instinctive Code. -// https://github.com/mattgemmell/MGSplitViewController - -using System; -using MonoTouch.UIKit; -using System.Drawing; -using MonoTouch.Foundation; -using MonoTouch.CoreGraphics; - -namespace MTSplitViewLib -{ - public class MTSplitCornersView : UIView - { - public enum CORNERS_POSITION - { - LeadingVertical = 0, // top of screen for a left/right split. - TrailingVertical = 1, // bottom of screen for a left/right split. - LeadingHorizontal = 2, // left of screen for a top/bottom split. - TrailingHorizontal = 3 // right of screen for a top/bottom split. - } - - public MTSplitCornersView () : base() - { - } - - public MTSplitCornersView (NSCoder coder) : base(coder) - { - } - - public MTSplitCornersView (NSObjectFlag t) : base(t) - { - } - - public MTSplitCornersView (IntPtr handle) : base(handle) - { - } - - public MTSplitCornersView (RectangleF frame) : base(frame) - { - this.ContentMode = UIViewContentMode.Redraw; - this.UserInteractionEnabled = false; - this.Opaque = false; - this.BackgroundColor = UIColor.Clear; - this.CornerRadius = 0.0f; // actual value is set by the splitViewController. - this.CornersPosition = MTSplitCornersView.CORNERS_POSITION.LeadingVertical; - } - - private float Deg2Rad(float fDegrees) - { - // Converts degrees to radians. - return fDegrees * ((float)Math.PI / 180.0f); - } - - - private float Rad2Deg(float fRadians) - { - // Converts radians to degrees. - return fRadians * (180f / (float)Math.PI); - } - - public override void Draw (RectangleF rect) - { - // Draw two appropriate corners, with cornerBackgroundColor behind them. - if (this.CornerRadius < 0) - { - return; - } - - float fMaxX = this.Bounds.GetMaxX(); - float fMaxY =this.Bounds.GetMaxY(); - UIBezierPath oPath = new UIBezierPath(); - PointF oPt = PointF.Empty; - switch (this.CornersPosition) - { - case CORNERS_POSITION.LeadingVertical: // top of screen for a left/right split - oPath.MoveTo(oPt); - oPt.Y += this.CornerRadius; - oPath.AppendPath(UIBezierPath.FromArc(oPt, this.CornerRadius, this.Deg2Rad(90), 0f, true)); - oPt.X += this.CornerRadius; - oPt.Y -= this.CornerRadius; - oPath.AddLineTo(oPt); - oPath.AddLineTo(PointF.Empty); - oPath.ClosePath();; - - oPt.X = fMaxX - this.CornerRadius; - oPt.Y = 0; - oPath.MoveTo(oPt); - oPt.Y = fMaxY; - oPath.AddLineTo(oPt); - oPt.X += this.CornerRadius; - oPath.AppendPath(UIBezierPath.FromArc(oPt, this.CornerRadius, this.Deg2Rad(180f), this.Deg2Rad(90), true)); - oPt.Y -= this.CornerRadius; - oPath.AddLineTo(oPt); - oPt.X -= this.CornerRadius; - oPath.AddLineTo(oPt); - oPath.ClosePath(); - break; - - case CORNERS_POSITION.TrailingVertical: // bottom of screen for a left/right split - oPt.Y = fMaxY; - oPath.MoveTo(oPt); - oPt.Y -= this.CornerRadius; - oPath.AppendPath(UIBezierPath.FromArc(oPt, this.CornerRadius, this.Deg2Rad(270f), this.Deg2Rad(360), false)); - oPt.X +=this.CornerRadius; - oPt.Y +=this.CornerRadius; - oPath.AddLineTo(oPt); - oPt.X -=this.CornerRadius; - oPath.AddLineTo(oPt); - oPath.ClosePath(); - - oPt.X = fMaxX -this.CornerRadius; - oPt.Y = fMaxY; - oPath.MoveTo(oPt); - oPt.Y -=this.CornerRadius; - oPath.AddLineTo(oPt); - oPt.X +=this.CornerRadius; - oPath.AppendPath(UIBezierPath.FromArc(oPt, this.CornerRadius, this.Deg2Rad(180f), this.Deg2Rad(270f), false)); - oPt.Y +=this.CornerRadius; - oPath.AddLineTo(oPt); - oPt.X -=this.CornerRadius; - oPath.AddLineTo(oPt); - oPath.ClosePath(); - break; - - case CORNERS_POSITION.LeadingHorizontal: // left of screen for a top/bottom split - oPt.X = 0; - oPt.Y =this.CornerRadius; - oPath.MoveTo(oPt); - oPt.Y -=this.CornerRadius; - oPath.AddLineTo(oPt); - oPt.X +=this.CornerRadius; - oPath.AppendPath(UIBezierPath.FromArc(oPt, this.CornerRadius, this.Deg2Rad(180), this.Deg2Rad(270), false)); - oPt.Y +=this.CornerRadius; - oPath.AddLineTo(oPt); - oPt.X -=this.CornerRadius; - oPath.AddLineTo(oPt); - oPath.ClosePath(); - - oPt.X = 0; - oPt.Y = fMaxY -this.CornerRadius; - oPath.MoveTo(oPt); - oPt.Y = fMaxY; - oPath.AddLineTo(oPt); - oPt.X +=this.CornerRadius; - oPath.AppendPath(UIBezierPath.FromArc(oPt, this.CornerRadius, this.Deg2Rad(180f), this.Deg2Rad(90f), true)); - oPt.Y -=this.CornerRadius; - oPath.AddLineTo(oPt); - oPt.X -=this.CornerRadius; - oPath.AddLineTo(oPt); - oPath.ClosePath(); - break; - - case CORNERS_POSITION.TrailingHorizontal: // right of screen for a top/bottom split - oPt.Y =this.CornerRadius; - oPath.MoveTo(oPt); - oPt.Y -=this.CornerRadius; - oPath.AppendPath(UIBezierPath.FromArc(oPt, this.CornerRadius, this.Deg2Rad(270f), this.Deg2Rad(360f), false)); - oPt.X +=this.CornerRadius; - oPt.Y +=this.CornerRadius; - oPath.AddLineTo(oPt); - oPt.X -=this.CornerRadius; - oPath.AddLineTo(oPt); - oPath.ClosePath(); - - oPt.Y = fMaxY -this.CornerRadius; - oPath.MoveTo(oPt); - oPt.Y +=this.CornerRadius; - oPath.AppendPath(UIBezierPath.FromArc(oPt, this.CornerRadius, this.Deg2Rad(90), 0f, true)); - oPt.X +=this.CornerRadius; - oPt.Y -=this.CornerRadius; - oPath.AddLineTo(oPt); - oPt.X -=this.CornerRadius; - oPath.AddLineTo(oPt); - oPath.ClosePath(); - break; - - default: - break; - } - - this.CornerBackgroundColor.SetFill(); - this.CornerBackgroundColor.SetStroke(); - oPath.Fill(); - } - - public float CornerRadius - { - get - { - return this.fCornerRadius; - } - set - { - if(value != this.fCornerRadius) - { - this.fCornerRadius = value; - this.SetNeedsDisplay(); - } - } - } - private float fCornerRadius; - - public MTSplitViewController SplitViewController - { - get - { - return this.oSplitViewController; - } - set - { - if(this.oSplitViewController != value) - { - this.oSplitViewController = value; - this.SetNeedsDisplay(); - } - } - } - private MTSplitViewController oSplitViewController; - - public CORNERS_POSITION CornersPosition - { - get - { - return this.eCornerPosition; - } - set - { - if(this.eCornerPosition != value) - { - this.eCornerPosition = value; - this.SetNeedsDisplay(); - } - } - } - private CORNERS_POSITION eCornerPosition; - - public UIColor CornerBackgroundColor - { - get - { - return this.oCornerBackgroundColor; - } - set - { - if(this.oCornerBackgroundColor != value) - { - this.oCornerBackgroundColor = value; - this.SetNeedsDisplay(); - } - } - } - private UIColor oCornerBackgroundColor; - } -} - diff --git a/MTSplitViewLib/MTSplitViewLib/MTSplitDividerView.cs b/MTSplitViewLib/MTSplitViewLib/MTSplitDividerView.cs deleted file mode 100644 index fa08647..0000000 --- a/MTSplitViewLib/MTSplitViewLib/MTSplitDividerView.cs +++ /dev/null @@ -1,254 +0,0 @@ -// MTSplitViewController -// https://github.com/Krumelur/MTSplitViewController -// -// Ported to Monotouch by René Ruppert, October 2011 -// -// Based on code by Matt Gemmell on 26/07/2010. -// Copyright 2010 Instinctive Code. -// https://github.com/mattgemmell/MGSplitViewController - -using System; -using MonoTouch.UIKit; -using System.Drawing; -using MonoTouch.CoreGraphics; -using MonoTouch.Foundation; - -namespace MTSplitViewLib -{ - public class MTSplitDividerView : UIView - { - public enum DIVIDER_STYLE - { - Thin = 0, // Thin divider, like UISplitViewController (default). - PaneSplitter = 1 // Thick divider, drawn with a grey gradient and a grab-strip. - } - - public MTSplitDividerView () : base() - { - } - - public MTSplitDividerView (NSCoder coder) : base(coder) - { - } - - public MTSplitDividerView (NSObjectFlag t) : base(t) - { - } - - public MTSplitDividerView (IntPtr handle) : base(handle) - { - } - - public MTSplitDividerView (RectangleF frame) : base(frame) - { - this.UserInteractionEnabled = false; - this.AllowsDragging = false; - this.ContentMode = UIViewContentMode.Redraw; - } - - public override void Draw (RectangleF rect) - { - if (this.SplitViewController.DividerStyle == DIVIDER_STYLE.Thin) - { - base.Draw(rect); - } - else if (this.SplitViewController.DividerStyle == DIVIDER_STYLE.PaneSplitter) - { - // Draw gradient background. - RectangleF oBounds = this.Bounds; - CGColorSpace oRGB = CGColorSpace.CreateDeviceRGB(); - float[] aLocations = new float[] {0, 1}; - float[] aComponents = new float[] - { - // light - 0.988f, 0.988f, 0.988f, 1.0f, - // dark - 0.875f, 0.875f, 0.875f, 1.0f - }; - CGGradient oGradient = new CGGradient(oRGB, aComponents, aLocations); - CGContext oContext = UIGraphics.GetCurrentContext(); - PointF oStart; - PointF oEnd; - if (this.SplitViewController.IsVertical) - { - // Light left to dark right. - oStart = new PointF(oBounds.GetMinX(), oBounds.GetMidY()); - oEnd = new PointF(oBounds.GetMaxX(), oBounds.GetMidY()); - } - else - { - // Light top to dark bottom. - oStart = new PointF(oBounds.GetMidX(), oBounds.GetMinY()); - oEnd = new PointF(oBounds.GetMidX(), oBounds.GetMaxY()); - } - oContext.DrawLinearGradient(oGradient, oStart, oEnd, CGGradientDrawingOptions.DrawsAfterEndLocation); - oRGB.Dispose(); - oGradient.Dispose(); - - // Draw borders. - float fBorderThickness = 1.0f; - UIColor.FromWhiteAlpha(0.7f, 1.0f).SetFill(); - UIColor.FromWhiteAlpha(0.7f, 1.0f).SetStroke(); - RectangleF oBorderRect = oBounds; - if (this.SplitViewController.IsVertical) - { - oBorderRect.Width = fBorderThickness; - UIGraphics.RectFill(oBorderRect); - oBorderRect.X = oBounds.GetMaxX() - fBorderThickness; - UIGraphics.RectFill(oBorderRect); - } - else - { - oBorderRect.Height = fBorderThickness; - UIGraphics.RectFill(oBorderRect); - oBorderRect.Y = oBounds.GetMaxY() - fBorderThickness; - UIGraphics.RectFill(oBorderRect); - } - - // Draw grip. - this.DrawGripThumbInRect(oBounds); - } - } - - private void DrawGripThumbInRect(RectangleF rect) - { - float fWidth = 9.0f; - float fHeight; - if (this.SplitViewController.IsVertical) - { - fHeight = 30.0f; - } - else - { - fHeight = fWidth; - fWidth = 30.0f; - } - - // Draw grip in centred in rect. - RectangleF oGripRect = new RectangleF(0, 0, fWidth, fHeight); - oGripRect.X = ((rect.Width - oGripRect.Width) / 2.0f); - oGripRect.Y = ((rect.Height - oGripRect.Height) / 2.0f); - - float stripThickness = 1.0f; - UIColor oStripColor = UIColor.FromWhiteAlpha(0.35f, 1.0f); - UIColor oLightColor = UIColor.FromWhiteAlpha(1.0f, 1.0f); - float fSpace = 3.0f; - if (this.SplitViewController.IsVertical) - { - oGripRect.Width = stripThickness; - oStripColor.SetFill(); - oStripColor.SetStroke(); - UIGraphics.RectFill(oGripRect); - - oGripRect.X += stripThickness; - oGripRect.Y += 1f; - oLightColor.SetFill(); - oLightColor.SetStroke(); - UIGraphics.RectFill(oGripRect); - oGripRect.X -= stripThickness; - oGripRect.Y -= 1f; - - oGripRect.X += fSpace + stripThickness; - oStripColor.SetFill(); - oStripColor.SetStroke(); - UIGraphics.RectFill(oGripRect); - - oGripRect.X += stripThickness; - oGripRect.Y += 1f; - oLightColor.SetFill(); - oLightColor.SetStroke(); - UIGraphics.RectFill(oGripRect); - oGripRect.X -= stripThickness; - oGripRect.Y -= 1f; - - oGripRect.X += fSpace + stripThickness; - oStripColor.SetFill(); - oStripColor.SetStroke(); - UIGraphics.RectFill(oGripRect); - - oGripRect.X += stripThickness; - oGripRect.Y += 1f; - oLightColor.SetFill(); - oLightColor.SetStroke(); - UIGraphics.RectFill(oGripRect); - } - else - { - oGripRect.Height = stripThickness; - oStripColor.SetFill(); - oStripColor.SetStroke(); - UIGraphics.RectFill(oGripRect); - - oGripRect.Y += stripThickness; - oGripRect.X -= 1f; - oLightColor.SetFill(); - oLightColor.SetStroke(); - UIGraphics.RectFill(oGripRect); - oGripRect.Y -= stripThickness; - oGripRect.X += 1f; - - oGripRect.Y += fSpace + stripThickness; - oStripColor.SetFill(); - oStripColor.SetStroke(); - UIGraphics.RectFill(oGripRect); - - oGripRect.Y += stripThickness; - oGripRect.X -= 1f; - oLightColor.SetFill(); - oLightColor.SetStroke(); - UIGraphics.RectFill(oGripRect); - oGripRect.Y -= stripThickness; - oGripRect.X += 1f; - - oGripRect.Y += fSpace + stripThickness; - oStripColor.SetFill(); - oStripColor.SetStroke(); - UIGraphics.RectFill(oGripRect); - - oGripRect.Y += stripThickness; - oGripRect.X -= 1f; - oLightColor.SetFill(); - oLightColor.SetStroke(); - UIGraphics.RectFill(oGripRect); - } - } - - public override void TouchesMoved (MonoTouch.Foundation.NSSet touches, UIEvent evt) - { - UITouch oTouch = touches.AnyObject as UITouch; - if (oTouch != null) - { - PointF oLastPt = oTouch.PreviousLocationInView(this); - PointF oPt = oTouch.LocationInView(this); - float fOffset = (this.SplitViewController.IsVertical) ? oPt.X - oLastPt.X : oPt.Y - oLastPt.Y; - if (!this.SplitViewController.MasterBeforeDetail) - { - fOffset = -fOffset; - } - this.SplitViewController.SplitPosition = this.SplitViewController.SplitPosition + fOffset; - } - } - - public virtual MTSplitViewController SplitViewController - { - get; - set; - } - - public virtual bool AllowsDragging - { - get - { - return this.bAlllowsDragging; - } - set - { - this.bAlllowsDragging = value; - this.UserInteractionEnabled = value; - } - } - private bool bAlllowsDragging; - } - -} - diff --git a/MTSplitViewLib/MTSplitViewLib/MTSplitViewController.cs b/MTSplitViewLib/MTSplitViewLib/MTSplitViewController.cs deleted file mode 100644 index bb4b2e2..0000000 --- a/MTSplitViewLib/MTSplitViewLib/MTSplitViewController.cs +++ /dev/null @@ -1,1460 +0,0 @@ -// MTSplitViewController -// https://github.com/Krumelur/MTSplitViewController -// -// Ported to Monotouch by René Ruppert, October 2011 -// -// Based on code by Matt Gemmell on 26/07/2010. -// Copyright 2010 Instinctive Code. -// https://github.com/mattgemmell/MGSplitViewController - -using System; -using MonoTouch.UIKit; -using MonoTouch.Foundation; -using System.Collections.Generic; -using System.Drawing; - -namespace MTSplitViewLib -{ - public class MTSplitViewController : UIViewController - { - // default width of master view in UISplitViewController. - public const float MG_DEFAULT_SPLIT_POSITION = 320.0f; - // default width of split-gutter in UISplitViewController. - public const float MG_DEFAULT_SPLIT_WIDTH = 1.0f; - // default corner-radius of overlapping split-inner corners on the master and detail views. - public const float MG_DEFAULT_CORNER_RADIUS = 5.0f; - // default color of intruding inner corners (and divider background). - public UIColor MG_DEFAULT_CORNER_COLOR = UIColor.Black; - // corner-radius of split-inner corners for MGSplitViewDividerStylePaneSplitter style. - public const float MG_PANESPLITTER_CORNER_RADIUS = 0.0f; - // width of split-gutter for MGSplitViewDividerStylePaneSplitter style. - public const float MG_PANESPLITTER_SPLIT_WIDTH = 25.0f; - // minimum width a view is allowed to become as a result of changing the splitPosition. - public const float MG_MIN_VIEW_WIDTH = 200.0f; - - public MTSplitViewController () : base() - { - this.Setup (); - } - - public MTSplitViewController (NSCoder coder) : base(coder) - { - this.Setup (); - } - - public MTSplitViewController (NSObjectFlag t) : base(t) - { - this.Setup (); - } - - public MTSplitViewController (IntPtr handle) : base(handle) - { - this.Setup (); - } - - public MTSplitViewController (string nibName, NSBundle bundle) : base(nibName, bundle) - { - this.Setup (); - } - - /// - /// Will be triggered if the orientation of the panels changes. - /// - public event Action WillChangeSplitOrientationToVertical; - /// - /// Will be triggered if the user wants to change the split position. - /// - public event Func ConstrainSplitPosition; - /// - /// Will be triggered if the split position is moved. - /// - public event Action WillMoveSplitToPosition; - /// - /// Will be triggered if the master view controller will be hidden. - /// - public event Action WillHideViewController; - /// - /// Will be called if the master view controller will be shown. - /// - public event Action WillShowViewController; - /// - /// Will be called if the master view controller will be shown in a popove. - /// - public event Action WillPresentViewController; - - // Indicates if the popover has to be reconfigured. - private bool bReconfigurePopup; - - /// - /// Gets or sets the hidden popover controller used to display the master view controller. - /// - public UIPopoverController HiddenPopoverController - { - get; - set; - } - - /// - /// If TRUE, the controller provides a popover and a bar button item for the master controller if the master is hidden. Default is TRUE. - /// - public bool AutoProvidePopoverAndBarItem = true; - - /// - /// Gets or sets the bar button item used to present the master view controller from. - /// - /// - /// The bar button item. - /// - public UIBarButtonItem BarButtonItem - { - get; - set; - } - - /// - /// Gets or sets a value indicating whether the master controller is shown in portrait mode. - /// master in portrait. - /// - /// - /// true if shows master in portrait; otherwise, false. - /// - public bool ShowsMasterInPortrait - { - get - { - return this.bShowsMasterInPortrait; - } - set - { - if (value != this.ShowsMasterInPortrait) - { - this.bShowsMasterInPortrait = value; - - if (!this.IsLandscape) - { - // i.e. if this will cause a visual change. - if (this.HiddenPopoverController != null && this.HiddenPopoverController.PopoverVisible) - { - this.HiddenPopoverController.Dismiss (false); - } - - // Rearrange views. - this.bReconfigurePopup = true; - this.LayoutSubviews (); - } - } - - } - } - private bool bShowsMasterInPortrait; - - /// - /// Gets or sets a value indicating whether the master controller is visible in landscape mode. - /// master in landscape. - /// - /// - /// true if shows master in landscape; otherwise, false. - /// - public bool ShowsMasterInLandscape - { - get - { - return this.bShowsMasterInLandscape; - } - set - { - this.bShowsMasterInLandscape = value; - if (this.IsLandscape) - { - // i.e. if this will cause a visual change. - if (this.HiddenPopoverController != null && this.HiddenPopoverController.PopoverVisible) - { - this.HiddenPopoverController.Dismiss (false); - } - - // Rearrange views. - this.bReconfigurePopup = true; - this.LayoutSubviews (); - } - } - } - private bool bShowsMasterInLandscape; - - /// - /// If FALSE, split is horizontal, i.e. master above detail. If TRUE, split is vertical, i.e. master left of detail. - /// - /// - /// true if this instance is vertical; otherwise, false. - /// - public bool IsVertical - { - get - { - return this.bIsVertical; - } - - set - { - if (value != this.IsVertical) - { - if (this.HiddenPopoverController != null && this.HiddenPopoverController.PopoverVisible) - { - this.HiddenPopoverController.Dismiss (false); - } - - this.bIsVertical = value; - - // Inform delegate. - if (this.WillChangeSplitOrientationToVertical != null) - { - this.WillChangeSplitOrientationToVertical (this, this.bIsVertical); - } - } - - this.LayoutSubviews (); - } - } - private bool bIsVertical; - - /// - /// If FALSE, master view is below/right of detail. Otherwise master view is above/left of detail. - /// before detail. - /// - /// - /// true if master before detail; otherwise, false. - /// - public bool MasterBeforeDetail - { - get - { - return this.bMasterBeforeDetail; - } - set - { - if (value != this.MasterBeforeDetail) - { - if (this.HiddenPopoverController != null && this.HiddenPopoverController.PopoverVisible) - { - this.HiddenPopoverController.Dismiss (false); - } - - this.bMasterBeforeDetail = value; - - if (this.IsShowingMaster) - { - this.LayoutSubviews (); - } - } - } - } - private bool bMasterBeforeDetail; - - - /// - /// Starting position of split in units, relative to top/left (depending on IsVertical setting) if MasterBeforeDetail is TRUE, - /// else relative to bottom/right. - /// - /// - /// The split position. - /// - public float SplitPosition - { - get - { - return this.fSplitPosition; - } - set - { - // Check to see if delegate wishes to constrain the position. - bool bConstrained = false; - SizeF oFullSize = this.SplitViewRectangleForOrientation (this.InterfaceOrientation).Size; - float fNewPos = value; - if (this.ConstrainSplitPosition != null) - { - fNewPos = this.ConstrainSplitPosition (this, value, oFullSize); - bConstrained = true; // implicitly trust delegate's response. - } - else - { - // Apply default constraints if delegate doesn't wish to participate. - float fMinPos = MG_MIN_VIEW_WIDTH; - float fMaxPos = ((this.IsVertical) ? oFullSize.Width : oFullSize.Height) - (MG_MIN_VIEW_WIDTH + this.SplitWidth); - bConstrained = (fNewPos != this.SplitPosition && fNewPos >= fMinPos && fNewPos <= fMaxPos); - } - if (bConstrained) - { - if (this.HiddenPopoverController != null && this.HiddenPopoverController.PopoverVisible) - { - this.HiddenPopoverController.Dismiss (false); - } - - this.fSplitPosition = fNewPos; - - // Inform delegate. - if (this.WillMoveSplitToPosition != null) - { - this.WillMoveSplitToPosition (this, this.SplitPosition); - } - - if (this.IsShowingMaster) - { - this.LayoutSubviews (); - } - } - } - } - - /// - /// Sets the split position animated. - /// Note: split position is the width (in a left/right split, or height in a top/bottom split) of the master view. - /// It is relative to the appropriate side of the splitView, which can be any of the four sides depending on the values - /// in IsMasterBeforeDetail and IsVertical: - /// IsVertical = YES, isMasterBeforeDetail = YES: splitPosition is relative to the LEFT edge. (Default) - /// IsVertical = YES, isMasterBeforeDetail = FALSE: split position is relative to the RIGHT edge. - /// IsVertical = NO, isMasterBeforeDetail = TRUE: split position is relative to the TOP edge. - /// IsVertical = NO, isMasterBeforeDetail = FALSE: split position is relative to the BOTTOM edge. - /// This implementation was chosen so you don't need to recalculate equivalent splitPositions if the user toggles masterBeforeDetail themselves. - /// - /// the new position in units - public void SetSplitPositionAnimated (float fNewPos) - { - bool bAnimate = this.IsShowingMaster; - if (bAnimate) - { - UIView.BeginAnimations ("SplitPosition"); - } - this.SplitPosition = fNewPos; - if (bAnimate) - { - UIView.CommitAnimations (); - } - } - - private float fSplitPosition; - - /// - /// Gets or sets the width of the split. - /// - /// - /// The width of the split. - /// - public float SplitWidth - { - get - { - return this.fSplitWidth; - } - set - { - if (value != this.SplitWidth && value >= 0) - { - this.fSplitWidth = value; - if (this.IsShowingMaster) - { - this.LayoutSubviews (); - } - } - } - } - - private float fSplitWidth; - - /// - /// Whether to let the user drag the divider to alter the split position. - /// dragging divider. - /// - /// - /// true if allows dragging divider; otherwise, false. - /// - public bool AllowsDraggingDivider - { - get - { - return this.DividerView != null && this.DividerView.AllowsDragging; - } - set - { - if (this.DividerView != null) - { - this.DividerView.AllowsDragging = value; - } - } - } - - /// - /// Array of UIViewControllers; master is at index 0, detail is at index 1. - /// - /// - /// The view controllers. - /// - /// - /// Is thrown when an argument passed to a method is invalid. - /// - public virtual UIViewController[] ViewControllers - { - get - { - return this.aViewControllers; - } - set - { - if (this.aViewControllers != null) - { - foreach (UIViewController oController in this.aViewControllers) - { - if (oController == null) - { - continue; - } - oController.View.RemoveFromSuperview (); - } - } - - this.aViewControllers = new UIViewController[2]; - if (value != null && value.Length >= 2) - { - this.MasterViewController = value [0]; - this.DetailViewController = value [1]; - } - else - { - throw new ArgumentException ("Error: require 2 view-controllers."); - } - - this.LayoutSubviews (); - } - } - - private UIViewController[] aViewControllers; - - /// - /// Gets or sets the master view controller. - /// - /// - /// The master view controller. - /// - public virtual UIViewController MasterViewController - { - get - { - if (this.ViewControllers != null && this.ViewControllers.Length > 0) - { - return this.ViewControllers [0]; - } - return null; - } - set - { - if (this.ViewControllers == null) - { - this.ViewControllers = new UIViewController[2]; - this.ViewControllers [1] = null; - } - - if (this.ViewControllers [0] == value) - { - return; - } - - // We need to remove the controller's view, otherwise it will float around as a zombie. - if(this.ViewControllers[0] != null && this.ViewControllers[0].View != null) - { - this.ViewControllers[0].View.RemoveFromSuperview(); - } - - this.ViewControllers [0] = value; - this.LayoutSubviews (); - } - } - - /// - /// Gets or sets the detail view controller. - /// - /// - /// The detail view controller. - /// - public virtual UIViewController DetailViewController - { - get - { - if (this.ViewControllers != null && this.ViewControllers.Length >= 2) - { - return this.ViewControllers [1]; - } - return null; - } - set - { - if (this.ViewControllers == null) - { - this.ViewControllers = new UIViewController[2]; - this.ViewControllers [0] = null; - } - - if (this.ViewControllers [1] == value) - { - return; - } - - // We need to remove the controller's view, otherwise it will float around as a zombie. - if ( this.ViewControllers [1] != null && this.ViewControllers[1].View != null ) - { - this.ViewControllers [1].View.RemoveFromSuperview (); - } - - this.ViewControllers [1] = value; - this.LayoutSubviews (); - } - } - - /// - /// Gets or sets the divider view. - /// - /// - /// The divider view. - /// - public MTSplitDividerView DividerView - { - get - { - return this.oDividerView; - } - set - { - if (value == this.oDividerView) - { - return; - } - if(this.oDividerView != null) - { - this.oDividerView.Dispose (); - } - this.oDividerView = value; - this.oDividerView.SplitViewController = this; - this.oDividerView.BackgroundColor = MG_DEFAULT_CORNER_COLOR; - if (this.IsShowingMaster) - { - this.LayoutSubviews (); - } - } - } - - private MTSplitDividerView oDividerView; - - /// - /// Gets or sets the divider style. - /// - /// - /// The divider style. - /// - public MTSplitDividerView.DIVIDER_STYLE DividerStyle - { - get - { - return this.eDividerStyle; - } - set - { - if (this.HiddenPopoverController != null && this.HiddenPopoverController.PopoverVisible) - { - this.HiddenPopoverController.Dismiss (false); - } - - // We don't check to see if newStyle equals _dividerStyle, because it's a meta-setting. - // Aspects could have been changed since it was set. - this.eDividerStyle = value; - - // Reconfigure general appearance and behaviour. - float fCornerRadius = 0f; - if (this.eDividerStyle == MTSplitDividerView.DIVIDER_STYLE.Thin) - { - fCornerRadius = MG_DEFAULT_CORNER_RADIUS; - this.SplitWidth = MG_DEFAULT_SPLIT_WIDTH; - this.AllowsDraggingDivider = false; - } - else if (this.eDividerStyle == MTSplitDividerView.DIVIDER_STYLE.PaneSplitter) - { - fCornerRadius = MG_PANESPLITTER_CORNER_RADIUS; - this.SplitWidth = MG_PANESPLITTER_SPLIT_WIDTH; - this.AllowsDraggingDivider = true; - } - - // Update divider and corners. - if(this.DividerView != null) - { - this.DividerView.SetNeedsDisplay (); - } - if (this.CornerViews != null) - { - foreach (MTSplitCornersView corner in this.CornerViews) - { - corner.CornerRadius = fCornerRadius; - } - } - // Layout all views. - this.LayoutSubviews (); - } - } - - private MTSplitDividerView.DIVIDER_STYLE eDividerStyle; - - /// - /// Sets the divider style animated. - /// - public void SetDividerStyleAnimated (MTSplitDividerView.DIVIDER_STYLE eStyle) - { - bool bAnimate = this.IsShowingMaster; - if (bAnimate) - { - UIView.BeginAnimations ("DividerStyle"); - } - this.DividerStyle = eStyle; - if (bAnimate) - { - UIView.CommitAnimations (); - } - } - - - /// - /// Returns TRUE if this view controller is in either of the two Landscape orientations, else FALSE. - /// - public bool IsLandscape - { - get - { - return this.InterfaceOrientation == UIInterfaceOrientation.LandscapeLeft || this.InterfaceOrientation == UIInterfaceOrientation.LandscapeRight; - } - } - - /// - /// Gets a value indicating whether the master controller is currently shown. - /// - public bool IsShowingMaster - { - get - { - return this.ShouldShowMaster - && this.MasterViewController != null - && this.MasterViewController.View != null - && this.MasterViewController.View.Superview == this.View; - } - } - - /// - /// Finds out if the master controller should be shown. - /// - /// - /// true if should show master; otherwise, false. - /// - private bool ShouldShowMaster - { - get - { - return this.ShouldShowMasterForInterfaceOrientation (this.InterfaceOrientation); - } - } - - - /// - /// Gets or sets the corner views. - /// Returns an array of two MGSplitCornersView objects, used to draw the inner corners. - /// The first view is the "leading" corners (top edge of screen for left/right split, left edge of screen for top/bottom split). - /// The second view is the "trailing" corners (bottom edge of screen for left/right split, right edge of screen for top/bottom split). - /// Do NOT modify them, except to: - /// 1. Change their background color - /// 2. Change their corner radius - /// - /// - /// The corner views. - /// - public MTSplitCornersView[] CornerViews - { - get - { - return this.aCornerViews; - } - set - { - this.aCornerViews = value; - } - } - - private MTSplitCornersView[] aCornerViews; - - /// - /// Gets a human readable name of the interface orientation. - /// - /// - /// The of interface orientation. - /// - /// - /// The orientation. - /// - public string NameOfInterfaceOrientation (UIInterfaceOrientation theOrientation) - { - string sOrientationName = null; - switch (theOrientation) - { - case UIInterfaceOrientation.Portrait: - sOrientationName = "Portrait"; // Home button at bottom - break; - case UIInterfaceOrientation.PortraitUpsideDown: - sOrientationName = "Portrait (Upside Down)"; // Home button at top - break; - case UIInterfaceOrientation.LandscapeLeft: - sOrientationName = "Landscape (Left)"; // Home button on left - break; - case UIInterfaceOrientation.LandscapeRight: - sOrientationName = "Landscape (Right)"; // Home button on right - break; - default: - break; - } - - return sOrientationName; - } - - /// - /// Returns TRUE if master view should be shown directly embedded in the splitview, instead of hidden in a popover. - /// - private bool ShouldShowMasterForInterfaceOrientation (UIInterfaceOrientation eOrientation) - { - if (eOrientation == UIInterfaceOrientation.LandscapeLeft || eOrientation == UIInterfaceOrientation.LandscapeRight) - { - return this.ShowsMasterInLandscape; - } - else - { - return this.ShowsMasterInPortrait; - } - } - - /// - /// Setup this instance's basic properties. - /// - private void Setup () - { - // Configure default behaviour. - this.SplitWidth = MG_DEFAULT_SPLIT_WIDTH; - this.ShowsMasterInPortrait = false; - this.ShowsMasterInLandscape = true; - this.bReconfigurePopup = false; - this.IsVertical = true; - this.MasterBeforeDetail = true; - this.SplitPosition = MG_DEFAULT_SPLIT_POSITION; - RectangleF oDivRect = this.View.Bounds; - if (this.IsVertical) - { - oDivRect.Y = this.SplitPosition; - oDivRect.Height = this.SplitWidth; - } - else - { - oDivRect.X = this.SplitPosition; - oDivRect.Width = this.SplitWidth; - } - this.DividerView = new MTSplitDividerView (oDivRect); - this.DividerView.SplitViewController = this; - this.DividerView.BackgroundColor = MG_DEFAULT_CORNER_COLOR; - this.DividerStyle = MTSplitDividerView.DIVIDER_STYLE.Thin; - } - - [Obsolete] - public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation) - { - return true; - } - - public override bool ShouldAutorotate () - { - return true; - } - - public override void WillRotate (UIInterfaceOrientation toInterfaceOrientation, double duration) - { - if (this.MasterViewController != null) - { - this.MasterViewController.WillRotate (toInterfaceOrientation, duration); - } - if (this.DetailViewController != null) - { - this.DetailViewController.WillRotate (toInterfaceOrientation, duration); - } - } - - public override void DidRotate (UIInterfaceOrientation fromInterfaceOrientation) - { - if (this.MasterViewController != null) - { - this.MasterViewController.DidRotate (fromInterfaceOrientation); - } - if (this.DetailViewController != null) - { - this.DetailViewController.DidRotate (fromInterfaceOrientation); - } - } - - public override void WillAnimateRotation (UIInterfaceOrientation toInterfaceOrientation, double duration) - { - if (this.MasterViewController != null) - { - this.MasterViewController.WillAnimateRotation (toInterfaceOrientation, duration); - } - if (this.DetailViewController != null) - { - this.DetailViewController.WillAnimateRotation (toInterfaceOrientation, duration); - } - - // Hide popover. - if (this.HiddenPopoverController != null && this.HiddenPopoverController.PopoverVisible) - { - this.HiddenPopoverController.Dismiss (false); - } - - // Re-tile views. - this.bReconfigurePopup = true; - this.LayoutSubviewsForInterfaceOrientation (toInterfaceOrientation, true); - } - - public override void WillAnimateFirstHalfOfRotation (UIInterfaceOrientation toInterfaceOrientation, double duration) - { - if (this.MasterViewController != null) - { - this.MasterViewController.WillAnimateFirstHalfOfRotation (toInterfaceOrientation, duration); - } - if (this.DetailViewController != null) - { - this.DetailViewController.WillAnimateFirstHalfOfRotation (toInterfaceOrientation, duration); - } - } - - public override void DidAnimateFirstHalfOfRotation (UIInterfaceOrientation toInterfaceOrientation) - { - if (this.MasterViewController != null) - { - this.MasterViewController.DidAnimateFirstHalfOfRotation (toInterfaceOrientation); - } - - if (this.DetailViewController != null) - { - this.DetailViewController.DidAnimateFirstHalfOfRotation (toInterfaceOrientation); - } - } - - public override void WillAnimateSecondHalfOfRotation (UIInterfaceOrientation fromInterfaceOrientation, double duration) - { - if (this.MasterViewController != null) - { - this.MasterViewController.WillAnimateSecondHalfOfRotation (fromInterfaceOrientation, duration); - } - if (this.DetailViewController != null) - { - this.DetailViewController.WillAnimateSecondHalfOfRotation (fromInterfaceOrientation, duration); - } - } - - protected virtual void LayoutSubviewsWithAnimation (bool animate) - { - this.LayoutSubviewsForInterfaceOrientation (this.InterfaceOrientation, animate); - } - - protected virtual void LayoutSubviews () - { - this.LayoutSubviewsForInterfaceOrientation (this.InterfaceOrientation, true); - } - - public override void ViewWillAppear (bool animated) - { - base.ViewWillAppear (animated); - - if (this.IsShowingMaster) - { - this.MasterViewController.ViewWillAppear (animated); - } - if (this.DetailViewController != null) - { - this.DetailViewController.ViewWillAppear (animated); - } - } - - public override void ViewDidAppear (bool animated) - { - base.ViewDidAppear (animated); - - if (this.IsShowingMaster) - { - this.MasterViewController.ViewDidAppear (animated); - } - if (this.DetailViewController != null) - { - this.DetailViewController.ViewDidAppear (animated); - } - this.bReconfigurePopup = true; - this.LayoutSubviews (); - } - - public override void ViewWillDisappear (bool animated) - { - base.ViewWillDisappear (animated); - - if (this.IsShowingMaster) - { - this.MasterViewController.ViewWillDisappear (animated); - } - if (this.DetailViewController != null) - { - this.DetailViewController.ViewWillDisappear (animated); - } - } - - public override void ViewDidDisappear (bool animated) - { - base.ViewDidDisappear (animated); - - if (this.IsShowingMaster) - { - this.MasterViewController.ViewDidDisappear (animated); - } - if (this.DetailViewController != null) - { - this.DetailViewController.ViewDidDisappear (animated); - } - } - - /// - /// Gets the rectangle that will be used to place the master and detail controller in for a sepcific orientation. - /// You can override this if you don't want to use the full screen to be used for the split controller. - /// - /// - /// The rectangle for the requested orientation. - /// - /// - /// The orientation. - /// - protected virtual RectangleF SplitViewRectangleForOrientation (UIInterfaceOrientation theOrientation) - { - return View.Bounds; - } - - /// - /// Layouts the subviews. - /// - protected virtual void LayoutSubviewsForInterfaceOrientation (UIInterfaceOrientation eOrientation, bool animate) - { - if (this.bReconfigurePopup) - { - this.ReconfigureForMasterInPopover (!this.ShouldShowMasterForInterfaceOrientation (eOrientation)); - } - - // Layout the master, detail and divider views appropriately, adding/removing subviews as needed. - // First obtain relevant geometry. - RectangleF oMainRect = this.SplitViewRectangleForOrientation (eOrientation); - SizeF oFullSize = oMainRect.Size; - float width = oFullSize.Width; - float height = oFullSize.Height; - -#if DEBUG - //Console.WriteLine("Target orientation is " + this.NameOfInterfaceOrientation(eOrientation) + " dimensions will be " + width + " x " + height ); -#endif - - // Layout the master, divider and detail views. - RectangleF eNewFrame = oMainRect;// new RectangleF (0, 0, width, height); - UIViewController oController; - UIView oView = null; - bool bShouldShowMaster = this.ShouldShowMasterForInterfaceOrientation (eOrientation); - bool bMasterFirst = this.MasterBeforeDetail; - if (this.IsVertical) - { - // Master on left, detail on right (or vice versa). - RectangleF oMasterRect; - RectangleF oDividerRect; - RectangleF oDetailRect; - if (bMasterFirst) - { - if (!bShouldShowMaster) - { - // Move off-screen. - eNewFrame.X -= (this.SplitPosition + this.SplitWidth); - } - eNewFrame.Width = this.SplitPosition; - oMasterRect = eNewFrame; - - eNewFrame.X += eNewFrame.Width; - eNewFrame.Width = this.SplitWidth; - oDividerRect = eNewFrame; - - eNewFrame.X += eNewFrame.Width; - eNewFrame.Width = width - eNewFrame.X; - oDetailRect = eNewFrame; - } - else - { - if (!bShouldShowMaster) - { - // Move off-screen. - eNewFrame.Width += (this.SplitPosition + this.SplitWidth); - } - - eNewFrame.Width -= (this.SplitPosition + this.SplitWidth); - oDetailRect = eNewFrame; - - eNewFrame.X += eNewFrame.Width; - eNewFrame.Width = this.SplitWidth; - oDividerRect = eNewFrame; - - eNewFrame.X += eNewFrame.Width; - eNewFrame.Width = this.SplitPosition; - oMasterRect = eNewFrame; - } - - // Position master. - oController = this.MasterViewController; - if (oController != null) - { - oView = oController.View; - if (oView != null) - { - oView.Frame = oMasterRect; - if (oView.Superview == null) - { - oController.ViewWillAppear (false); - this.View.AddSubview (oView); - oController.ViewDidAppear (false); - } - } - } - - // Position divider. - if (oView != null) - { - oView = this.DividerView; - oView.Frame = oDividerRect; - if (oView.Superview == null) - { - this.View.AddSubview (oView); - } - } - - // Position detail. - oController = this.DetailViewController; - if (oController != null) - { - oView = oController.View; - if (oView != null) - { - oView.Frame = oDetailRect; - if (oView.Superview == null) - { - oController.ViewWillAppear(false); - this.View.InsertSubviewAbove (oView, this.MasterViewController.View); - oController.ViewDidAppear ( false ); - } - else - { - this.View.BringSubviewToFront (oView); - } - } - } - } - else - { - // Master above, detail below (or vice versa). - RectangleF oMasterRect, oDividerRect, oDetailRect; - if (bMasterFirst) - { - if (!bShouldShowMaster) - { - // Move off-screen. - eNewFrame.Y -= (this.SplitPosition + this.SplitWidth); - } - - eNewFrame.Height = this.SplitPosition; - oMasterRect = eNewFrame; - - eNewFrame.Y += eNewFrame.Height; - eNewFrame.Height = this.SplitWidth; - oDividerRect = eNewFrame; - - eNewFrame.Y += eNewFrame.Height; - eNewFrame.Height = height - eNewFrame.Y; - oDetailRect = eNewFrame; - } - else - { - if (!bShouldShowMaster) - { - // Move off-screen. - eNewFrame.Height += (this.SplitPosition + this.SplitWidth); - } - - eNewFrame.Height -= (this.SplitPosition + this.SplitWidth); - oDetailRect = eNewFrame; - - eNewFrame.Y += eNewFrame.Height; - eNewFrame.Height = this.SplitWidth; - oDividerRect = eNewFrame; - - eNewFrame.Y += eNewFrame.Height; - eNewFrame.Height = this.SplitPosition; - oMasterRect = eNewFrame; - } - - // Position master. - oController = this.MasterViewController; - if (oController != null) - { - oView = oController.View; - if (oView != null) - { - oView.Frame = oMasterRect; - if (oView.Superview == null) - { - oController.ViewWillAppear (false); - this.View.AddSubview (oView); - oController.ViewDidAppear (false); - } - } - } - - // Position divider. - if (oView != null && this.DividerView != null) - { - oView = this.DividerView; - oView.Frame = oDividerRect; - if (oView.Superview == null) - { - this.View.AddSubview (oView); - } - } - - // Position detail. - oController = this.DetailViewController; - if (oController != null) - { - oView = oController.View; - if (oView != null) - { - oView.Frame = oDetailRect; - if (oView.Superview == null) - { - oController.ViewWillAppear ( false ); - this.View.InsertSubviewAbove (oView, this.MasterViewController.View); - oController.ViewDidAppear ( false ); - } - else - { - this.View.BringSubviewToFront (oView); - } - } - } - } - - // Create corner views if necessary. - MTSplitCornersView oLeadingCorners; // top/left of screen in vertical/horizontal split. - MTSplitCornersView oTrailingCorners; // bottom/right of screen in vertical/horizontal split. - if (this.CornerViews == null) - { - RectangleF oCornerRect = new RectangleF (0, 0, 10, 10); // arbitrary, will be resized below. - oLeadingCorners = new MTSplitCornersView (oCornerRect); - oLeadingCorners.SplitViewController = this; - oLeadingCorners.CornerBackgroundColor = MG_DEFAULT_CORNER_COLOR; - oLeadingCorners.CornerRadius = MG_DEFAULT_CORNER_RADIUS; - oTrailingCorners = new MTSplitCornersView (oCornerRect); - oTrailingCorners.SplitViewController = this; - oTrailingCorners.CornerBackgroundColor = MG_DEFAULT_CORNER_COLOR; - oTrailingCorners.CornerRadius = MG_DEFAULT_CORNER_RADIUS; - this.CornerViews = new MTSplitCornersView[]{ oLeadingCorners, oTrailingCorners }; - } - else - { - oLeadingCorners = this.CornerViews [0]; - oTrailingCorners = this.CornerViews [1]; - } - - // Configure and layout the corner-views. - oLeadingCorners.CornersPosition = (this.IsVertical) ? MTSplitCornersView.CORNERS_POSITION.LeadingVertical : MTSplitCornersView.CORNERS_POSITION.LeadingHorizontal; - oTrailingCorners.CornersPosition = (this.IsVertical) ? MTSplitCornersView.CORNERS_POSITION.TrailingVertical : MTSplitCornersView.CORNERS_POSITION.TrailingHorizontal; - oLeadingCorners.AutoresizingMask = (this.IsVertical) ? UIViewAutoresizing.FlexibleBottomMargin : UIViewAutoresizing.FlexibleRightMargin; - oTrailingCorners.AutoresizingMask = (this.IsVertical) ? UIViewAutoresizing.FlexibleTopMargin : UIViewAutoresizing.FlexibleLeftMargin; - - float fX; - float fY; - float fCornersWidth; - float fCornersHeight; - - RectangleF oLeadingRect; - RectangleF oTrailingRect; - - float fRadius = oLeadingCorners.CornerRadius; - if (this.IsVertical) - { - // left/right split - fCornersWidth = (fRadius * 2.0f) + this.SplitWidth; - fCornersHeight = fRadius; - if (bShouldShowMaster) - { - if (bMasterFirst) - { - fX = this.SplitPosition; - } - else - { - fX = width - (this.SplitPosition + this.SplitWidth); - } - } - else - { - fX = 0 - this.SplitWidth; - } - fX -= fRadius; - fY = oMainRect.Top; - oLeadingRect = new RectangleF (fX, fY, fCornersWidth, fCornersHeight); // top corners - oTrailingRect = new RectangleF (fX, (height - fCornersHeight) + oMainRect.Top, fCornersWidth, fCornersHeight); // bottom corners - - } - else - { - // top/bottom split - fX = 0; - fY = 0; - if(bShouldShowMaster) - { - if(bMasterFirst) - { - fY = this.SplitPosition; - } - else - { - fY = height - (this.SplitPosition + this.SplitWidth); - } - } - else - { - fY = 0 - this.SplitWidth; - } - fY -= fRadius; - fY += oMainRect.Top; - fCornersWidth = fRadius; - fCornersHeight = (fRadius * 2.0f) + this.SplitWidth; - oLeadingRect = new RectangleF (fX, fY, fCornersWidth, fCornersHeight); // left corners - oTrailingRect = new RectangleF ((width - fCornersWidth), fY, fCornersWidth, fCornersHeight); // right corners - } - - oLeadingCorners.Frame = oLeadingRect; - oTrailingCorners.Frame = oTrailingRect; - - // Ensure corners are visible and frontmost. - if (this.DetailViewController != null) - { - if (oLeadingCorners.Superview == null) - { - this.View.InsertSubviewAbove (oLeadingCorners, this.DetailViewController.View); - this.View.InsertSubviewAbove (oTrailingCorners, this.DetailViewController.View); - } - else - { - this.View.BringSubviewToFront (oLeadingCorners); - this.View.BringSubviewToFront (oTrailingCorners); - } - } - - if(this.DividerView != null && this.DividerView.Superview != null) - { - this.DividerView.Superview.BringSubviewToFront(this.DividerView); - } - } - - /// - /// Reconfigures the controller to show master controller in a popover or as a real pane. - /// - /// - /// B in popover. - /// - private void ReconfigureForMasterInPopover (bool bInPopover) - { - this.bReconfigurePopup = false; - - // Check if the user actually wants the master to be put into a popover. - if(!this.AutoProvidePopoverAndBarItem) - { - return; - } - - if ((bInPopover && this.HiddenPopoverController != null) - || (!bInPopover && this.HiddenPopoverController == null) || this.MasterViewController == null) - { - // Nothing to do. - return; - } - - if (bInPopover && this.HiddenPopoverController == null && this.BarButtonItem == null) - { - // Create and configure popover for our masterViewController. - if(this.HiddenPopoverController != null) - { - this.HiddenPopoverController.Dispose (); - } - this.HiddenPopoverController = null; - - this.MasterViewController.ViewWillDisappear (false); - this.HiddenPopoverController = new UIPopoverController (this.MasterViewController); - this.MasterViewController.ViewDidDisappear (false); - - // Create and configure UIBarButtonItem. - this.BarButtonItem = new UIBarButtonItem ("Master", UIBarButtonItemStyle.Bordered, this.ShowMasterPopover); - - // Inform delegate of this state of affairs. - if (this.WillHideViewController != null) - { - this.WillHideViewController (this, this.MasterViewController, this.BarButtonItem, this.HiddenPopoverController); - } - } - else if (!bInPopover && this.HiddenPopoverController != null && this.BarButtonItem != null) - { - // I know this looks strange, but it fixes a bizarre issue with UIPopoverController leaving masterViewController's views in disarray. - this.HiddenPopoverController.PresentFromRect (RectangleF.Empty, this.View, UIPopoverArrowDirection.Any, false); - - // Remove master from popover and destroy popover, if it exists. - this.HiddenPopoverController.Dismiss (false); - this.HiddenPopoverController.Dispose (); - this.HiddenPopoverController = null; - - // Inform delegate that the _barButtonItem will become invalid. - if (this.WillShowViewController != null) - { - this.WillShowViewController (this, this.MasterViewController, this.BarButtonItem); - } - - // Destroy _barButtonItem. - if(this.BarButtonItem != null) - { - this.BarButtonItem.Dispose (); - } - this.BarButtonItem = null; - - // Move master view. - UIView masterView = this.MasterViewController.View; - if (masterView != null && masterView.Superview != this.View) - { - masterView.RemoveFromSuperview (); - } - } - } - - private void PopoverControllerDidDismissPopover (UIPopoverController popoverController) - { - this.ReconfigureForMasterInPopover (false); - } - - /// - /// Toggles the split orientation. - /// - public virtual void ToggleSplitOrientation () - { - bool bShowingMaster = this.IsShowingMaster; - if (bShowingMaster) - { - if (this.CornerViews != null) - { - foreach (UIView oCorner in this.CornerViews) - { - oCorner.Hidden = true; - } - this.DividerView.Hidden = true; - } - UIView.Animate(0.1f, delegate - { - this.IsVertical = !this.IsVertical; - }, - delegate - { - foreach (UIView oCorner in this.CornerViews) - { - oCorner.Hidden = false; - } - this.DividerView.Hidden = false; - }); - } - } - - /// - /// Toggles the master before detail. - /// - public void ToggleMasterBeforeDetail () - { - bool bShowingMaster = this.IsShowingMaster; - if (bShowingMaster) - { - if (this.CornerViews != null) - { - foreach (UIView oCorner in this.CornerViews) - { - oCorner.Hidden = true; - } - this.DividerView.Hidden = true; - } - UIView.Animate(0.1f, delegate - { - this.MasterBeforeDetail = !this.MasterBeforeDetail; - }, - delegate - { - foreach (UIView oCorner in this.CornerViews) - { - oCorner.Hidden = false; - } - this.DividerView.Hidden = false; - }); - } - } - - /// - /// Toggles the visibility of the master view. - /// - public virtual void ToggleMasterView () - { - if (this.HiddenPopoverController != null && this.HiddenPopoverController.PopoverVisible) - { - this.HiddenPopoverController.Dismiss (false); - } - - if (!this.IsShowingMaster) - { - // We're about to show the master view. Ensure it's in place off-screen to be animated in. - this.bReconfigurePopup = true; - this.ReconfigureForMasterInPopover (false); - this.LayoutSubviews (); - } - - // This action functions on the current primary orientation; it is independent of the other primary orientation. - UIView.BeginAnimations ("toggleMaster"); - if (this.IsLandscape) - { - this.ShowsMasterInLandscape = !this.ShowsMasterInLandscape; - } - else - { - this.ShowsMasterInPortrait = !this.ShowsMasterInPortrait; - } - UIView.CommitAnimations (); - } - - /// - /// Called from the bar button item to show the master controller in a popover. - /// - public void ShowMasterPopover (object sender, EventArgs args) - { - if (this.HiddenPopoverController != null && !this.HiddenPopoverController.PopoverVisible) - { - // Inform delegate. - if (this.WillPresentViewController != null) - { - this.WillPresentViewController (this, this.HiddenPopoverController, this.MasterViewController); - } - // Show popover. - this.HiddenPopoverController.PresentFromBarButtonItem (this.BarButtonItem, UIPopoverArrowDirection.Any, true); - } - } - } -} \ No newline at end of file diff --git a/README b/README.md similarity index 75% rename from README rename to README.md index fefbe37..65b930b 100644 --- a/README +++ b/README.md @@ -5,13 +5,11 @@ MTSplitViewController is a replacement for UISplitViewController, with various u It is a 1:1 port of Matt Gemmell's brilliant MGSplitViewController (https://github.com/mattgemmell/MGSplitViewController) I needed a substitute for the limited UISplitViewController and read a lot about MGSplitViewController on the web. -Unfortunately, the code was ObjectiveC only. There are bindings available to use the ObjC version in Monotouch but I don't like -dealing with Xcode and I don't like dealing external bindings, so I decided to port the whole thing over to Monotouch. +Unfortunately, the code was ObjectiveC only. There are bindings available to use the ObjC version in Monotouch but I don't like dealing with Xcode and I don't like dealing external bindings, so I decided to port the whole thing over to Monotouch. -This code has been tested with Monodevelop 2.8 and Monotouch 4.2 on the iOS simulator and on an iPad 2. +This code has been tested with Xamarin Studio 5.8.2 and Xamarin.iOS 8.8.2.4 on the iOS simulator. -You can use the code in private or commercial applications without limitations from my side, however I would be happy -to receive information or a screenshot of the application you built. +You can use the code in private or commercial applications without limitations from my side, however I would be happy to receive information or a screenshot of the application you built. Donations --------- @@ -20,37 +18,29 @@ If you find this code useful please donate to Matt Gemmell, as he is the origina A Paypal donation (or something from his Amazon.co.uk Wishlist) would be very much appreciated. Appropriate links can be found here: - Features -------- Please note that, since split-views are commonly used for "Master-Detail" interfaces, I call the first sub-view the "master" and the second sub-view the "detail". -- Unlike MGSplitViewController, the Monotouch implementation does not mimic the delegate interface but instead - offers C# events to attach to UI changes. +- Unlike MGSplitViewController, the Xamarin implementation does not mimic the delegate interface but instead offers C# events to attach to UI changes. - MTSplitViewController is not limited to iPad use only but will (with some code changes involved, like removing the iPad only UIPopoverController) work on iPhone. - MTSplitViewController mimics the appearance and (complete) behaviour of UISplitViewController. It accepts two UIViewControllers (or subclasses thereof). -- Allows toggling the visibility of the master view in either interface-orientation; - i.e. you can have master-detail or detail-only in either landscape and/or portrait orientations (independently, and/or interactively). -- Allows choosing whether the split orientation is vertical (i.e. left/right, like UISplitViewController), - or horizontal (master above, and detail below). You can toggle between modes interactively, with animation. -- Allows choosing whether the master view is before (above, or to left of) the detail view, - or after it (below, or to the right). +- Allows toggling the visibility of the master view in either interface-orientation; i.e. you can have master-detail or detail-only in either landscape and/or portrait orientations (independently, and/or interactively). +- Allows choosing whether the split orientation is vertical (i.e. left/right, like UISplitViewController), or horizontal (master above, and detail below). You can toggle between modes interactively, with animation. +- Allows choosing whether the master view is before (above, or to left of) the detail view, or after it (below, or to the right). - Allows you to choose (and change) the position of the split, i.e. the relative sizes of the master and detail views. -- Allows you to enable dragging of the split/divider between the master and detail views, - with optional constraining via a delegate method. +- Allows you to enable dragging of the split/divider between the master and detail views, with optional constraining via a delegate method. - Allows you to choose the width of the split between the master and detail views. - Preset divider styles: one for non-draggable UISplitViewController-like dividers, and one for draggable, thicker style with a grip-strip. - Allows you to substitute your own divider-view (an MTSplitDividerView subclass), used to draw the split between the master and detail views. - How to use ---------- -This Monodevelop 2.8 project contains a XIB free example of how to use the controller. - +This Xamarin project contains a XIB free example of how to use the controller. Interface Builder support ------------------------- @@ -67,15 +57,13 @@ You're welcome to use it in commercial, closed-source, open source, free or any The MTSplitViewController code comes with no warranty of any kind. I hope it'll be useful to you (it certainly is to me), but I make no guarantees regarding its functionality or otherwise. - Support / Contact / Bugs / Features ----------------------------------- Please email me about issues or bugs or just to say thanks if you find the code useful. If you create an app which uses the code, I'd also love to hear about it. -Likewise, if you want to submit a feature request or bug report, feel free to get in touch. Better yet, -fork the code and implement the feature/fix yourself, then submit a pull request. +Likewise, if you want to submit a feature request or bug report, feel free to get in touch. Better yet, fork the code and implement the feature/fix yourself, then submit a pull request. Enjoy the code!