我有两个高度不同的单元格。当我移除第一个单元格后,第二个单元格会继承第一个单元格的高度。

9

一些背景

在这个屏幕上,您可以添加和删除人员。不是所有字段都是必需的,因此单元格高度是动态的。

问题

如果我先添加一个填写了所有字段的人员,然后再添加一个没有填写所有字段的人员,接着删除第一个人员,则第二个人员将占据第一个人员的位置,但使用第一个人员的布局。

重要提示

在我删除第一个人员后,如果我向上滚动直到剩余单元格离开屏幕,那么它会自动修复。

代码

这是表格源码

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];
        }
    }
}

这是单元格视图。
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();
            });
        }
    }
}

单元格视图模型

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");
        }
    }

}

最后一个消息者。Publish被订阅到另一个ViewModel上。

OnRemovePersonaDenuncia = message =>
                {
                    var listPersonas = new ObservableCollection<PersonaDenunciaItemViewModel>(this.Personas);
                    listPersonas.Remove(this.Personas.First(p => p.Index == message.Index));
                    this.Personas = listPersonas;
                }

更新

将RemoveCommand的实现更改为以下内容

this.Personas.Remove(this.Personas.First(p => p.Index == message.Index));

当我按下删除按钮时,模拟器会无错误关闭。在Xamarin Studio中的应用程序跟踪显示如下信息:
*** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3512.60.7/UITableView.m:1700

你在TableViewCells中使用Autolayout吗?另外,你能发布你的viewmodel吗?特别是RemoveCommand的实现。 - wishmaster
@wishmaster 是的,我正在使用AutoLayout。我现在会更新帖子。 - Santiago Quiroga
@wishmaster 已更新 - Santiago Quiroga
你能试试这个吗:在OnRemovePersonaDenuncia中,将实现更改为this.Personas?.Remove(message.Persona)? - wishmaster
我已经更新了帖子以展示结果。 - Santiago Quiroga
显示剩余2条评论
1个回答

1

iOS在内容高度动态时无法正确计算单元格的高度。这非常令人恼火,但您可以重写SiniestroParticipantesSource中的GetHeightForRowEstimatedHeight以根据数据计算每个单元格的确切高度:

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;
}

这里有一个使用相同代码的示例


为什么我应该忽略绑定? - Santiago Quiroga
因为您不想等待任何绑定完成其工作。您希望立即分配值。此操作仅用于计算高度。与mvvmcross绑定无关。 - xleon
我无法访问单元格元素,例如cell.lblNombre。"由于其保护级别"。 - Santiago Quiroga
1
lblNombre 可能是在设计文件中自动生成的。通过 public UILabel LblNombre => lblNombre 将其公开。 - wishmaster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接