diff --git a/Demo/Demo.csproj b/Demo/Demo.csproj index ae068f4..4cb1569 100644 --- a/Demo/Demo.csproj +++ b/Demo/Demo.csproj @@ -3,8 +3,6 @@ Debug iPhoneSimulator - 8.0.30703 - 2.0 {3AB2BCA1-4E9C-44FD-81AD-5B8F2B4F6BE0} {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} Exe diff --git a/Demo/TableViewCellDemo.cs b/Demo/TableViewCellDemo.cs index 722927c..b9d2732 100644 --- a/Demo/TableViewCellDemo.cs +++ b/Demo/TableViewCellDemo.cs @@ -26,7 +26,7 @@ public override void ViewDidLoad() { var item = new Item(); item.Title = string.Format("Item {0}", i+1); - item.Total = r.Next(1000); + item.Total = r.Next(999)+1; item.Count = r.Next(item.Total); _items.Add(item); } @@ -125,7 +125,7 @@ public DemoTableViewCell() : base(UITableViewCellStyle.Default, "DemoTableViewCe BackgroundColor = UIColor.Clear, TextColor = UIColor.FromRGB(51,102,153), HighlightedTextColor = UIColor.White, - Font = UIFont.BoldSystemFontOfSize(24), + Font = UIFont.BoldSystemFontOfSize(20), TextAlignment = UITextAlignment.Right, }, LayoutParameters = new LayoutParameters() diff --git a/Demo/TableViewCellDemo2.cs b/Demo/TableViewCellDemo2.cs index e828c05..69bb4fc 100644 --- a/Demo/TableViewCellDemo2.cs +++ b/Demo/TableViewCellDemo2.cs @@ -34,7 +34,7 @@ public override void ViewDidLoad() { var item = new Item(); item.Title = string.Format("Item {0}", i+1); - item.Total = r.Next(1000); + item.Total = r.Next(999) + 1; item.Count = r.Next(item.Total); item.LongText = messages[r.Next(messages.Length)]; _items.Add(item); @@ -155,7 +155,7 @@ public DemoTableViewCell() : base(UITableViewCellStyle.Default, "DemoTableViewCe BackgroundColor = UIColor.Clear, TextColor = UIColor.FromRGB(51,102,153), HighlightedTextColor = UIColor.White, - Font = UIFont.BoldSystemFontOfSize(24), + Font = UIFont.BoldSystemFontOfSize(20), TextAlignment = UITextAlignment.Right, }, LayoutParameters = new LayoutParameters() diff --git a/XibFree/LinearLayout.cs b/XibFree/LinearLayout.cs index b804b26..f38c2bc 100644 --- a/XibFree/LinearLayout.cs +++ b/XibFree/LinearLayout.cs @@ -367,7 +367,16 @@ void LayoutVertical(CGRect newPosition) // Hide hidden views if (v.Gone) { - v.Layout(CGRect.Empty, false); + try + { + v.Layout(CGRect.Empty, false); + } + catch + { + // mmuegel: see exception when Visibility=Gone initially; could + // not figure it out, so this *appears* to be hack work around + System.Diagnostics.Debug.WriteLine("error laying out Gone view " + v); + } continue; } @@ -397,9 +406,12 @@ void LayoutVertical(CGRect newPosition) x = newPosition.Right - Padding.Right - v.LayoutParameters.Margins.Right - size.Width; break; - case Gravity.CenterHorizontal: - x = (newPosition.Left + newPosition.Right)/2 - - (size.Width + v.LayoutParameters.Margins.TotalWidth())/2; + case Gravity.CenterHorizontal: + nfloat boxWidth = newPosition.Right - newPosition.Left - + Padding.TotalWidth() - v.LayoutParameters.Margins.TotalWidth(); + nfloat offsetInBox = (boxWidth - size.Width)/2; + x = newPosition.Left + Padding.Left + v.LayoutParameters.Margins.Left + + offsetInBox; break; } @@ -494,13 +506,13 @@ private nfloat getTotalSpacing() // Helper to get the total measured height of all subviews, including all padding and margins private nfloat getTotalMeasuredHeight() { - return (nfloat)(Padding.TotalWidth() + getTotalSpacing() + SubViews.Where(x=>!x.Gone).Sum(x=>x.GetMeasuredSize().Height + x.LayoutParameters.Margins.TotalHeight())); + return (nfloat)(Padding.TotalHeight() + getTotalSpacing() + SubViews.Where(x=>!x.Gone).Sum(x=>x.GetMeasuredSize().Height + x.LayoutParameters.Margins.TotalHeight())); } // Helper to get the total measured width of all subviews, including all padding and margins private nfloat getTotalMeasuredWidth() { - return (nfloat)(Padding.TotalHeight() + getTotalSpacing() + SubViews.Where(x=>!x.Gone).Sum(x=>x.GetMeasuredSize().Width + x.LayoutParameters.Margins.TotalWidth())); + return (nfloat)(Padding.TotalWidth() + getTotalSpacing() + SubViews.Where(x=>!x.Gone).Sum(x=>x.GetMeasuredSize().Width + x.LayoutParameters.Margins.TotalWidth())); } // Helper to adjust the parent width passed down to subviews during measurement diff --git a/XibFree/PublicExtensions.cs b/XibFree/PublicExtensions.cs index fea7939..de8fcb4 100644 --- a/XibFree/PublicExtensions.cs +++ b/XibFree/PublicExtensions.cs @@ -16,6 +16,7 @@ using System; using UIKit; +using System.Collections.Generic; namespace XibFree { @@ -47,5 +48,87 @@ public static View GetLayoutRoot(this UIView view) var host = view.GetLayoutHost(); return host.Layout; } + + /// + /// Returns the top-level ViewGroup that this view is + /// a part of. Returns null if it is not under a group + /// yet. If view is the root, it is returned. + /// + public static ViewGroup FindRootGroup(this View view) + { + if (view.Parent == null && view is ViewGroup) + { + return (ViewGroup)view; + } + + ViewGroup parent = null; + while (view.Parent != null) + { + view = parent = view.Parent; + } + return parent; + } + + /// + /// Returns the top-level UIView that this view is being hosted under. + /// Returns null if not hosted. + /// + public static UIView FindRootUIView(this View view) + { + return FindRootGroup(view)?.GetHost()?.GetUIView(); + } + + /// + /// Returns the nearest parent ViewGroup that this view is + /// a part of. Returns null if it is not under a group + /// yet. Returns the view passed if it is actually a + /// ViewGroup. + /// + public static ViewGroup FindNearestGroup(this View view) + { + while (true) + { + if (view is ViewGroup) + { + return (ViewGroup)view; + } + view = view.Parent; + if (view == null) + { + return null; + } + } + } + + /// + /// Returns the UIView associated with nearest parent ViewGroup + /// that this view is a part of. Returns null if it is not under + /// a group yet. Returns the UIView for the view passed if it is + /// actually a ViewGroup. + /// + public static UIView FindNearestGroupUIView(this View view) + { + return view.FindNearestGroup()?.GetHost()?.GetUIView(); + } + + /// + /// Returns all UIViews at or under the passed view. + /// + public static IEnumerable FindUIViews(this View view) + { + var views = new List(); + if (view is NativeView) + { + views.Add((view as NativeView).View); + } + else if (view is ViewGroup) + { + foreach (var child in (view as ViewGroup).SubViews) + { + views.AddRange(FindUIViews(child)); + } + } + return views; + } } -} +} \ No newline at end of file diff --git a/XibFree/UILayoutHost.cs b/XibFree/UILayoutHost.cs index 92ec1b9..3dae7f0 100644 --- a/XibFree/UILayoutHost.cs +++ b/XibFree/UILayoutHost.cs @@ -17,6 +17,7 @@ using System; using UIKit; using CoreGraphics; +using System.Diagnostics; namespace XibFree { @@ -99,10 +100,17 @@ public override void LayoutSubviews() { if (_layout!=null) { - // Remeasure - _layout.Measure(Bounds.Width, Bounds.Height); - // Apply layout - _layout.Layout(Bounds, false); + try + { + // Remeasure + _layout.Measure(Bounds.Width, Bounds.Height); + // Apply layout + _layout.Layout(Bounds, false); + } + catch (Exception ex) + { + Trace.WriteLine("XibFree LayoutSubviews error: " + ex.Message); + } } } diff --git a/XibFree/View.cs b/XibFree/View.cs index a01a92d..20e1242 100644 --- a/XibFree/View.cs +++ b/XibFree/View.cs @@ -18,6 +18,7 @@ using UIKit; using CoreGraphics; using CoreAnimation; +using System.Diagnostics; namespace XibFree { @@ -75,7 +76,7 @@ public virtual LayoutParameters LayoutParameters } // Internal helper to walk the parent view hierachy and find the view that's hosting this view hierarchy - internal virtual ViewGroup.IHost GetHost() + public virtual ViewGroup.IHost GetHost() { if (_parent==null) return null; @@ -100,7 +101,14 @@ internal virtual void onDetach() /// The new position of this view public void Layout(CGRect newPosition, bool parentHidden) { - onLayout(newPosition, parentHidden); + try + { + onLayout(newPosition, parentHidden); + } + catch (Exception ex) + { + Trace.WriteLine("XibFree Layout error: " + ex.Message); + } } /// @@ -224,7 +232,68 @@ public bool Visible LayoutParameters.Visibility = value ? Visibility.Visible : Visibility.Invisible; } } + + public void Hide(bool collapsed, bool animate) + { + if (LayoutParameters.Visibility != Visibility.Visible) + { + // Already hidden or in progress + // Console.WriteLine("Skipping Hide: already hidden"); + return; + } + LayoutParameters.Visibility = (collapsed) ? Visibility.Gone : Visibility.Invisible; + ShowHide(false, animate); + } + public void Show(bool animate) + { + if (LayoutParameters.Visibility == Visibility.Visible) + { + // Already visible or in progress + // Console.WriteLine("Skipping Show: already shown"); + return; + } + LayoutParameters.Visibility = Visibility.Visible; + ShowHide(true, animate); + } + + public void SetVisibility(bool visible, bool animate) + { + if (visible) + Show(animate); + else + Hide(true, animate); + } + + public void SetVisibility(Visibility visibility, bool animate) + { + if (LayoutParameters.Visibility != visibility) + { + LayoutParameters.Visibility = visibility; + ShowHide(visibility == Visibility.Visible, animate); + } + } + + private void ShowHide(bool show, bool animate) + { + //Console.WriteLine("ShowHide(show=" + show + ",animate=" + animate + ")"); + double delay = animate ? 0.25f : 0.0; + //double delay = 0; + var root = this.FindRootUIView(); + UIView.AnimateNotify(delay, delegate + { + foreach (var uiview in this.FindUIViews()) + { + uiview.Alpha = (show) ? 1.0f : 0.0f; + } + }, (bool completed) => + { + //Console.WriteLine("completed=" + completed); + //root?.Superview?.SetNeedsLayout(); + root?.SetNeedsLayout(); + }); + } + public void RemoveFromSuperview() { if (Parent!=null) diff --git a/XibFree/ViewGroup.cs b/XibFree/ViewGroup.cs index 602282f..c852d9f 100644 --- a/XibFree/ViewGroup.cs +++ b/XibFree/ViewGroup.cs @@ -49,6 +49,9 @@ public IEnumerable SubViews } set { + // Skip null views + value = value.Where(v => v != null); + // Check none of the child already have parents foreach (var c in value) { @@ -67,7 +70,7 @@ public IEnumerable SubViews } /// - /// Insert a new subview at a specified position + /// Insert a new native subview at a specified position /// /// Zero-based index of where to insert the new subview. /// The native subview to insert. @@ -78,7 +81,7 @@ public void InsertSubView(int position, UIView view, LayoutParameters lp) } /// - /// Insert a new subview at the end of the subview collection + /// Insert a new native subview at the end of the subview collection /// /// The native subview to insert. /// Layout parameters for the subview. @@ -88,7 +91,7 @@ public void AddSubView(UIView view, LayoutParameters lp) } /// - /// Insert a new subview at the end of the subview collection + /// Insert a new Xib subview at the end of the subview collection /// /// The subview to add public void AddSubView(View view) @@ -97,7 +100,7 @@ public void AddSubView(View view) } /// - /// Remove a subview from the subview collection + /// Remove a native subview from the subview collection /// /// The subview to remove. public void RemoveSubView(UIView view) @@ -113,7 +116,7 @@ public void RemoveSubView(UIView view) } /// - /// Insert a new subview at a specified position + /// Insert a new Xib subview at a specified position /// /// Zero-based index of where to insert the new subview. /// The subview to add. @@ -129,7 +132,7 @@ public void InsertSubView(int position, View view) } /// - /// Remove the specified subview + /// Remove the specified Xib subview /// /// The subview to remove public void RemoveSubView(View view) @@ -138,7 +141,7 @@ public void RemoveSubView(View view) } /// - /// Remove the subview at a specified position + /// Remove the Xib subview at a specified position /// /// The zero-based index of the view to remove. public void RemoveSubViewAt(int index) @@ -191,7 +194,7 @@ public void SetHost(IHost host) /// Overridden to locate the parent host for this view hierarchy /// /// The host. - internal override ViewGroup.IHost GetHost() + public override ViewGroup.IHost GetHost() { // If this view group has been parented into an actual UIView, we'll have a IHost reference // that acts as the host for all views in the hierarchy. If not, ask our parent diff --git a/XibFree/XibFree.csproj b/XibFree/XibFree.csproj index e5db645..4f8be01 100644 --- a/XibFree/XibFree.csproj +++ b/XibFree/XibFree.csproj @@ -3,8 +3,6 @@ Debug AnyCPU - 8.0.30703 - 2.0 {3CAF9EB6-5E29-40E2-8798-2DE909310CBE} {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} Library @@ -23,6 +21,8 @@ prompt 4 false + true + true true @@ -32,7 +32,11 @@ false - + + AfterBuild + cp ${TargetFile} ${SolutionDir}/out + + true