In this screen you can add and remove people. Not all fields are required, so the cell height is dynamic.
If I add first a person with all the fields completed, then a second person with not all fields completed, and then I remove the first person, the second person takes the first place but with the layout of the first person
After I remove the first person, if I scroll up until the remaining cell is off screen, then it fixes itself
This is the table source
namespace xXxx.xXxx.iOS
{
public class SiniestroParticipantesSource : MvxTableViewSource
{
private readonly SiniestroParticipantesViewModel viewModel;
public SiniestroParticipantesSource(UITableView tableView, SiniestroParticipantesViewModel viewModel)
: base(tableView)
{
this.UseAnimations = true;
this.AddAnimation = UITableViewRowAnimation.Top;
this.RemoveAnimation = UITableViewRowAnimation.Middle;
this.viewModel = viewModel;
tableView.RegisterNibForCellReuse(UINib.FromName(PersonaDenunciaCellView.Key, NSBundle.MainBundle), PersonaDenunciaCellView.Key);
}
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
tableView.DeselectRow(indexPath, true);
var itemPersona = this.viewModel.Personas[indexPath.Section];
this.viewModel.AgregarCommand.Execute(itemPersona);
}
protected override UITableViewCell GetOrCreateCellFor(UITableView tableView, NSIndexPath indexPath, object item)
{
var cell = (PersonaDenunciaCellView)tableView.DequeueReusableCell(PersonaDenunciaCellView.Key, indexPath);
return cell;
}
public override nint RowsInSection(UITableView tableview, nint section)
{
return 1;
}
public override nint NumberOfSections(UITableView tableView)
{
return this.viewModel.Personas.Count;
}
protected override object GetItemAt(NSIndexPath indexPath)
{
return this.viewModel.Personas[indexPath.Section];
}
}
}
This is the cell view
namespace xXxx.xXxx.iOS
{
public partial class PersonaDenunciaCellView : MvxTableViewCell
{
public static readonly NSString Key = new NSString("PersonaDenunciaCellView");
public static readonly UINib Nib;
static PersonaDenunciaCellView()
{
Nib = UINib.FromName("PersonaDenunciaCellView", NSBundle.MainBundle);
}
protected PersonaDenunciaCellView(IntPtr handle) : base(handle)
{
this.DelayBind(() =>
{
var set = this.CreateBindingSet<PersonaDenunciaCellView, PersonaDenunciaItemViewModel>();
set.Bind(btnRemove).To(vm => vm.RemoveCommand);
set.Bind(lblNombre).To(vm => vm.Persona.Persona.Nombre);
set.Bind(lblTipoDoc).To(vm => vm.Persona.Persona.TipoDoc.Descripcion);
set.Bind(tipoDocVisibilityConst).For("Priority").To(vm => vm.Persona.Persona.Nrodoc).WithConversion("iOSVisibility", true);
set.Bind(lblNrodoc).To(vm => vm.Persona.Persona.Nrodoc);
set.Bind(nroDocVisibilityConst).For("Priority").To(vm => vm.Persona.Persona.Nrodoc).WithConversion("iOSVisibility", true);
set.Bind(lblMailContacto).To(vm => vm.Persona.MailContacto);
set.Bind(mailContactoVisibilityConst).For("Priority").To(vm => vm.Persona.MailContacto).WithConversion("iOSVisibility", true);
set.Bind(lblTelContacto).To(vm => vm.Persona.TelContacto);
set.Bind(telContactoVisibilityConst).For("Priority").To(vm => vm.Persona.TelContacto).WithConversion("iOSVisibility", true);
set.Bind(lblLesionado).To(vm => vm.Persona.Lesionado).WithConversion("Lesionado");
set.Bind(vehiculoVisibilityConst).For("Priority").To(vm => vm.Persona.Patente).WithConversion("iOSVisibility", true);
set.Bind(viewVehiculo).For("Visibility").To(vm => vm.Persona.Patente).WithConversion("Visibility");
set.Bind(lblPatente).To(vm => vm.Persona.Patente);
set.Bind(lblCiaSeguroDesc).To(vm => vm.Persona.CiaSeguroDesc);
set.Apply();
});
}
}
}
Cell ViewModel
namespace xXxx.xXxx.Core.ViewModels.Items
{
public class PersonaDenunciaItemViewModel:MvxViewModel
{
private readonly IMvxMessenger messenger;
private readonly IUserInteraction userInteraction;
public string Index { get; set; }
public PersonaDenunciaItemViewModel (SiniestroCarga.PersonaDenuncia persona, IMvxMessenger messenger, IUserInteraction userInteraction, string index)
{
this.messenger = messenger;
this.userInteraction = userInteraction;
this.Persona = persona;
this.Index = index;
}
private SiniestroCarga.PersonaDenuncia persona;
public SiniestroCarga.PersonaDenuncia Persona
{
get
{
return this.persona;
}
set
{
this.persona = value;
this.RaisePropertyChanged(() => this.Persona);
}
}
private ICommand removeCommand;
public ICommand RemoveCommand
{
get
{
return this.removeCommand = this.removeCommand ?? new MvxCommand(this.RemovePersona);
}
}
private void RemovePersona()
{
this.userInteraction.Confirm("Are you sure?", () =>
{
this.messenger.Publish(new RemovePersonaDenunciaMessage(this, this.Persona, this.Index));
}, null, "OK", "Cancel");
}
}
}
And that last messenger.Publish is subscribed to this on another ViewModel
OnRemovePersonaDenuncia = message =>
{
var listPersonas = new ObservableCollection<PersonaDenunciaItemViewModel>(this.Personas);
listPersonas.Remove(this.Personas.First(p => p.Index == message.Index));
this.Personas = listPersonas;
}
Changing the implementation of RemoveCommand to this
this.Personas.Remove(this.Personas.First(p => p.Index == message.Index));
Makes that, when I press the remove button, the simulator closes without any error. The application trace on Xamarin Studio shows this
*** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3512.60.7/UITableView.m:1700
iOS does not calculate the height of the cells correctly when the content height is dynamic. That´s very annoying but you can override GetHeightForRow
and EstimatedHeight
in SiniestroParticipantesSource
to calculate the exact height of each cell depending on the data:
public override nfloat EstimatedHeight(UITableView tableView, NSIndexPath indexPath) =>
GetHeightForRow(tableView, indexPath);
public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
var data = (PersonaDenunciaItemViewModel)ItemsSource.ElementAt(indexPath.Row);
var cell = (PersonaDenunciaCellView)tableView.DequeueReusableCell(PersonaDenunciaCellView.Key, indexPath);
// TODO set the cell data manually (ignoring bindings)
// i.e: **cell.lblNombre = data.Persona.Persona.Nombre**; // and every other field required
cell.SetNeedsLayout();
cell.LayoutIfNeeded();
var size = cell.ContentView.SystemLayoutSizeFittingSize(UIView.UILayoutFittingCompressedSize);
return NMath.Ceiling(size.Height) + 1;
}
Here´s an example using the very same code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With