Monotouch中的DequeueReusableCell导致细胞在滚动时重新排列

时间:2012-07-18 22:44:54

标签: ios uitableview xamarin.ios monotouch.dialog

我正在使用Monotouch.Dialog类来填充UITableView。我正在使用自定义单元格,您可以看到元素中获取单元格的代码如下:

public override UITableViewCell GetCell (UITableView tv)
{
var cell = tv.DequeueReusableCell(_key) as FoodItemCell;

if (cell == null)
   cell = new FoodItemCell(_foodItem, _key);
else
   cell.UpdateCell(_foodItem);

return cell;
}

我从Miguel De Icaza网上发布了这个代码,建议为MonoTouch.Dialog创建自定义单元格的正确方法。

数据显示得恰当但是当我有一个很长的列表并且我快速向上和向下滚动时,单元格以随机不可预测的方式交换位置。因此,当我完成滚动时,行中的单元格可能会在第4行结束。

当我使用下面的代码时,这个问题就解决了,但正如你所看到的那样,我并没有将单元格排队,这可能会造成内存问题。

private FoodItemCell _currentCell;

public override UITableViewCell GetCell (UITableView tv)
{
    if(_currentCell == null)
    {
        _currentCell = new FoodItemCell(_foodItem, _key);
        return _currentCell;
    }
    else
    {
        return _currentCell;
    }
}

以下是完整代码:

public class FoodItemElement: Element
{
    private static NSString _key = new NSString ("foodItemCell");
    private FoodItem _foodItem;
    public event EventHandler<ElementClickedEventArgs> ElementClicked;


    public FoodItemElement(FoodItem foodItem): base(null)
    {
        _foodItem = foodItem;
    }

    public override UITableViewCell GetCell (UITableView tv)
    {
        var cell = tv.DequeueReusableCell(_key) as FoodItemCell;

        if (cell == null)
            cell = new FoodItemCell(_foodItem, _key);
        else
            cell.UpdateCell(_foodItem);

        return cell;
    }
}


public class FoodItemCell: UITableViewCell
{    
    private FoodItemCellDataView _dataView;
    private FoodItem _foodItem;

    public FoodItemCell(FoodItem data, NSString key) : base (UITableViewCellStyle.Default, key)
    {
        _foodItem = (FoodItem)data;
        _dataView = new FoodItemCellDataView(_foodItem);

        ContentView.Add(_dataView);
        ConstructCell();
    }

    public override void LayoutSubviews ()
    {
        base.LayoutSubviews ();
        _dataView.Frame = ContentView.Bounds;
        _dataView.SetNeedsDisplay ();
    }

     /// <summary>
     /// Updates the cell.
     /// </summary>
    public void UpdateCell(FoodItem newData)
    {
        _dataView.Update(newData);
        SetNeedsLayout();
    }

    /// <summary>
    /// Constructs the cell.
    /// </summary>
    private void ConstructCell()
    {
        //This prevents the default blue color when selecting the cell.
        //this.SelectionStyle = UITableViewCellSelectionStyle.None;
        //this.ContentView.BackgroundColor = UIColor.White;

        var lblFoodItemName = new UILabel();
        lblFoodItemName.Frame = new System.Drawing.RectangleF(4,2,270,20);
        lblFoodItemName.TextColor = UIColor.Black;
        lblFoodItemName.Font = Fonts.H3;
        lblFoodItemName.BackgroundColor = UIColor.Clear;
        lblFoodItemName.Text = _foodItem.Name;

        var lblCalories = new UILabel();
        lblCalories.Frame = new System.Drawing.RectangleF(15,22,75,20);
        lblCalories.TextColor = UIColor.Black;
        lblCalories.Font = Fonts.Small;
        lblCalories.BackgroundColor = UIColor.Clear;
        lblCalories.Text = "CAL - " + _foodItem.CaloriesRounded.ToString();

        var lblPortion = new UILabel();
        lblPortion.Frame = new System.Drawing.RectangleF(95,22,190,20);
        lblPortion.TextColor = UIColor.Black;
        lblPortion.Font = Fonts.Small;
        lblPortion.BackgroundColor = UIColor.Clear;
        lblPortion.Text = "Portion - " + _foodItem.Portion.ToString();

        this.ContentView.AddSubview(lblFoodItemName);
        this.ContentView.AddSubview(lblCalories);
        this.ContentView.AddSubview(lblPortion);

        Accessory = UITableViewCellAccessory.DisclosureIndicator;
    }   
}


// I create a view that renders my data, as this allows me to reuse
// the data rendering outside of a UITableViewCell context as well.
public class FoodItemCellDataView : UIView {

     public FoodItemCellDataView(FoodItem foodItem)
     {
          Update (foodItem);
     }

     // Public method, that allows the code to externally update
     // what we are rendering.   
     public void Update(FoodItem foodItem)
     {
          SetNeedsDisplay();
     }
}

有没有人知道如何正确地将单元格出列并且没有滚动问题?

2 个答案:

答案 0 :(得分:1)

您的代码没有显示_dataView.Update(newData)的功能,但我知道它不会更改单元格布局上的任何内容,只是使用新数据刷新UI元素。在这种情况下,(我一定是疯了矛盾米格尔),你应该到GetCell每次访问时被调用cell.UpdateCell(_foodItem)单元格是否出队还是新的,所以:

public override UITableViewCell GetCell (UITableView tv)
{
var cell = tv.DequeueReusableCell(_key) as FoodItemCell;

if (cell == null)
   cell = new FoodItemCell(_foodItem, _key);
// else  <- I would remove this
   cell.UpdateCell(_foodItem);

return cell;
}

答案 1 :(得分:0)

如果没有看到更多的源代码(请参阅我的评论),很难确定原因。

以下是一个可用于比较代码的工作示例(BubbleCell)。

一个重要的部分是在UpdateCell方法中调用SetNeedsLayout。否则,在完成刷新之前,内容可能会出现(在新的重用单元格中)。这可以解释你的问题。