Hi,
I've been working on a custom renderer to create an Accordion controller. So far I was successful using Xamarin Labs - EditableListView as reference.
Here's how the code is so far for the custom renderer: AccordionListViewRenderer
`
public UITableView _tableView;
private AccordionTableViewSource _editableListViewSource;
public readonly float _rowListHeight = 100;
public readonly float _rowSelectedHeight = 600;
public static int _selectedRow = -1;
public static int _oldSelectedRow = -1;
protected override void OnElementChanged(ElementChangedEventArgs<AccordionListView<T>> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
_tableView = new UITableView(new RectangleF(0, 0, 1, 1), UITableViewStyle.Plain);
SetNativeControl(_tableView);
}
Unbind(e.OldElement);
Bind(e.NewElement);
_editableListViewSource = new AccordionTableViewSource(this);
_tableView.Source = _editableListViewSource;
_tableView.BackgroundView = new UIView();
_tableView.TableFooterView = new UIView();
}
private void Unbind(AccordionListView<T> oldElement)
{
if (oldElement != null)
{
oldElement.PropertyChanged -= ElementPropertyChanged;
oldElement.Source.CollectionChanged += DataCollectionChanged;
}
}
private void Bind(AccordionListView<T> newElement)
{
if (newElement != null)
{
newElement.PropertyChanged += ElementPropertyChanged;
newElement.Source.CollectionChanged += DataCollectionChanged;
}
}
private void DataCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
_tableView.ReloadData();
}
private void ElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "Source")
{
Element.Source.CollectionChanged += DataCollectionChanged;
}
}
private class AccordionTableViewSource : UITableViewSource
{
AccordionListViewRenderer<T> _containerRenderer;
public AccordionTableViewSource(AccordionListViewRenderer<T> containerRenderer)
{
_containerRenderer = containerRenderer;
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var item = _containerRenderer.Element.Source[indexPath.Row];
ViewCell viewCell = Activator.CreateInstance(_containerRenderer.Element.ListViewType) as ViewCell;
viewCell.BindingContext = item;
//Create a selected view cell if we are in the selected row.
if (indexPath.Row == _selectedRow)
{
SelectedAdvisorListCell mainCell = Activator.CreateInstance(_containerRenderer.Element.FocusViewType,
_containerRenderer.AccordionListView.Source[_selectedRow],
false) as SelectedAdvisorListCell;
mainCell.BindingContext = item;
if (_containerRenderer.Element.AdvisorSelectedCallback != null)
{
mainCell.mainAdvisor.chooseButton.Clicked += (sender, e) =>
{
var advisor = _containerRenderer.AccordionListView.Source[_selectedRow];
_containerRenderer.Element.AdvisorSelectedCallback(advisor);
};
}
mainCell.Height = _containerRenderer._rowSelectedHeight;
viewCell = (ViewCell)mainCell;
}
UITableViewCell cell = new ViewCellRenderer().GetCell(viewCell, tableView);
return cell;
}
public override int RowsInSection(UITableView tableView, int section)
{
return _containerRenderer.Element.Source.Count;
}
public override float GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
if (tableView.IndexPathForSelectedRow != null)
{
if (tableView.IndexPathForSelectedRow.Row == indexPath.Row && _selectedRow != -1)
return _containerRenderer._rowSelectedHeight;
}
return _containerRenderer._rowListHeight;
}
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
_selectedRow = indexPath.Row;
NSIndexPath[] rowsToReload;
if (_oldSelectedRow >= 0)
{
//If we have the selected row the same as the old one, resize to hide/show the details.
if (_selectedRow == _oldSelectedRow)
{
rowsToReload = new NSIndexPath[] {
NSIndexPath.FromRowSection(indexPath.Row, 0)
};
}
else //refresh both the clicked and the last clicked cells
{
rowsToReload = new NSIndexPath[] {
NSIndexPath.FromRowSection(_oldSelectedRow, 0),
NSIndexPath.FromRowSection(indexPath.Row, 0)
};
}
}
else
{
rowsToReload = new NSIndexPath[] {
NSIndexPath.FromRowSection(indexPath.Row, 0)
};
}
tableView.ReloadRows(rowsToReload, UITableViewRowAnimation.Top);
_oldSelectedRow = indexPath.Row;
}
}
}`
On the GetCell I'm creating new instances of Xamarin classes that extend from ViewCell and hold a stacklayout.
Right now I'm facing two problems:
- All of the subviews inside my type classes (used to create on the GetCell) have a -1 Width and -1 Height. This won't change unless I manually set a WidthRequest and HeightRequest for all children.
- After iOS update, when I select another row, it doesn't expand anymore. The content height was going all the way to 600, now it's going just a little bit further than 100 and it stop there.
Maybe I got this thing all wrong, any idea?
Thank you!