redraw stack layouts on ios tableviews

This commit is contained in:
Kyle Spearrin 2018-01-03 12:18:15 -05:00
parent fa9e22730a
commit 9456f5dc31
16 changed files with 130 additions and 103 deletions

View file

@ -1,6 +1,4 @@
using Xamarin.Forms;
using XLabs.Ioc;
using Bit.App.Abstractions;
using System;
using System.Reflection;
@ -42,6 +40,7 @@ namespace Bit.App.Controls
public bool NoHeader { get; set; }
public bool NoFooter { get; set; }
public int BottomPadding { get; set; }
public Func<RedrawableStackLayout> WrappingStackLayout { get; set; }
protected override SizeRequest OnSizeRequest(double widthConstraint, double heightConstraint)
{

View file

@ -0,0 +1,27 @@
using System;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class RedrawableStackLayout : StackLayout
{
private DateTime _lastRedraw = DateTime.MinValue;
private TimeSpan _redrawThreshold = TimeSpan.FromMilliseconds(1000);
public async Task RedrawIfNeededAsync(int delay = 0, bool force = false)
{
var now = DateTime.UtcNow;
if(Device.RuntimePlatform == Device.iOS && (force || (now - _lastRedraw) > _redrawThreshold))
{
_lastRedraw = now;
if(delay > 0)
{
await Task.Delay(delay);
}
InvalidateLayout();
}
}
}
}

View file

@ -30,7 +30,7 @@ namespace Bit.App.Pages
public FormEntryCell ApiUrlCell { get; set; }
public FormEntryCell IdentityUrlCell { get; set; }
public FormEntryCell IconsUrlCell { get; set; }
public StackLayout StackLayout { get; set; }
public RedrawableStackLayout StackLayout { get; set; }
public Label SelfHostLabel { get; set; }
public Label CustomLabel { get; set; }
@ -57,7 +57,7 @@ namespace Bit.App.Pages
entryKeyboard: Keyboard.Url);
BaseUrlCell.Entry.Text = _appSettings.BaseUrl;
var table = new FormTableView
var table = new FormTableView(this)
{
Root = new TableRoot
{
@ -74,10 +74,10 @@ namespace Bit.App.Pages
LineBreakMode = LineBreakMode.WordWrap,
FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)),
Style = (Style)Application.Current.Resources["text-muted"],
Margin = new Thickness(15, (this.IsLandscape() ? 5 : 0), 15, 25)
Margin = new Thickness(15, (this.IsLandscape() ? 5 : 0), 15, 5)
};
var table2 = new FormTableView
var table2 = new FormTableView(this)
{
Root = new TableRoot
{
@ -97,10 +97,10 @@ namespace Bit.App.Pages
LineBreakMode = LineBreakMode.WordWrap,
FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)),
Style = (Style)Application.Current.Resources["text-muted"],
Margin = new Thickness(15, (this.IsLandscape() ? 5 : 0), 15, 25)
Margin = new Thickness(15, (this.IsLandscape() ? 5 : 0), 15, 5)
};
StackLayout = new StackLayout
StackLayout = new RedrawableStackLayout
{
Children = { table, SelfHostLabel, table2, CustomLabel },
Spacing = 0
@ -138,7 +138,6 @@ namespace Bit.App.Pages
IdentityUrlCell.InitEvents();
ApiUrlCell.InitEvents();
WebVaultUrlCell.InitEvents();
StackLayout.LayoutChanged += Layout_LayoutChanged;
BaseUrlCell.Entry.FocusWithDelay();
}
protected override void OnDisappearing()
@ -149,13 +148,6 @@ namespace Bit.App.Pages
IdentityUrlCell.Dispose();
ApiUrlCell.Dispose();
WebVaultUrlCell.Dispose();
StackLayout.LayoutChanged -= Layout_LayoutChanged;
}
private void Layout_LayoutChanged(object sender, EventArgs e)
{
SelfHostLabel.WidthRequest = StackLayout.Bounds.Width - SelfHostLabel.Bounds.Left * 2;
CustomLabel.WidthRequest = StackLayout.Bounds.Width - CustomLabel.Bounds.Left * 2;
}
private async Task SaveAsync()
@ -259,7 +251,7 @@ namespace Bit.App.Pages
private class FormTableView : ExtendedTableView
{
public FormTableView()
public FormTableView(EnvironmentPage page)
{
Intent = TableIntent.Settings;
EnableScrolling = false;
@ -267,6 +259,7 @@ namespace Bit.App.Pages
EnableSelection = true;
VerticalOptions = LayoutOptions.Start;
NoFooter = true;
WrappingStackLayout = () => page.StackLayout;
}
}
}

View file

@ -67,12 +67,14 @@ namespace Bit.App.Pages
Uppercase = false
};
var stackLayout = new StackLayout
var stackLayout = new RedrawableStackLayout
{
Spacing = 10,
Children = { table, logoutButton }
};
table.WrappingStackLayout = () => stackLayout;
var scrollView = new ScrollView { Content = stackLayout };
if(Device.RuntimePlatform == Device.iOS)

View file

@ -71,7 +71,6 @@ namespace Bit.App.Pages
HasUnevenRows = true,
EnableSelection = true,
NoFooter = true,
//NoHeader = true,
VerticalOptions = LayoutOptions.Start,
Root = new TableRoot
{
@ -87,18 +86,20 @@ namespace Bit.App.Pages
{
Text = AppResources.GetPasswordHint,
Style = (Style)Application.Current.Resources["btn-primaryAccent"],
Margin = new Thickness(15, 0, 15, 25),
Command = new Command(async () => await ForgotPasswordAsync()),
VerticalOptions = LayoutOptions.End,
Uppercase = false,
BackgroundColor = Color.Transparent
};
var layout = new StackLayout
var layout = new RedrawableStackLayout
{
Children = { table, forgotPasswordButton },
Spacing = Helpers.OnPlatform(iOS: 0, Android: 10, Windows: 0)
Spacing = 10
};
table.WrappingStackLayout = () => layout;
var scrollView = new ScrollView { Content = layout };
if(Device.RuntimePlatform == Device.iOS)

View file

@ -135,12 +135,13 @@ namespace Bit.App.Pages
RememberCell
});
var layout = new StackLayout
var layout = new RedrawableStackLayout
{
Children = { instruction, table },
Spacing = 0
};
table.WrappingStackLayout = () => layout;
scrollView.Content = layout;
switch(_providerType.Value)
@ -213,12 +214,13 @@ namespace Bit.App.Pages
RememberCell
});
var layout = new StackLayout
var layout = new RedrawableStackLayout
{
Children = { webView, table, anotherMethodButton },
Spacing = 0
};
table.WrappingStackLayout = () => layout;
scrollView.Content = layout;
Title = "Duo";
@ -244,12 +246,13 @@ namespace Bit.App.Pages
RememberCell
});
var layout = new StackLayout
var layout = new RedrawableStackLayout
{
Children = { instruction, image, table, anotherMethodButton },
Spacing = 0
};
table.WrappingStackLayout = () => layout;
scrollView.Content = layout;
Title = AppResources.YubiKeyTitle;
@ -524,7 +527,7 @@ namespace Bit.App.Pages
NoFooter = true;
NoHeader = true;
VerticalOptions = LayoutOptions.Start;
Root = Root = new TableRoot
Root = new TableRoot
{
section
};

View file

@ -64,12 +64,13 @@ namespace Bit.App.Pages
Margin = new Thickness(15, (this.IsLandscape() ? 5 : 0), 15, 25)
};
var layout = new StackLayout
var layout = new RedrawableStackLayout
{
Children = { table, hintLabel },
Spacing = 0
};
table.WrappingStackLayout = () => layout;
var scrollView = new ScrollView { Content = layout };
if(Device.RuntimePlatform == Device.iOS)

View file

@ -35,7 +35,7 @@ namespace Bit.App.Pages
public FormEntryCell PasswordCell { get; set; }
public FormEntryCell ConfirmPasswordCell { get; set; }
public FormEntryCell PasswordHintCell { get; set; }
public StackLayout StackLayout { get; set; }
public RedrawableStackLayout StackLayout { get; set; }
public Label PasswordLabel { get; set; }
public Label HintLabel { get; set; }
@ -62,7 +62,7 @@ namespace Bit.App.Pages
PasswordHintCell.Entry.ReturnType = Enums.ReturnType.Done;
var table = new FormTableView
var table = new FormTableView(this)
{
Root = new TableRoot
{
@ -83,7 +83,7 @@ namespace Bit.App.Pages
Margin = new Thickness(15, (this.IsLandscape() ? 5 : 0), 15, 25)
};
var table2 = new FormTableView
var table2 = new FormTableView(this)
{
NoHeader = true,
Root = new TableRoot
@ -105,7 +105,7 @@ namespace Bit.App.Pages
Margin = new Thickness(15, (this.IsLandscape() ? 5 : 0), 15, 25)
};
StackLayout = new StackLayout
StackLayout = new RedrawableStackLayout
{
Children = { table, PasswordLabel, table2, HintLabel },
Spacing = 0
@ -145,7 +145,6 @@ namespace Bit.App.Pages
PasswordHintCell.InitEvents();
ConfirmPasswordCell.InitEvents();
PasswordHintCell.Entry.Completed += Entry_Completed;
StackLayout.LayoutChanged += Layout_LayoutChanged;
EmailCell.Entry.FocusWithDelay();
}
protected override void OnDisappearing()
@ -156,13 +155,6 @@ namespace Bit.App.Pages
PasswordHintCell.Dispose();
ConfirmPasswordCell.Dispose();
PasswordHintCell.Entry.Completed -= Entry_Completed;
StackLayout.LayoutChanged -= Layout_LayoutChanged;
}
private void Layout_LayoutChanged(object sender, EventArgs e)
{
PasswordLabel.WidthRequest = StackLayout.Bounds.Width - PasswordLabel.Bounds.Left * 2;
HintLabel.WidthRequest = StackLayout.Bounds.Width - HintLabel.Bounds.Left * 2;
}
private async void Entry_Completed(object sender, EventArgs e)
@ -229,7 +221,7 @@ namespace Bit.App.Pages
private class FormTableView : ExtendedTableView
{
public FormTableView()
public FormTableView(RegisterPage page)
{
Intent = TableIntent.Settings;
EnableScrolling = false;
@ -237,6 +229,7 @@ namespace Bit.App.Pages
EnableSelection = true;
VerticalOptions = LayoutOptions.Start;
NoFooter = true;
WrappingStackLayout = () => page.StackLayout;
}
}
}

View file

@ -73,12 +73,14 @@ namespace Bit.App.Pages
table.EstimatedRowHeight = 44;
}
var stackLayout = new StackLayout
var stackLayout = new RedrawableStackLayout
{
Children = { logoVersionStackLayout, table },
Spacing = 0
};
table.WrappingStackLayout = () => stackLayout;
if(Device.RuntimePlatform == Device.iOS || Device.RuntimePlatform == Device.UWP)
{
ToolbarItems.Add(new DismissModalToolBarItem(this, AppResources.Close));

View file

@ -50,9 +50,7 @@ namespace Bit.App.Pages
var mainTable = new ExtendedTableView
{
Intent = TableIntent.Settings,
EnableScrolling = false,
HasUnevenRows = true,
VerticalOptions = LayoutOptions.Start,
Root = new TableRoot
{
new TableSection(Helpers.GetEmptyTableSectionTitle())

View file

@ -22,7 +22,7 @@ namespace Bit.App.Pages
public ExtendedTextCell EmailCell { get; set; }
public ExtendedTextCell WebsiteCell { get; set; }
public ExtendedTextCell BugCell { get; set; }
public StackLayout StackLayout { get; set; }
public RedrawableStackLayout StackLayout { get; set; }
private CustomLabel EmailLabel { get; set; }
private CustomLabel WebsiteLabel { get; set; }
private CustomLabel BugLabel { get; set; }
@ -35,7 +35,7 @@ namespace Bit.App.Pages
ShowDisclousure = true
};
var emailTable = new CustomTableView
var emailTable = new CustomTableView(this)
{
Root = new TableRoot
{
@ -57,7 +57,7 @@ namespace Bit.App.Pages
ShowDisclousure = true
};
var websiteTable = new CustomTableView
var websiteTable = new CustomTableView(this)
{
NoHeader = true,
Root = new TableRoot
@ -80,7 +80,7 @@ namespace Bit.App.Pages
ShowDisclousure = true
};
var bugTable = new CustomTableView
var bugTable = new CustomTableView(this)
{
NoHeader = true,
Root = new TableRoot
@ -97,7 +97,7 @@ namespace Bit.App.Pages
Text = AppResources.FileBugReportDescription
};
StackLayout = new StackLayout
StackLayout = new RedrawableStackLayout
{
Children = { emailTable, EmailLabel, websiteTable, WebsiteLabel, bugTable, BugLabel },
Spacing = 0
@ -118,7 +118,6 @@ namespace Bit.App.Pages
EmailCell.Tapped += EmailCell_Tapped;
WebsiteCell.Tapped += WebsiteCell_Tapped;
BugCell.Tapped += BugCell_Tapped;
StackLayout.LayoutChanged += StackLayout_LayoutChanged;
}
protected override void OnDisappearing()
@ -127,14 +126,6 @@ namespace Bit.App.Pages
EmailCell.Tapped -= EmailCell_Tapped;
WebsiteCell.Tapped -= WebsiteCell_Tapped;
BugCell.Tapped -= BugCell_Tapped;
StackLayout.LayoutChanged -= StackLayout_LayoutChanged;
}
private void StackLayout_LayoutChanged(object sender, EventArgs e)
{
WebsiteLabel.WidthRequest = StackLayout.Bounds.Width - WebsiteLabel.Bounds.Left * 2;
EmailLabel.WidthRequest = StackLayout.Bounds.Width - EmailLabel.Bounds.Left * 2;
BugLabel.WidthRequest = StackLayout.Bounds.Width - BugLabel.Bounds.Left * 2;
}
private void EmailCell_Tapped(object sender, EventArgs e)
@ -157,7 +148,7 @@ namespace Bit.App.Pages
private class CustomTableView : ExtendedTableView
{
public CustomTableView()
public CustomTableView(SettingsHelpPage page)
{
Intent = TableIntent.Settings;
EnableScrolling = false;
@ -165,6 +156,7 @@ namespace Bit.App.Pages
EnableSelection = true;
VerticalOptions = LayoutOptions.Start;
NoFooter = true;
WrappingStackLayout = () => page.StackLayout;
if(Device.RuntimePlatform == Device.iOS)
{

View file

@ -24,7 +24,7 @@ namespace Bit.App.Pages
Init();
}
private StackLayout StackLayout { get; set; }
private RedrawableStackLayout StackLayout { get; set; }
private ExtendedSwitchCell CopyTotpCell { get; set; }
private Label CopyTotpLabel { get; set; }
private ExtendedSwitchCell AnalyticsCell { get; set; }
@ -46,7 +46,7 @@ namespace Bit.App.Pages
On = _appSettings.DisableWebsiteIcons
};
var websiteIconsTable = new FormTableView(true)
var websiteIconsTable = new FormTableView(this, true)
{
Root = new TableRoot
{
@ -63,7 +63,7 @@ namespace Bit.App.Pages
On = _settings.GetValueOrDefault(Constants.SettingDisableTotpCopy, false)
};
var totpTable = new FormTableView
var totpTable = new FormTableView(this)
{
Root = new TableRoot
{
@ -80,7 +80,7 @@ namespace Bit.App.Pages
On = _settings.GetValueOrDefault(Constants.SettingGaOptOut, false)
};
var analyticsTable = new FormTableView
var analyticsTable = new FormTableView(this)
{
Root = new TableRoot
{
@ -106,7 +106,7 @@ namespace Bit.App.Pages
Text = AppResources.DisableWebsiteIconsDescription
};
StackLayout = new StackLayout
StackLayout = new RedrawableStackLayout
{
Children =
{
@ -125,7 +125,7 @@ namespace Bit.App.Pages
On = !_appSettings.AutofillPersistNotification && !_appSettings.AutofillPasswordField
};
var autofillAlwaysTable = new FormTableView(true)
var autofillAlwaysTable = new FormTableView(this, true)
{
Root = new TableRoot
{
@ -147,7 +147,7 @@ namespace Bit.App.Pages
On = _appSettings.AutofillPersistNotification
};
var autofillPersistNotificationTable = new FormTableView
var autofillPersistNotificationTable = new FormTableView(this)
{
Root = new TableRoot
{
@ -169,7 +169,7 @@ namespace Bit.App.Pages
On = _appSettings.AutofillPasswordField
};
var autofillPasswordFieldTable = new FormTableView
var autofillPasswordFieldTable = new FormTableView(this)
{
Root = new TableRoot
{
@ -217,7 +217,6 @@ namespace Bit.App.Pages
AnalyticsCell.OnChanged += AnalyticsCell_Changed;
WebsiteIconsCell.OnChanged += WebsiteIconsCell_Changed;
CopyTotpCell.OnChanged += CopyTotpCell_OnChanged;
StackLayout.LayoutChanged += Layout_LayoutChanged;
if(Device.RuntimePlatform == Device.Android)
{
@ -234,7 +233,6 @@ namespace Bit.App.Pages
AnalyticsCell.OnChanged -= AnalyticsCell_Changed;
WebsiteIconsCell.OnChanged -= WebsiteIconsCell_Changed;
CopyTotpCell.OnChanged -= CopyTotpCell_OnChanged;
StackLayout.LayoutChanged -= Layout_LayoutChanged;
if(Device.RuntimePlatform == Device.Android)
{
@ -244,29 +242,6 @@ namespace Bit.App.Pages
}
}
private void Layout_LayoutChanged(object sender, EventArgs e)
{
AnalyticsLabel.WidthRequest = StackLayout.Bounds.Width - AnalyticsLabel.Bounds.Left * 2;
WebsiteIconsLabel.WidthRequest = StackLayout.Bounds.Width - WebsiteIconsLabel.Bounds.Left * 2;
CopyTotpLabel.WidthRequest = StackLayout.Bounds.Width - CopyTotpLabel.Bounds.Left * 2;
if(AutofillAlwaysLabel != null)
{
AutofillAlwaysLabel.WidthRequest = StackLayout.Bounds.Width - AutofillAlwaysLabel.Bounds.Left * 2;
}
if(AutofillPasswordFieldLabel != null)
{
AutofillPasswordFieldLabel.WidthRequest = StackLayout.Bounds.Width - AutofillPasswordFieldLabel.Bounds.Left * 2;
}
if(AutofillPersistNotificationLabel != null)
{
AutofillPersistNotificationLabel.WidthRequest =
StackLayout.Bounds.Width - AutofillPersistNotificationLabel.Bounds.Left * 2;
}
}
private void WebsiteIconsCell_Changed(object sender, ToggledEventArgs e)
{
var cell = sender as ExtendedSwitchCell;
@ -352,7 +327,7 @@ namespace Bit.App.Pages
private class FormTableView : ExtendedTableView
{
public FormTableView(bool header = false)
public FormTableView(SettingsOptionsPage page, bool header = false)
{
Intent = TableIntent.Settings;
EnableScrolling = false;
@ -361,6 +336,7 @@ namespace Bit.App.Pages
VerticalOptions = LayoutOptions.Start;
NoFooter = true;
NoHeader = !header;
WrappingStackLayout = () => page.StackLayout;
}
}

View file

@ -163,7 +163,7 @@ namespace Bit.App.Pages
table.BottomPadding = 50;
}
var stackLayout = new StackLayout
var stackLayout = new RedrawableStackLayout
{
Orientation = StackOrientation.Vertical,
Children = { Password, table },
@ -171,6 +171,8 @@ namespace Bit.App.Pages
Spacing = 0
};
table.WrappingStackLayout = () => stackLayout;
var scrollView = new ScrollView
{
Content = stackLayout,

View file

@ -44,7 +44,7 @@ namespace Bit.App.Pages
public ExtendedObservableCollection<VaultAttachmentsPageModel.Attachment> PresentationAttchments { get; private set; }
= new ExtendedObservableCollection<VaultAttachmentsPageModel.Attachment>();
public ExtendedListView ListView { get; set; }
public StackLayout NoDataStackLayout { get; set; }
public RedrawableStackLayout NoDataStackLayout { get; set; }
public StackLayout AddNewStackLayout { get; set; }
public Label FileLabel { get; set; }
public ExtendedTableView NewTable { get; set; }
@ -88,6 +88,7 @@ namespace Bit.App.Pages
EnableSelection = false,
VerticalOptions = LayoutOptions.Start,
Margin = new Thickness(0, Helpers.OnPlatform(iOS: 10, Android: 30), 0, 0),
WrappingStackLayout = () => NoDataStackLayout,
Root = new TableRoot
{
new TableSection(AppResources.AddNewAttachment)
@ -122,7 +123,7 @@ namespace Bit.App.Pages
Style = (Style)Application.Current.Resources["text-muted"]
};
NoDataStackLayout = new StackLayout
NoDataStackLayout = new RedrawableStackLayout
{
VerticalOptions = LayoutOptions.Start,
Spacing = 0,

View file

@ -36,6 +36,7 @@ namespace Bit.App.Pages
}
public ToolbarItem SaveToolbarItem { get; set; }
public ToolbarItem CloseToolbarItem { get; set; }
public Label NoDataLabel { get; set; }
public TableSection FieldsSection { get; set; }
public ExtendedTableView Table { get; set; }
@ -131,12 +132,16 @@ namespace Bit.App.Pages
await DisplayAlert(null, AppResources.AnErrorHasOccurred, AppResources.Ok);
}
}, ToolbarItemOrder.Default, 0);
ToolbarItems.Add(SaveToolbarItem);
Title = AppResources.CustomFields;
Content = Table;
if(Device.RuntimePlatform == Device.iOS)
{
CloseToolbarItem = new DismissModalToolBarItem(this, AppResources.Close);
ToolbarItems.Add(CloseToolbarItem);
Table.RowHeight = -1;
Table.EstimatedRowHeight = 44;
}
@ -157,13 +162,14 @@ namespace Bit.App.Pages
return;
}
if(_cipher.Fields != null && _cipher.Fields.Any())
var hasFields = _cipher.Fields?.Any() ?? false;
if(hasFields)
{
Content = Table;
ToolbarItems.Add(SaveToolbarItem);
if(Device.RuntimePlatform == Device.iOS)
if(CloseToolbarItem != null)
{
ToolbarItems.Add(new DismissModalToolBarItem(this, AppResources.Cancel));
CloseToolbarItem.Text = AppResources.Cancel;
}
foreach(var field in _cipher.Fields)
@ -213,9 +219,9 @@ namespace Bit.App.Pages
else
{
Content = NoDataLabel;
if(Device.RuntimePlatform == Device.iOS)
if(ToolbarItems.Count > 0)
{
ToolbarItems.Add(new DismissModalToolBarItem(this, AppResources.Close));
ToolbarItems.RemoveAt(0);
}
}
}

View file

@ -63,7 +63,7 @@ namespace Bit.iOS.Controls
private void SetSource()
{
var view = (ExtendedTableView)Element;
if(view.NoFooter || view.NoHeader)
if(true || view.NoFooter || view.NoHeader)
{
Control.Source = new CustomTableViewModelRenderer(view);
}
@ -116,6 +116,7 @@ namespace Bit.iOS.Controls
public class CustomTableViewModelRenderer : UnEvenTableViewModelRenderer
{
private readonly ExtendedTableView _view;
private bool _didRedraw = false;
public CustomTableViewModelRenderer(ExtendedTableView model)
: base(model)
@ -123,6 +124,16 @@ namespace Bit.iOS.Controls
_view = model;
}
public override async void WillDisplay(UITableView tableView, UITableViewCell cell, NSIndexPath indexPath)
{
// ref https://stackoverflow.com/a/48076188/1090359
if(!_didRedraw && _view.WrappingStackLayout != null)
{
_didRedraw = true;
await _view.WrappingStackLayout()?.RedrawIfNeededAsync(10, false);
}
}
public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
if(_view.HasUnevenRows)
@ -143,6 +154,16 @@ namespace Bit.iOS.Controls
return base.GetHeightForHeader(tableView, section);
}
public override UIView GetViewForHeader(UITableView tableView, nint section)
{
if(_view.NoHeader && section == 0)
{
return new UIView(new CGRect(0, 0, 0, 0));
}
return null;
}
public override nfloat GetHeightForFooter(UITableView tableView, nint section)
{
if(_view.NoFooter && (section + 1) == NumberOfSections(tableView))
@ -152,6 +173,16 @@ namespace Bit.iOS.Controls
return 10f;
}
public override UIView GetViewForFooter(UITableView tableView, nint section)
{
if(_view.NoFooter && (section + 1) == NumberOfSections(tableView))
{
return new UIView(new CGRect(0, 0, 0, 0));
}
return null;
}
}
}
}