public class ShellTableViewController : UITableViewController
{
readonly IShellContext _context;
- readonly UIView _headerView;
+ readonly UIContainerView _headerView;
readonly ShellTableViewSource _source;
- double _headerMax = 200;
- double _headerMin = 44;
+ double _headerMin = 56;
double _headerOffset = 0;
double _headerSize;
- public ShellTableViewController(IShellContext context, UIView headerView, Action<Element> onElementSelected)
+ public ShellTableViewController(IShellContext context, UIContainerView headerView, Action<Element> onElementSelected)
{
- if (headerView == null)
- {
- _headerMax = 20;
- _headerMin = 0;
- }
-
- _headerSize = _headerMax;
_context = context;
_headerView = headerView;
_source = new ShellTableViewSource(context, onElementSelected);
_source.ScrolledEvent += OnScrolled;
-
+ _headerView.HeaderSizeChanged += OnHeaderSizeChanged;
((IShellController)_context.Shell).StructureChanged += OnStructureChanged;
}
+
+ void OnHeaderSizeChanged(object sender, EventArgs e)
+ {
+ _headerSize = HeaderMax;
+ TableView.ContentInset = new UIEdgeInsets((nfloat)HeaderMax + SafeAreaOffset, 0, 0, 0);
+ LayoutParallax();
+ }
void OnStructureChanged(object sender, EventArgs e)
{
public void LayoutParallax()
{
+ if (TableView?.Superview == null)
+ return;
+
var parent = TableView.Superview;
TableView.Frame = parent.Bounds.Inset(0, SafeAreaOffset);
if (_headerView != null)
{
_headerView.Frame = new CGRect(0, _headerOffset + SafeAreaOffset, parent.Frame.Width, _headerSize);
- if (_headerOffset < 0 && _headerSize + _headerOffset >= 0)
+ var headerHeight = Math.Max(_headerMin, _headerSize + _headerOffset);
+ if (_headerOffset < 0)
{
CAShapeLayer shapeLayer = new CAShapeLayer();
- CGRect rect = new CGRect(0, _headerOffset * -1, parent.Frame.Width, _headerSize + _headerOffset);
+ CGRect rect = new CGRect(0, _headerOffset * -1, parent.Frame.Width, headerHeight);
var path = CGPath.FromRect(rect);
shapeLayer.Path = path;
_headerView.Layer.Mask = shapeLayer;
public override void ViewDidLoad()
{
base.ViewDidLoad();
+ _headerView.MeasureIfNeeded();
TableView.SeparatorStyle = UITableViewCellSeparatorStyle.None;
if (Forms.IsiOS11OrNewer)
TableView.ContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.Never;
- TableView.ContentInset = new UIEdgeInsets((nfloat)_headerMax + SafeAreaOffset, 0, 0, 0);
+ TableView.ContentInset = new UIEdgeInsets((nfloat)HeaderMax + SafeAreaOffset, 0, 0, 0);
TableView.Source = _source;
}
{
if ((_context?.Shell as IShellController) != null)
((IShellController)_context.Shell).StructureChanged -= OnStructureChanged;
+
+ if(_source != null)
+ _source.ScrolledEvent -= OnScrolled;
+
+ if(_headerView != null)
+ _headerView.HeaderSizeChanged -= OnHeaderSizeChanged;
}
base.Dispose(disposing);
}
+
void OnScrolled(object sender, UIScrollView e)
{
var headerBehavior = _context.Shell.FlyoutHeaderBehavior;
{
case FlyoutHeaderBehavior.Default:
case FlyoutHeaderBehavior.Fixed:
- _headerSize = _headerMax;
+ _headerSize = HeaderMax;
break;
case FlyoutHeaderBehavior.Scroll:
- _headerSize = _headerMax;
- _headerOffset = Math.Min(0, -(_headerMax + e.ContentOffset.Y));
+ _headerSize = HeaderMax;
+ _headerOffset = Math.Min(0, -(HeaderMax + e.ContentOffset.Y));
break;
case FlyoutHeaderBehavior.CollapseOnScroll:
- _headerSize = Math.Max(_headerMin, Math.Min(_headerMax, _headerMax - e.ContentOffset.Y - _headerMax));
+ _headerSize = Math.Max(_headerMin, Math.Min(HeaderMax, HeaderMax - e.ContentOffset.Y - HeaderMax));
break;
}
}
float SafeAreaOffset => (float)Platform.SafeAreaInsetsForWindow.Top;
+ double HeaderMax => _headerView.MeasuredHeight;
}
}
\ No newline at end of file
-using CoreGraphics;
+using System;
+using CoreGraphics;
using UIKit;
namespace Xamarin.Forms.Platform.iOS
readonly View _view;
IVisualElementRenderer _renderer;
bool _disposed;
+ internal event EventHandler HeaderSizeChanged;
public UIContainerView(View view)
{
Platform.SetRenderer(view, _renderer);
AddSubview(_renderer.NativeView);
+ ClipsToBounds = true;
+ view.MeasureInvalidated += OnMeasureInvalidated;
+ MeasuredHeight = double.NaN;
+ }
+
+ internal double MeasuredHeight { get; private set; }
+
+ internal bool MeasureIfNeeded()
+ {
+ if (double.IsNaN(MeasuredHeight))
+ {
+ ReMeasure();
+ return true;
+ }
+ return false;
+ }
+
+ void ReMeasure()
+ {
+ var request = _view.Measure(Frame.Width, double.PositiveInfinity, MeasureFlags.IncludeMargins);
+ Layout.LayoutChildIntoBoundingRegion(_view, new Rectangle(0, 0, Frame.Width, request.Request.Height));
+ MeasuredHeight = request.Request.Height;
+ HeaderSizeChanged?.Invoke(this, EventArgs.Empty);
+ }
+
+ void OnMeasureInvalidated(object sender, System.EventArgs e)
+ {
+ ReMeasure();
}
public override void LayoutSubviews()
{
- _view.Layout(Bounds.ToRectangle());
+ if(!MeasureIfNeeded())
+ _view.Layout(Bounds.ToRectangle());
}
protected override void Dispose(bool disposing)