简体   繁体   English

Xamarin自定义UITableViewCell重复使用时重叠文本

[英]Xamarin custom UITableViewCell overlapping text on reuse

I'm using the Monotouch.Dialog framework to build forms for user input my app. 我正在使用Monotouch.Dialog框架来构建供用户输入应用程序的表单。 I have run into an odd problem where the screen displays overlapping text when I subclass UITableViewCell. 我遇到一个奇怪的问题,当我继承UITableViewCell时,屏幕显示重叠的文本。 When I say text overlapping I mean it looks as if one entire cell is placed on top of another, not just labels being pushed together or misplaced. 当我说文本重叠时,我的意思是好像整个单元格都放在另一个单元格之上,而不仅仅是标签被推到一起或放错位置。

I followed this example on the Xamarin website here . 我跟着Xamarin网站上的这个例子在这里

Basically I have this UITableViewCell class 基本上我有这个UITableViewCell类

public class SAFutureAdCell : UITableViewCell
{
    private UILabel issueAndSizeLabel, mailDateLabel, orderDateLabel, miscLabel, totalLabel;
    private UIImage monthlyImage, ccoImage;

    public SAFutureAdCell(IntPtr p) : base(p) 
    {
        init ();
    }
    public SAFutureAdCell(string resuseIdentifier) : base(UITableViewCellStyle.Default, resuseIdentifier)
    {
        init ();
    }
    public SAFutureAdCell(NSString cellKey): base(UITableViewCellStyle.Default, cellKey)
    {
        init ();
    }

    private void init()
    {
        issueAndSizeLabel = new UILabel() {
            TextColor = UIColor.Black,
            Font = UIFont.BoldSystemFontOfSize(15),
            BackgroundColor = UIColor.Clear,
            ShadowColor = UIColor.Clear,
            TextAlignment = UITextAlignment.Left,
            ClipsToBounds = true
        };

        mailDateLabel = new UILabel() {
            TextColor = UIColor.Black,
            Font = UIFont.BoldSystemFontOfSize(15),
            BackgroundColor = UIColor.Clear,
            ShadowColor = UIColor.Clear,
            TextAlignment = UITextAlignment.Left,
            ClipsToBounds = true
        };

        orderDateLabel = new UILabel() {
            TextColor = UIColor.Gray,
            Font = UIFont.SystemFontOfSize(13),
            BackgroundColor = UIColor.Clear,
            ShadowColor = UIColor.Clear,
            TextAlignment = UITextAlignment.Left,
            ClipsToBounds = true
        };

        miscLabel = new UILabel() {
            TextColor = UIColor.Gray,
            Font = UIFont.SystemFontOfSize(13),
            BackgroundColor = UIColor.Clear,
            ShadowColor = UIColor.Clear,
            TextAlignment = UITextAlignment.Right,
            ClipsToBounds = true
        };

        totalLabel = new UILabel() {
            TextColor = UIColor.Black,
            Font = UIFont.BoldSystemFontOfSize(15),
            BackgroundColor = UIColor.Clear,
            ShadowColor = UIColor.Clear,
            TextAlignment = UITextAlignment.Right,
            ClipsToBounds = true
        };

        monthlyImage = AppearanceManager.MonthlyIndicator; // small blue circle
        ccoImage = AppearanceManager.CcoIndicator; // small red circle
        ImageView.Image = monthlyImage;
        ImageView.ContentMode = UIViewContentMode.ScaleAspectFit;

        ContentView.AddSubviews(issueAndSizeLabel, mailDateLabel, orderDateLabel, miscLabel, totalLabel);

    }

    public override void LayoutSubviews()
    {
        base.LayoutSubviews();

        Accessory = UITableViewCellAccessory.DisclosureIndicator;

        var b = ContentView.Bounds;
        b.Width -= 30;
        var x = 24;

        issueAndSizeLabel.Frame = new RectangleF(x, 5, b.Width / 2, b.Height / 2 - 5).RoundFloats();
        mailDateLabel.Frame = new RectangleF(issueAndSizeLabel.Frame.Right, 5, b.Width / 4, b.Height / 2 - 5).RoundFloats();
        totalLabel.Frame = new RectangleF(mailDateLabel.Frame.Right, 5, b.Width / 4, b.Height / 2 - 5).RoundFloats();
        orderDateLabel.Frame = new RectangleF(x, b.Height / 2 + 5, b.Width / 3, b.Height / 2 - 10).RoundFloats();
        miscLabel.Frame = new RectangleF(totalLabel.Frame.Left, b.Height / 2 + 5, b.Width / 4, b.Height / 2 - 10).RoundFloats();
        ImageView.Frame = new RectangleF(5, 0, AppearanceManager.MonthlyIndicator.Size.Width, ContentView.Frame.Height);
    }

    public void Update(Ad ad)
    {
        issueAndSizeLabel.Text = string.Format("{0} - {1}", ad.IssueCode, ad.AdvertSize);
        mailDateLabel.Text = string.Format("Mail: {0}", ad.MailDate.ToShortDateString());
        orderDateLabel.Text = string.Format("Order: {0}", ad.OrderDate.ToShortDateString());
        miscLabel.Text = string.Format("Misc: {0}", ad.Misc.ToCurrency());
        totalLabel.Text = string.Format("Total: {0}", ad.Total.ToCurrency());

        if (ad.IsCCOPackage)
            ImageView.Image = ccoImage;
        else
            ImageView.Image = monthlyImage;

        ImageView.Alpha = (ad.IsMonthlyBilling || ad.IsCCOPackage) ? 1f : 0f;
    }
}

This cell gets used from this Element. 此单元格从此元素中使用。

public class SAFutureAdDetailElement : Element, IElementSizing
{
    public SAFutureAdDetailElement(Ad ad, NSAction tapped) : base("FutureAdDetail")
    {
        this.ad = ad;
        Tapped += tapped;
    }

    public SAFutureAdDetailElement(Ad ad) : base("FutureAdDetail")
    {
        this.ad = ad;
    }

    private static NSString cellKey = new NSString("SAFutureAdDetailElement");
    protected override NSString CellKey
    {
        get
        {
            return cellKey;
        }
    }

    public override UITableViewCell GetCell(UITableView tv)
    {
        var cell = tv.DequeueReusableCell (cellKey) as SAFutureAdCell;
        if (cell == null) {
            cell = new SAFutureAdCell(cellKey);
        }

        cell.Update (ad);

        return cell;
    }

    public override void Selected(DialogViewController dvc, UITableView tableView, NSIndexPath path)
    {
        if (Tapped != null)
            Tapped ();

        tableView.DeselectRow (path, true);
    }

    public float GetHeight(UITableView tableView, NSIndexPath indexPath)
    {
        return cellHeight;
    }

    private Ad ad;
    public event NSAction Tapped;

    private int cellHeight = 60;
}

A collection of these elements are added to an MTD Section like so 这些元素的集合像这样添加到MTD部分

Section CreateOnPageSection()
{
    var onPageSection = new Section ("Future On Page Ads");
    onPageSection.AddAll (
        from ad in orderInfo.AdsFuture
        where !Settings.offPageAdSizes.Contains (ad.AdvertSizeID)
        select new SAFutureAdDetailElement (
            ad, 
            () => {
                NavigationController.PushViewController (new FutureAdDetailController (customer.CustID, ad, this), true);
            }
        )
    );
    return onPageSection;
 }

Which is then added to a RootElement as a part of a DialogViewController. 然后将其作为DialogViewController的一部分添加到RootElement中。 The root element has 3 other sections added to it, all with custom elements that have their own custom UITableViewCells and they are all very similar. 根元素还添加了其他3个部分,所有部分都包含具有自己的自定义UITableViewCells的自定义元素,并且它们都非常相似。 They basically differ in the placement of the labels and the data that goes into the labels. 它们在标签的位置和放入标签的数据上基本上有所不同。

The text doesn't overlap until scrolling occurs or until you push a view onto the NavigationController and then pop back to this view. 直到发生滚动或将视图推到NavigationController上然后弹出回到该视图之前,文本不会重叠。 It is often difficult to reproduce on newer iPads as well (this app is iPad only). 通常也很难在较新的iPad上进行复制(此应用程序仅适用于iPad)。 This issue happens much more frequently on older iPad 2s. 在较旧的iPad 2s上,此问题的发生频率更高。 Sometimes i can get it to happen on my Air but it is much more difficult to make it happen on that machine. 有时我可以在Air上实现它,但是要在该机器上实现它要困难得多。

Here is a screenshot of the overlapping text. 这是重叠文本的屏幕截图。

IOS UITableViewCell Overlapping Text iOS UITableViewCell重叠文本

It has to be a case of cell not getting re-used properly. 这必须是单元无法正确重用的情况。 So my intuition is that a change in GetCell method will do the job. 所以我的直觉是,GetCell方法的更改将完成此工作。

public override UITableViewCell GetCell(UITableView tv)
{
    var cell = tv.DequeueReusableCell (cellKey);// as SAFutureAdCell;
    if (cell == null) {
        cell = new SAFutureAdCell(cellKey);
    }
    else
        {
            cell.Element = this;
        }

    cell.Update (ad);

    return cell;
}

Can you try changing GetCell method like this ? 您可以尝试更改这样的GetCell方法吗? It might fix it... 它可能会解决...

OK so I found answer to my own question. 好的,所以我找到了自己的问题的答案。 It looks like there is an issue with how LayoutSubviews works with the cell recycling. 看起来LayoutSubviews如何与单元回收一起工作时存在问题。 Basically what I did was I got rid of the custom cell and moved all of the display loginc into my GetCell method in the custom element. 基本上,我要做的是摆脱自定义单元,并将所有显示loginc移到自定义元素中的GetCell方法中。 The element class looks like so. 元素类看起来像这样。

public class SAFutureAdDetailElement : Element, IElementSizing
{
    public SAFutureAdDetailElement(Ad ad, NSAction tapped) : base("FutureAdDetail")
    {
        this.ad = ad;
        Tapped += tapped;
    }

    public SAFutureAdDetailElement(Ad ad) : base("FutureAdDetail")
    {
        this.ad = ad;
    }

    private static NSString cellKey = new NSString("SAFutureAdDetailElement");
    protected override NSString CellKey
    {
        get
        {
            return cellKey;
        }
    }

    public override UITableViewCell GetCell(UITableView tv)
    {
        var cell = tv.DequeueReusableCell (cellKey);
        if (cell == null) {
            cell = new UITableViewCell (UITableViewCellStyle.Default, cellKey);

            cell.IndentationLevel = 0;
            var x = 24;
            var contentWidth = tv.Bounds.Width - 30 - x;
            var issueAndSizeLabel = new UILabel (new RectangleF (x, 5, contentWidth / 2, cellHeight / 2 - 5).RoundFloats ()) {
                TextColor = UIColor.Black,
                Font = UIFont.BoldSystemFontOfSize (15),
                BackgroundColor = UIColor.Clear,
                ShadowColor = UIColor.Clear,
                TextAlignment = UITextAlignment.Left,
                ClipsToBounds = true,
                Text = string.Format ("{0} - {1}", ad.IssueCode, ad.AdvertSize)
            };

            var mailDateLabel = new UILabel (new RectangleF (issueAndSizeLabel.Frame.Right, 5, contentWidth / 4, cellHeight / 2 - 5).RoundFloats ()) {
                TextColor = UIColor.Black,
                Font = UIFont.BoldSystemFontOfSize (15),
                BackgroundColor = UIColor.Clear,
                ShadowColor = UIColor.Clear,
                TextAlignment = UITextAlignment.Left,
                ClipsToBounds = true,
                Text = string.Format ("Mail: {0}", ad.MailDate.ToShortDateString ())
            };

            var orderDateLabel = new UILabel (new RectangleF (x, cellHeight / 2 + 5, contentWidth / 3, cellHeight / 2 - 10).RoundFloats ()) {
                TextColor = UIColor.Gray,
                Font = UIFont.SystemFontOfSize (13),
                BackgroundColor = UIColor.Clear,
                ShadowColor = UIColor.Clear,
                TextAlignment = UITextAlignment.Left,
                ClipsToBounds = true,
                Text = string.Format ("Order: {0}", ad.OrderDate.ToShortDateString ())
            };

            var totalLabel = new UILabel (new RectangleF (mailDateLabel.Frame.Right, 5, contentWidth / 4, cellHeight / 2 - 5).RoundFloats ()) {
                TextColor = UIColor.Black,
                Font = UIFont.BoldSystemFontOfSize (15),
                BackgroundColor = UIColor.Clear,
                ShadowColor = UIColor.Clear,
                TextAlignment = UITextAlignment.Right,
                ClipsToBounds = true,
                Text = string.Format ("Total: {0}", ad.Total.ToCurrency ())
            };

            var miscLabel = new UILabel (new RectangleF (totalLabel.Frame.Left, cellHeight / 2 + 5, contentWidth / 4, cellHeight / 2 - 10).RoundFloats ()) {
                TextColor = UIColor.Gray,
                Font = UIFont.SystemFontOfSize (13),
                BackgroundColor = UIColor.Clear,
                ShadowColor = UIColor.Clear,
                TextAlignment = UITextAlignment.Right,
                ClipsToBounds = true,
                Text = string.Format ("Misc: {0}", ad.Misc.ToCurrency ())
            };

            var indicator = new UIImageView (new RectangleF (5, 0, AppearanceManager.MonthlyIndicator.Size.Width, cellHeight));
            indicator.ContentMode = UIViewContentMode.ScaleAspectFit;
            if (ad.IsCCOPackage) {
                indicator.Image = AppearanceManager.CcoIndicator;
            } else if (ad.IsMonthlyBilling) {
                indicator.Image = AppearanceManager.MonthlyIndicator;
            }

            cell.Accessory = UITableViewCellAccessory.DisclosureIndicator;

            cell.ContentView.AddSubviews (indicator, issueAndSizeLabel, mailDateLabel, orderDateLabel, miscLabel, totalLabel);
        }

        ((UILabel)cell.ContentView.Subviews[1]).Text = string.Format("{0} - {1}", ad.IssueCode, ad.AdvertSize);
        ((UILabel)cell.ContentView.Subviews[2]).Text = string.Format("Mail: {0}", ad.MailDate.ToShortDateString());
        ((UILabel)cell.ContentView.Subviews[3]).Text = string.Format("Order: {0}", ad.OrderDate.ToShortDateString());
        ((UILabel)cell.ContentView.Subviews[4]).Text = string.Format("Misc: {0}", ad.Misc.ToCurrency());
        ((UILabel)cell.ContentView.Subviews[5]).Text = string.Format("Total: {0}", ad.Total.ToCurrency());
        if (ad.IsCCOPackage) {
            ((UIImageView)cell.ContentView.Subviews [0]).Image = AppearanceManager.CcoIndicator;
        } else if (ad.IsMonthlyBilling) {
            ((UIImageView)cell.ContentView.Subviews [0]).Image = AppearanceManager.MonthlyIndicator;
        } else {
            ((UIImageView)cell.ContentView.Subviews [0]).Image = null;
        }
        return cell;
    }

    public override void Selected(DialogViewController dvc, UITableView tableView, NSIndexPath path)
    {
        if (Tapped != null)
            Tapped ();

        tableView.DeselectRow (path, true);
    }

    public float GetHeight(UITableView tableView, NSIndexPath indexPath)
    {
        return cellHeight;
    }

    private Ad ad;
    public event NSAction Tapped;

    private int cellHeight = 60;
}

The only thing I don't like about this is updating the cell values is kind of a pain since I have to grab the UILabel from an array of UIView s and cast them as such like this ((UILabel)cell.ContentView.Subviews[1]) , And good luck keeping track of which UILabel is which since you now can't use a variable name to reference the UILabel . 我唯一不喜欢的就是更新单元格值,这有点痛苦,因为我必须从UIView数组中获取UILabel并像这样((UILabel)cell.ContentView.Subviews[1])其中,好运保持跟踪UILabel是因为你现在已经不能用一个变量名来引用UILabel Yes I did try making the labels a private member of the element and tried updating them that way which didn't work. 是的,我确实尝试过将标签设置为元素的私有成员,并尝试以这种方式进行更新,但这是行不通的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM