簡體   English   中英

Xamarin Forms iOS自定義UITableViewCell動態高度

[英]Xamarin Forms iOS custom UITableViewCell dynamic height

我正在嘗試為Xamarin Forms創建自定義UITableViewCell,它將根據其中包含的文本自動調整其高度。

我已經找到了通過Designer創建的解決方案,但是我需要在代碼中執行此操作。

這是我在分析Designer解決方案之后所擁有的,但是它不起作用:

public class FormLabelCellView : UITableViewCell, INativeElementView
{
    public UILabel Label { get; private set; }
    public FormLabelCell Cell { get; set; }
    public Element Element => Cell;

    public FormLabelCellView(FormLabelCell cell) : base(UITableViewCellStyle.Default, cell.GetType().FullName)
    {
        Cell = cell;
        // in the custom ContentView solution I can't set the cell to expand and contract according to the text it contains
        Label = new UILabel();

        Label.TranslatesAutoresizingMaskIntoConstraints = false;
        Label.SetContentCompressionResistancePriority(751, UILayoutConstraintAxis.Vertical);
        Label.SetContentHuggingPriority(251, UILayoutConstraintAxis.Vertical);

        this.ContentView.AddSubview(Label);

        this.ContentView.AddConstraint(NSLayoutConstraint.Create(Label, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.ContentView, NSLayoutAttribute.Left, 1, 0));
        this.ContentView.AddConstraint(NSLayoutConstraint.Create(Label, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.ContentView, NSLayoutAttribute.Right, 1, 0));
        this.ContentView.AddConstraint(NSLayoutConstraint.Create(Label, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.ContentView, NSLayoutAttribute.Top, 1, 0));
        this.ContentView.AddConstraint(NSLayoutConstraint.Create(Label, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, this.ContentView, NSLayoutAttribute.Bottom, 1, 0));
    }
}

這是結果(行高可能是DefaultRowHeight of 44):

自定義ContentView解決方案

在任何人問到RowHeightEstimatedRowHeight之前 是的,我已設置RowHeight = UITableView.AutomaticDimension; EstimatedRowHeight = 24; 在我的自定義ListViewRenderer中。

當我將自定義UITableViewCell修改為此時,我還可以驗證它是否有效:

public class FormLabelCellView : UITableViewCell, INativeElementView
{
    public UILabel Label { get; private set; }
    public FormLabelCell Cell { get; set; }
    public Element Element => Cell;

    public FormLabelCellView(FormLabelCell cell) : base(UITableViewCellStyle.Default, cell.GetType().FullName)
    {
        Cell = cell;
        // this solution works, but I can't remove the margins / padding and set background color
        Label = this.TextLabel;
    }
}

然后結果如下所示:

使用TextLabel

我認為我沒有正確創建約束。 有人能幫我嗎?

編輯:嘗試創建用於測試目的的自定義UITableViewSource之后,我發現問題出在ListViewDataSourceUnevenListViewDataSource的Xamarin實現中。 不幸的是,因為這些類是內部的,所以我無法擴展它們並覆蓋GetHeightForRow函數。

在我的測試中,如果我設置RowHeight = UITableView.AutomaticDimension; EstimatedRowHeight = 24; 在listViewRenderer中,我將獲得與您顯示的效果相同的效果:TableView似乎具有相等的行高。

但是,當我嘗試使用另一種方式時:在tableView的源代碼中使用override方法,例如:

public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
    return UITableView.AutomaticDimension;
}

public override nfloat EstimatedHeight(UITableView tableView, NSIndexPath indexPath)
{
    return 24;
}

它工作正常(單元格將在運行時自動調整其行高的大小)。

此外,我真的建議您使用此方法來構造您的Cell:

public MyListViewCell(NSString cellId) : base(UITableViewCellStyle.Default, cellId)
{
     //add your controls in the cell's ContentView
}

然后我們可以在Source中使用它,例如:

public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
    MyListViewCell cell = tableView.DequeueReusableCell("Cell") as MyListViewCell;

    if (cell == null)
    {
        cell = new MyListViewCell(new NSString("Cell"));
    }

    //Update your data

    return Cell;
}
public void SetUpCell(string ParticipantName)
        {
            ParticipantNameLabel.Text = ParticipantName;
        }

public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
        {
            var cell = tableView.DequeueReusableCell("PeopleCell", indexPath) as PeopleCell;

            if (cell == null)
            {
                cell = new PeopleCell(new NSString("PeopleCell"));
            }
            cell.SelectionStyle = UITableViewCellSelectionStyle.None;
            cell.SetUpCell(ListPeople[indexPath.Row]);

            return cell;
        }

當我調用cell.SetUpCell()時,我在ParticipantNameLabel上得到了一個空引用,該實例在您上面演示的構造函數中實例化。

public MyListViewCell(NSString cellId) : base(UITableViewCellStyle.Default, cellId)
{
     //add your controls in the cell's ContentView
}

如果我將實例化放在下面的構造函數中,則不會獲得此null引用。

public PeopleCell(IntPtr handle) : base(handle)
        {
        }

我想念什么?

所以回答我自己的問題。 問題出在內部類ListViewDataSourceUnevenListViewDataSource的Xamarin實現中。 因為我們不能擴展這些類,所以對於ListView中的動態行高有兩種可能的解決方案。

  1. 創建自己的UITableViewSource實現。
  2. 使用ViewCell創建您的自定義單元。

我使用了第二個選項,因為我正在做多平台應用程序,並且我不想創建UITableViewSource的復雜實現。

因此,這是自定義ViewCell的示例實現:

public class CustomLabelCell : ViewCell
{
    private Label label;

    public static readonly BindableProperty TextProperty = BindableProperty.Create("Text", typeof(string), typeof(CustomLabelCell), null);

    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    // disable public set on View property
    public new View View
    {
        get { return base.View; }
        private set { base.View = value; }
    }

    public CustomLabelCell()
    {
        this.label = new Label()
        {
            Text = this.Text
        };
        ContentView frame = new ContentView()
        {
            Padding = new Thickness(4.0),
            Content = label
        };
        this.View = frame;
    }

    protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        base.OnPropertyChanged(propertyName);

        if (propertyName == TextProperty.PropertyName)
        {
            this.label.Text = this.Text;
            ForceUpdateSize();
        }
    }
}

這就是您在ListView中使用它的方式:

ListView listView = new ListView(ListViewCachingStrategy.RecycleElement)
{
    HasUnevenRows = true,
    ItemsSource = new ObservableCollection<TestObj> { new TestObj("one - example text that will reach s e c o n d row"), new TestObj("two"), new TestObj("three - longer example text with more words for third row that will span across three rows"), new TestObj("four"), new TestObj("five") },
    ItemTemplate = new DataTemplate(typeof(CustomLabelCell))
};
listView.ItemTemplate.SetBinding(CustomLabelCell.TextProperty, "Name");

為了完整起見,這是TestObj的實現:

public class TestObj : System.ComponentModel.INotifyPropertyChanged
{
    private string name;

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs("Name"));
        }
    }

    public TestObj(string name)
    {
        this.name = name;
    }
}

如您所見,沒有必要在特定於平台的代碼中創建自定義渲染器和自定義單元。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM