Merge pull request #207 from zumero/listview-subviews

Fixing layouts of Ooui.Forms ViewCells
This commit is contained in:
Frank A. Krueger 2019-01-05 12:23:48 -06:00 committed by GitHub
commit 7fdefa5a58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 116 additions and 1 deletions

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Timers;
using Xamarin.Forms; using Xamarin.Forms;
using Xamarin.Forms.Internals; using Xamarin.Forms.Internals;
using Ooui.Forms.Cells; using Ooui.Forms.Cells;
@ -11,7 +12,18 @@ namespace Ooui.Forms.Renderers
{ {
public class ListViewRenderer : ViewRenderer<ListView, List> public class ListViewRenderer : ViewRenderer<ListView, List>
{ {
const int DefaultRowHeight = 44;
private bool _disposed; private bool _disposed;
IVisualElementRenderer _prototype;
Timer _timer;
int _rowHeight;
public int RowHeight
{
get => _rowHeight;
set => _rowHeight = value;
}
public ListViewRenderer () public ListViewRenderer ()
{ {
@ -32,6 +44,10 @@ namespace Ooui.Forms.Renderers
var list = new List (); var list = new List ();
list.Style.Overflow = "scroll"; list.Style.Overflow = "scroll";
list.Style.Padding = "0"; list.Style.Padding = "0";
// Make the list element positioned so child elements will
// be positioned relative to it. This will allow the list
// to scroll properly.
list.Style.Position = "relative";
SetNativeControl (list); SetNativeControl (list);
} }
@ -40,6 +56,8 @@ namespace Ooui.Forms.Renderers
templatedItems.CollectionChanged += OnCollectionChanged; templatedItems.CollectionChanged += OnCollectionChanged;
e.NewElement.ScrollToRequested += ListView_ScrollToRequested; e.NewElement.ScrollToRequested += ListView_ScrollToRequested;
UpdateRowHeight();
UpdateItems (); UpdateItems ();
UpdateSeparator (); UpdateSeparator ();
UpdateBackgroundColor (); UpdateBackgroundColor ();
@ -53,7 +71,30 @@ namespace Ooui.Forms.Renderers
base.OnElementPropertyChanged (sender, e); base.OnElementPropertyChanged (sender, e);
if (e.PropertyName == ItemsView<Cell>.ItemsSourceProperty.PropertyName) if (e.PropertyName == ItemsView<Cell>.ItemsSourceProperty.PropertyName)
UpdateItems (); UpdateItems();
else if (e.PropertyName == Xamarin.Forms.ListView.RowHeightProperty.PropertyName)
{
UpdateRowHeight();
UpdateItems();
}
else if (e.PropertyName == VisualElement.WidthProperty.PropertyName)
{
if (_timer != null)
{
_timer.Stop();
}
else
{
_timer = new Timer();
_timer.Interval = 250;
_timer.Elapsed += delegate {
UpdateItems();
};
_timer.Enabled = true;
_timer.AutoReset = false;
}
_timer.Start();
}
else if (e.PropertyName == Xamarin.Forms.ListView.SeparatorColorProperty.PropertyName) else if (e.PropertyName == Xamarin.Forms.ListView.SeparatorColorProperty.PropertyName)
UpdateSeparator (); UpdateSeparator ();
else if (e.PropertyName == Xamarin.Forms.ListView.SeparatorVisibilityProperty.PropertyName) else if (e.PropertyName == Xamarin.Forms.ListView.SeparatorVisibilityProperty.PropertyName)
@ -68,6 +109,8 @@ namespace Ooui.Forms.Renderers
if (disposing && !_disposed) { if (disposing && !_disposed) {
ClearPrototype();
if (Element != null) { if (Element != null) {
var templatedItems = TemplatedItemsView.TemplatedItems; var templatedItems = TemplatedItemsView.TemplatedItems;
templatedItems.CollectionChanged -= OnCollectionChanged; templatedItems.CollectionChanged -= OnCollectionChanged;
@ -78,6 +121,17 @@ namespace Ooui.Forms.Renderers
} }
} }
void ClearPrototype()
{
if (_prototype != null)
{
var element = _prototype.Element;
element?.ClearValue(Platform.RendererProperty);
_prototype?.Dispose();
_prototype = null;
}
}
private void OnCollectionChanged (object sender, NotifyCollectionChangedEventArgs e) private void OnCollectionChanged (object sender, NotifyCollectionChangedEventArgs e)
{ {
UpdateItems (); UpdateItems ();
@ -127,11 +181,22 @@ namespace Ooui.Forms.Renderers
} }
else { else {
var i = 0; var i = 0;
double offset = 0;
foreach (var item in items) { foreach (var item in items) {
var li = listItems[i]; var li = listItems[i];
var nativeCell = items[i];
var children = li.Children; var children = li.Children;
var rv = children.Count > 0 ? children[0] as CellElement : null; var rv = children.Count > 0 ? children[0] as CellElement : null;
var cell = GetCell (item, rv); var cell = GetCell (item, rv);
var height = CalculateHeightForCell(nativeCell);
li.Style.Height = height;
var viewCell = (ViewCell)cell.Cell;
if (viewCell != null && viewCell.View != null)
{
var rect = new Rectangle(0, offset, Element.Width, height);
Layout.LayoutChildIntoBoundingRegion(viewCell.View, rect);
}
offset += height;
if (rv == null) { if (rv == null) {
li.AppendChild (cell); li.AppendChild (cell);
} }
@ -188,6 +253,56 @@ namespace Ooui.Forms.Renderers
} }
} }
void UpdateRowHeight()
{
var rowHeight = Element.RowHeight;
if (Element.HasUnevenRows && rowHeight == -1)
RowHeight = -1;
else
RowHeight = rowHeight <= 0 ? DefaultRowHeight : rowHeight;
}
internal double CalculateHeightForCell(Cell cell)
{
if (!Element.HasUnevenRows)
{
return RowHeight;
}
else
{
var viewCell = cell as ViewCell;
if (viewCell != null && viewCell.View != null)
{
var target = viewCell.View;
if (_prototype == null)
_prototype = Platform.CreateRenderer(target);
else
_prototype.SetElement(target);
Platform.SetRenderer(target, _prototype);
var req = target.Measure(Element.Width, double.PositiveInfinity, MeasureFlags.IncludeMargins);
target.ClearValue(Platform.RendererProperty);
foreach (Xamarin.Forms.Element descendant in target.Descendants())
{
IVisualElementRenderer renderer = Platform.GetRenderer(descendant as VisualElement);
// Clear renderer from descendent; this will not happen in Dispose as normal because we need to
// unhook the Element from the renderer before disposing it.
descendant.ClearValue(Platform.RendererProperty);
renderer?.Dispose();
renderer = null;
}
var height = req.Request.Height;
return height > 1 ? height : DefaultRowHeight;
}
var renderHeight = cell.RenderHeight;
return renderHeight > 0 ? renderHeight : DefaultRowHeight;
}
}
void UpdateBackgroundColor () void UpdateBackgroundColor ()
{ {
if (Control == null) if (Control == null)