maui-linux/Xamarin.Forms.Platform.Android/Renderers/TableViewModelRenderer.cs

271 строка
6.2 KiB
C#

using Android.Content;
using Android.Util;
using Android.Views;
using Android.Widget;
using AView = Android.Views.View;
using AListView = Android.Widget.ListView;
using System;
using System.Collections.Generic;
namespace Xamarin.Forms.Platform.Android
{
public class TableViewModelRenderer : CellAdapter
{
readonly TableView _view;
protected readonly Context Context;
ITableViewController Controller => _view;
Cell _restoreFocus;
Cell[] _cellCache;
Cell[] CellCache
{
get
{
if (_cellCache == null)
FillCache();
return _cellCache;
}
}
bool[] _isHeaderCache;
bool[] IsHeaderCache
{
get
{
if (_isHeaderCache == null)
FillCache();
return _isHeaderCache;
}
}
bool[] _nextIsHeaderCache;
bool[] NextIsHeaderCache
{
get
{
if (_nextIsHeaderCache == null)
FillCache();
return _nextIsHeaderCache;
}
}
public TableViewModelRenderer(Context context, AListView listView, TableView view) : base(context)
{
_view = view;
Context = context;
Controller.ModelChanged += OnModelChanged;
listView.OnItemClickListener = this;
listView.OnItemLongClickListener = this;
}
public override int Count => CellCache.Length;
public override object this[int position]
{
get
{
if (position < 0 || position >= CellCache.Length)
return null;
return CellCache[position];
}
}
public override int ViewTypeCount
{
get
{
// 1 for the headers + 1 for each non header cell
var viewTypeCount = 1;
foreach (var b in IsHeaderCache)
if (!b)
viewTypeCount++;
return viewTypeCount;
}
}
public override bool AreAllItemsEnabled()
{
return false;
}
public override long GetItemId(int position)
{
return position;
}
public override AView GetView(int position, AView convertView, ViewGroup parent)
{
bool isHeader, nextIsHeader;
Cell item = GetCellForPosition(position, out isHeader, out nextIsHeader);
if (item == null)
return new AView(Context);
var makeBline = true;
var layout = convertView as ConditionalFocusLayout;
if (layout != null)
{
makeBline = false;
convertView = layout.GetChildAt(0);
}
else
layout = new ConditionalFocusLayout(Context) { Orientation = Orientation.Vertical };
AView aview = CellFactory.GetCell(item, convertView, parent, Context, _view);
if (!makeBline)
{
if (convertView != aview)
{
layout.RemoveViewAt(0);
layout.AddView(aview, 0);
}
}
else
layout.AddView(aview, 0);
AView bline;
if (makeBline)
{
bline = new AView(Context) { LayoutParameters = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, 1) };
layout.AddView(bline);
}
else
bline = layout.GetChildAt(1);
if (isHeader)
bline.SetBackgroundColor(Color.Accent.ToAndroid());
else if (nextIsHeader)
bline.SetBackgroundColor(global::Android.Graphics.Color.Transparent);
else
{
using (var value = new TypedValue())
{
int id = global::Android.Resource.Drawable.DividerHorizontalDark;
if (Context.Theme.ResolveAttribute(global::Android.Resource.Attribute.ListDivider, value, true))
id = value.ResourceId;
else if (Context.Theme.ResolveAttribute(global::Android.Resource.Attribute.Divider, value, true))
id = value.ResourceId;
bline.SetBackgroundResource(id);
}
}
layout.ApplyTouchListenersToSpecialCells(item);
if (_restoreFocus == item)
{
if (!aview.HasFocus)
aview.RequestFocus();
_restoreFocus = null;
}
else if (aview.HasFocus)
aview.ClearFocus();
return layout;
}
public override bool IsEnabled(int position)
{
bool isHeader, nextIsHeader;
Cell item = GetCellForPosition(position, out isHeader, out nextIsHeader);
return !isHeader && item.IsEnabled;
}
protected override Cell GetCellForPosition(int position)
{
bool isHeader, nextIsHeader;
return GetCellForPosition(position, out isHeader, out nextIsHeader);
}
protected override void HandleItemClick(AdapterView parent, AView nview, int position, long id)
{
ITableModel model = Controller.Model;
if (position < 0 || position >= CellCache.Length)
return;
if (IsHeaderCache[position])
return;
model.RowSelected(CellCache[position]);
}
Cell GetCellForPosition(int position, out bool isHeader, out bool nextIsHeader)
{
isHeader = false;
nextIsHeader = false;
if (position < 0 || position >= CellCache.Length)
return null;
isHeader = IsHeaderCache[position];
nextIsHeader = NextIsHeaderCache[position];
return CellCache[position];
}
void FillCache()
{
ITableModel model = Controller.Model;
int sectionCount = model.GetSectionCount();
var newCellCache = new List<Cell>();
var newIsHeaderCache = new List<bool>();
var newNextIsHeaderCache = new List<bool>();
for (var sectionIndex = 0; sectionIndex < sectionCount; sectionIndex++)
{
var sectionTitle = model.GetSectionTitle(sectionIndex);
var sectionRowCount = model.GetRowCount(sectionIndex);
if (!string.IsNullOrEmpty(sectionTitle))
{
Cell headerCell = model.GetHeaderCell(sectionIndex);
if (headerCell == null)
headerCell = new TextCell { Text = sectionTitle };
headerCell.Parent = _view;
newIsHeaderCache.Add(true);
newNextIsHeaderCache.Add(sectionRowCount == 0 && sectionIndex < sectionCount - 1);
newCellCache.Add(headerCell);
}
for (int i = 0; i < sectionRowCount; i++)
{
newIsHeaderCache.Add(false);
newNextIsHeaderCache.Add(i == sectionRowCount - 1 && sectionIndex < sectionCount - 1);
newCellCache.Add((Cell)model.GetItem(sectionIndex, i));
}
}
_cellCache = newCellCache.ToArray();
_isHeaderCache = newIsHeaderCache.ToArray();
_nextIsHeaderCache = newNextIsHeaderCache.ToArray();
}
void InvalidateCellCache()
{
_cellCache = null;
_isHeaderCache = null;
_nextIsHeaderCache = null;
}
void OnModelChanged(object sender, EventArgs e)
{
InvalidateCellCache();
NotifyDataSetChanged();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
InvalidateCellCache();
Controller.ModelChanged -= OnModelChanged;
}
base.Dispose(disposing);
}
}
}