public DetailsPage(MasterDetailPage masterDetailPage)
{
MDP = masterDetailPage;
- lblThings = new Label();
+ lblThings = new Label() { HorizontalTextAlignment = TextAlignment.Center, AutomationId = "CurrentMasterBehavior" };
+
Content = new StackLayout()
{
Children =
new Button()
{
Text = "Click to rotate through MasterBehavior settings and test each one",
- Command = new Command(OnChangeMasterBehavior)
+ Command = new Command(OnChangeMasterBehavior),
+ AutomationId = "ChangeMasterBehavior"
},
new Button()
{
}
});
})
- }
+ },
+ new Label(){ HorizontalTextAlignment = TextAlignment.Center, Text = "Close Master" }
}
};
RunningApp.WaitForElement("Master Visible");
}
+ [Test]
+ public void SplitOnLandscapeFailsToDetectClose()
+ {
+ if (!RunningApp.IsTablet())
+ return;
+
+ while(RunningApp.WaitForElement("CurrentMasterBehavior")[0].ReadText() != MasterBehavior.SplitOnLandscape.ToString())
+ {
+ RunningApp.Tap("ChangeMasterBehavior");
+
+ if(RunningApp.Query("Master Visible").Length > 0)
+ RunningApp.Tap("Close Master");
+ }
+
+ RunningApp.Tap("Master");
+ RunningApp.WaitForElement("Master Visible");
+ RunningApp.Tap("Close Master");
+
+ RunningApp.SetOrientationLandscape();
+ RunningApp.SetOrientationPortrait();
+ RunningApp.SetOrientationLandscape();
+ RunningApp.SetOrientationPortrait();
+
+ if (RunningApp.Query("Master Visible").Length > 0)
+ RunningApp.Tap("Close Master");
+
+ RunningApp.Tap("Master");
+ RunningApp.WaitForElement("Master Visible");
+ RunningApp.Tap("Close Master");
+ RunningApp.Tap("Master");
+ RunningApp.WaitForElement("Master Visible");
+ }
+
[TearDown]
public override void TearDown()
{
internal class EventedViewController : ChildViewController
{
- public override void ViewWillDisappear(bool animated)
+ MasterView _masterView;
+
+ event EventHandler _didAppear;
+ event EventHandler _willDisappear;
+
+ public EventedViewController()
{
- base.ViewWillDisappear(animated);
+ _masterView = new MasterView();
+ }
+
- WillDisappear?.Invoke(this, EventArgs.Empty);
+ public event EventHandler DidAppear
+ {
+ add
+ {
+ _masterView.DidAppear += value;
+ _didAppear += value;
+ }
+ remove
+ {
+ _masterView.DidAppear -= value;
+ _didAppear -= value;
+ }
+ }
+
+ public event EventHandler WillDisappear
+ {
+ add
+ {
+ _masterView.WillDisappear += value;
+ _willDisappear += value;
+ }
+ remove
+ {
+ _masterView.WillDisappear -= value;
+ _willDisappear -= value;
+ }
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
+ _didAppear?.Invoke(this, EventArgs.Empty);
+ }
- DidAppear?.Invoke(this, EventArgs.Empty);
+ public override void ViewWillDisappear(bool animated)
+ {
+ base.ViewWillDisappear(animated);
+ _willDisappear?.Invoke(this, EventArgs.Empty);
}
- public event EventHandler DidAppear;
+ public override void ViewDidDisappear(bool animated)
+ {
+ base.ViewDidDisappear(animated);
+ _willDisappear?.Invoke(this, EventArgs.Empty);
+ }
- public event EventHandler WillDisappear;
+ public override void LoadView()
+ {
+ View = _masterView;
+ }
+
+ public class MasterView : UIView
+ {
+ public bool IsCollapsed => Center.X <= 0;
+ bool _previousIsCollapsed = true;
+
+ public event EventHandler DidAppear;
+ public event EventHandler WillDisappear;
+
+ // this only gets called on iOS12 everytime it's collapsed or expanded
+ // I haven't found an override on iOS13 that gets called but it doesn't seem
+ // to matter because the DidAppear and WillDisappear seem more consistent on iOS 13
+ public override void LayoutSubviews()
+ {
+ base.LayoutSubviews();
+ UpdateCollapsedSetting();
+ }
+
+ void UpdateCollapsedSetting()
+ {
+ if (_previousIsCollapsed != IsCollapsed)
+ {
+ _previousIsCollapsed = IsCollapsed;
+
+ if (IsCollapsed)
+ WillDisappear?.Invoke(this, EventArgs.Empty);
+ else
+ DidAppear?.Invoke(this, EventArgs.Empty);
+ }
+ }
+ }
}
public class TabletMasterDetailRenderer : UISplitViewController, IVisualElementRenderer, IEffectControlProvider
nfloat _masterWidth = 0;
EventedViewController _masterController;
MasterDetailPage _masterDetailPage;
- bool _masterVisible;
VisualElementTracker _tracker;
+ CGSize _previousSize = CGSize.Empty;
+ CGSize _previousViewDidLayoutSize = CGSize.Empty;
+ UISplitViewControllerDisplayMode _previousDisplayMode = UISplitViewControllerDisplayMode.Automatic;
Page PageController => Element as Page;
Element ElementController => Element as Element;
+ bool IsMasterVisible => !(_masterController?.View as EventedViewController.MasterView).IsCollapsed;
protected MasterDetailPage MasterDetailPage => _masterDetailPage ?? (_masterDetailPage = (MasterDetailPage)Element);
if (_masterController != null)
{
- _masterController.DidAppear -= MasterControllerWillAppear;
+ _masterController.DidAppear -= MasterControllerDidAppear;
_masterController.WillDisappear -= MasterControllerWillDisappear;
}
UpdateControllers();
- _masterController.DidAppear += MasterControllerWillAppear;
+ _masterController.DidAppear += MasterControllerDidAppear;
_masterController.WillDisappear += MasterControllerWillDisappear;
PresentsWithGesture = MasterDetailPage.IsGestureEnabled;
PageController?.SendDisappearing();
}
+
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
if (!detailsBounds.IsEmpty)
MasterDetailPage.DetailBounds = new Rectangle(0, 0, detailsBounds.Width, detailsBounds.Height);
}
+
+ if (_previousViewDidLayoutSize == CGSize.Empty)
+ _previousViewDidLayoutSize = View.Bounds.Size;
+
+ // Is this being called from a rotation
+ if (_previousViewDidLayoutSize != View.Bounds.Size)
+ {
+ _previousViewDidLayoutSize = View.Bounds.Size;
+
+ // make sure IsPresented matches state of Master View
+ if (MasterDetailPage.CanChangeIsPresented && MasterDetailPage.IsPresented != IsMasterVisible)
+ ElementController.SetValueFromRenderer(MasterDetailPage.IsPresentedProperty, IsMasterVisible);
+ }
+
+ if(_previousDisplayMode != PreferredDisplayMode)
+ {
+ _previousDisplayMode = PreferredDisplayMode;
+
+ // make sure IsPresented matches state of Master View
+ if (MasterDetailPage.CanChangeIsPresented && MasterDetailPage.IsPresented != IsMasterVisible)
+ ElementController.SetValueFromRenderer(MasterDetailPage.IsPresentedProperty, IsMasterVisible);
+ }
}
public override void ViewDidLoad()
return;
bool isPortrait = newBounds.Height > newBounds.Width;
+ var previous = PreferredDisplayMode;
+
switch (masterDetailPage.MasterBehavior)
{
case MasterBehavior.Split:
break;
}
+ if (previous == PreferredDisplayMode)
+ return;
+
if (!MasterDetailPage.ShouldShowSplitMode)
MasterDetailPage.CanChangeIsPresented = true;
MasterDetailPage.UpdateMasterBehavior();
-
- if(MasterDetailPage.CanChangeIsPresented && !MasterDetailPage.ShouldShowSplitMode)
- ElementController.SetValueFromRenderer(MasterDetailPage.IsPresentedProperty, false);
}
public override void ViewWillDisappear(bool animated)
{
- if (_masterVisible && !MasterDetailPage.ShouldShowSplitMode)
+ if (IsMasterVisible && !MasterDetailPage.ShouldShowSplitMode)
PerformButtonSelector();
base.ViewWillDisappear(animated);
// I tested this code on iOS9+ and it's never called
if (!Forms.IsiOS9OrNewer)
{
- if (!MasterDetailPage.ShouldShowSplitMode && _masterVisible)
+ if (!MasterDetailPage.ShouldShowSplitMode && IsMasterVisible)
{
MasterDetailPage.CanChangeIsPresented = true;
PreferredDisplayMode = UISplitViewControllerDisplayMode.PrimaryHidden;
public override void ViewWillTransitionToSize(CGSize toSize, IUIViewControllerTransitionCoordinator coordinator)
{
base.ViewWillTransitionToSize(toSize, coordinator);
- UpdateMasterBehavior(toSize);
+
+ if (_previousSize != toSize)
+ {
+ _previousSize = toSize;
+ UpdateMasterBehavior(toSize);
+ }
}
- void MasterControllerWillAppear(object sender, EventArgs e)
+ void MasterControllerDidAppear(object sender, EventArgs e)
{
- _masterVisible = true;
- if (MasterDetailPage.CanChangeIsPresented)
+ if (MasterDetailPage.CanChangeIsPresented && IsMasterVisible)
ElementController.SetValueFromRenderer(MasterDetailPage.IsPresentedProperty, true);
}
void MasterControllerWillDisappear(object sender, EventArgs e)
{
- _masterVisible = false;
- if (MasterDetailPage.CanChangeIsPresented)
+ if (MasterDetailPage.CanChangeIsPresented && !IsMasterVisible)
ElementController.SetValueFromRenderer(MasterDetailPage.IsPresentedProperty, false);
}
void ToggleMaster()
{
- if (_masterVisible == MasterDetailPage.IsPresented || MasterDetailPage.ShouldShowSplitMode)
+ if (IsMasterVisible == MasterDetailPage.IsPresented || MasterDetailPage.ShouldShowSplitMode)
return;
PerformButtonSelector();