UITableViewCell UIImageView在同一个表上的不同单元格之间移动

时间:2017-06-27 16:37:47

标签: c# ios iphone uitableview xamarin

当我在UITableView中滚动时,单个UITableViewCell的UIImageView子视图在其他单元格之间移动。这个问题不会花很长时间。只需向下滚动到列表底部,就会使回复指示符(UIImageView)在不同的单元格之间移动。

这是我的自定义表视图类:

/// <summary>
/// Control for interacting with comments
/// </summary>
public sealed class CommentView : UITableView
{
    /// <summary>
    /// Initializes with a data source
    /// </summary>
    /// <param name="source">Data source</param>
    /// <param name="useSeparators">Whether separators should be used between comments</param>
    public CommentView(UITableViewSource source, bool useSeparators)
    {
        AllowsSelection = true;
        SeparatorStyle = useSeparators ?
            UITableViewCellSeparatorStyle.SingleLine :
            UITableViewCellSeparatorStyle.None;
        Source = source;
        RowHeight = AutomaticDimension;
        EstimatedRowHeight = 100;
    }
}

以下是我的数据源中的GetCell方法:

/// <summary>
/// Gets the cell in the table view at the index given
/// </summary>
/// <param name="tableView">Table view to get cell from</param>
/// <param name="indexPath">Index to get cell at</param>
/// <returns>Cell at the index specified</returns>
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
    var comment = Data[indexPath.Row];
    var cell = tableView.DequeueReusableCell(CellId) as CommentCell;

    // ReSharper disable once PossibleNullReferenceException
    cell.LineCount = CommentLineCount;
    cell.HasReplies = comment.Replies.Count > 0;
    cell.UpdateCell(comment);
    cell.DrawIndicator(comment);
    if (!comment.IsReply)
    {
        DrawAccessories(comment, cell);
    }
    cell.UpdateConstraints();

    return cell;
}

这是完整的评论细胞&#39;类:

using App.Common.Models;
using App.iOS.Utilities;
using CoreGraphics;
using Foundation;
using System;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

namespace App.iOS.Views.Controls
{
    /// <summary>
    /// Custom cell control for displaying a single comment
    /// </summary>
    public sealed class CommentCell : UITableViewCell
    {
        private const string CustomCommentCss =
            "<style>*{{font-family:{0};font-size:{1};color:{2};}}span{{font-
weight:600;}}</style>";
        private static readonly CGRect ReplyIconDimensions = new CGRect(6, 6, 12, 9);
        private readonly UILabel _authorLabel;
        private readonly UILabel _commentLabel;
        private readonly UILabel _dateLabel;
        private readonly UIFont _font;

    private UIView _indicator;
    private ReplyCountIndicatorView _replyCountIndicator;

    public CommentCell(IntPtr p) : base(p)
    {
        SelectionStyle = UITableViewCellSelectionStyle.None;
        SeparatorInset = UIEdgeInsets.Zero;
        LayoutMargins = UIEdgeInsets.Zero;

        var textColor = Globals.ColorDark;

        _font = UIFont.FromName(Globals.FontSanFranLight, Globals.FontSizeBody);
        _authorLabel = new UILabel
        {
            Font = UIFont.FromName(Globals.FontSanFranSemiBold, Globals.FontSizeBody),
            Lines = 1,
            LineBreakMode = UILineBreakMode.TailTruncation,
            TextColor = textColor
        };
        _commentLabel = new UILabel
        {
            Font = _font,
            LineBreakMode = UILineBreakMode.TailTruncation,
            TextColor = textColor
        };
        _dateLabel = new UILabel
        {
            Font = UIFont.FromName(Globals.FontSanFranLight, Globals.FontSizeSmall),
            TextColor = Globals.ColorDisabled
        };

        ContentView.AddSubviews(_authorLabel, _commentLabel, _dateLabel);
    }

    /// <summary>
    /// Sets whether this cell has replies associated with it
    /// </summary>
    public bool HasReplies { private get; set; }

    /// <summary>
    /// Sets the number of lines in the comment field
    /// </summary>
    public int LineCount { set { _commentLabel.Lines = value; } }

    /// <summary>
    /// Updates the constraints of the subviews
    /// </summary>
    public override void UpdateConstraints()
    {
        base.UpdateConstraints();
        _authorLabel.SetContentCompressionResistancePriority(1000, UILayoutConstraintAxis.Vertical);
        _commentLabel.SetContentCompressionResistancePriority(1000, UILayoutConstraintAxis.Vertical);
        _dateLabel.SetContentCompressionResistancePriority(1000, UILayoutConstraintAxis.Vertical);
        _replyCountIndicator?.SetContentCompressionResistancePriority(1000, UILayoutConstraintAxis.Vertical);

        var leftMargin = AnnotationIndicator.Size.Width + 2 * Globals.MarginGrid;

        if (_replyCountIndicator != null && HasReplies)
        {
            ContentView.ConstrainLayout(() =>
                _authorLabel.Frame.Top == ContentView.Frame.Top + Globals.MarginGrid &&
                _authorLabel.Frame.Left == ContentView.Frame.Left + leftMargin &&
                _authorLabel.Frame.Right == ContentView.Frame.Right - Globals.MarginGrid &&

                _commentLabel.Frame.Top == _authorLabel.Frame.Bottom + Globals.MarginGrid / 4 &&
                _commentLabel.Frame.Left == _authorLabel.Frame.Left &&
                _commentLabel.Frame.Right == _authorLabel.Frame.Right &&

                _dateLabel.Frame.Top == _commentLabel.Frame.Bottom + Globals.MarginGrid / 4 &&
                _dateLabel.Frame.Left == _authorLabel.Frame.Left &&
                _dateLabel.Frame.Right == _authorLabel.Frame.Right &&

                _replyCountIndicator.Frame.Top == _dateLabel.Frame.Bottom + Globals.MarginGrid &&
                _replyCountIndicator.Frame.Left == _dateLabel.Frame.Left &&
                _replyCountIndicator.Frame.Width == Globals.SmallToolbarItemSize &&
                _replyCountIndicator.Frame.Height == Globals.SmallToolbarItemSize &&
                _replyCountIndicator.Frame.Bottom == ContentView.Frame.Bottom - Globals.MarginGrid);   
        }
        else
        {
            ContentView.ConstrainLayout(() =>
                _authorLabel.Frame.Top == ContentView.Frame.Top + Globals.MarginGrid &&
                _authorLabel.Frame.Left == ContentView.Frame.Left + leftMargin &&
                _authorLabel.Frame.Right == ContentView.Frame.Right - Globals.MarginGrid &&

                _commentLabel.Frame.Top == _authorLabel.Frame.Bottom + Globals.MarginGrid / 4 &&
                _commentLabel.Frame.Left == _authorLabel.Frame.Left &&
                _commentLabel.Frame.Right == _authorLabel.Frame.Right &&

                _dateLabel.Frame.Top == _commentLabel.Frame.Bottom + Globals.MarginGrid / 4 &&
                _dateLabel.Frame.Left == _authorLabel.Frame.Left &&
                _dateLabel.Frame.Right == _authorLabel.Frame.Right &&
                _dateLabel.Frame.Bottom == ContentView.Frame.Bottom - Globals.MarginGrid);
        }
    }

    /// <summary>
    /// Updates the contents of the cell
    /// </summary>
    /// <param name="comment">Comment to update cell for</param>
    public void UpdateCell(Comment comment)
    {
        // update the comment author
        _authorLabel.Text = string.IsNullOrWhiteSpace(comment.CreatedByUser.FirstName) &&
            string.IsNullOrWhiteSpace(comment.CreatedByUser.LastName) ?
                comment.CreatedByUser.Email :
                $"{comment.CreatedByUser.FirstName} {comment.CreatedByUser.LastName}";

        // update the text
        var attr = new NSAttributedStringDocumentAttributes { DocumentType = NSDocumentType.HTML };
        var nsError = new NSError();

        // TODO: This is where emoji rendering goes wrong
        var text = comment.Text.Insert(0, string.Format(CustomCommentCss,
            _font.FontDescriptor.Name, _font.PointSize,
            ColorConverter.ConvertToHex(_commentLabel.TextColor)));
        var mutableString = new NSMutableAttributedString(new NSAttributedString(
            text, attr, ref nsError));
        var mutableParagraph = new NSMutableParagraphStyle
        {
            Alignment = UITextAlignment.Left,
            LineBreakMode = UILineBreakMode.TailTruncation
        };
        mutableString.AddAttribute(UIStringAttributeKey.ParagraphStyle, mutableParagraph,
            new NSRange(0, mutableString.Length));
        mutableString.AddAttribute(UIStringAttributeKey.StrokeColor, Globals.ColorDark,
            new NSRange(0, mutableString.Length));
        _commentLabel.AttributedText = mutableString;

        // update the timestamp
        var localTime = TimeZone.CurrentTimeZone.ToLocalTime(
            comment.LastModifiedDateTime).ToString("g");
        _dateLabel.Text = comment.LastModifiedDateTime == comment.CreatedDateTime ? 
            localTime : $"Modified {localTime}";
    }

    /// <summary>
    /// Draws the appropriate type of indicator next to the author's name
    /// </summary>
    /// <param name="comment">Comment to draw indicator for</param>
    public void DrawIndicator(Comment comment)
    {
        // if we've already drawn the indicator and 
        // the comment has no annotation associated with it
        _indicator?.RemoveFromSuperview();

        // if the comment havs an annotation associated with it,
        // draw the annotation indicator
        if (comment.Annotation != null)
        {
            _indicator = new AnnotationIndicator
            {
                Location = new CGPoint(Globals.MarginGrid, Globals.MarginGrid),
                Number = comment.Annotation.AnnotationNumber,
                FillColor = Color.FromHex(comment.Annotation.FillColorValue).ToUIColor(),
                TextColor = Color.FromHex(comment.Annotation.TextColorValue).ToUIColor()
            };
            ContentView.AddSubview(_indicator);
        }

        // otherwise, draw the general comment indicator
        else
        {
            var dim = comment.IsReply ? ReplyIconDimensions :
                new CGRect(0, 0, AnnotationIndicator.Size.Width, AnnotationIndicator.Size.Height);
            _indicator = new UIImageView
            {
                ContentMode = UIViewContentMode.ScaleAspectFit,
                Frame = new CGRect(Globals.MarginGrid + dim.X, Globals.MarginGrid + dim.Y, dim.Width, dim.Height),
                Image = comment.IsReply ? UIImage.FromFile("reply.png") :
                    UIImage.FromFile("general_annotation_indicator.png")
            };
            ContentView.AddSubview(_indicator);
        }
    }

    /// <summary>
    /// Draws the reply count indicator
    /// </summary>
    /// <param name="comment">Comment to draw indicator for</param>
    public void DrawReplyCountIndicator(Comment comment)
    {
        if (_replyCountIndicator != null)
        {
            _replyCountIndicator.RemoveFromSuperview();
            _replyCountIndicator = null;
        }
        _replyCountIndicator = new ReplyCountIndicatorView(comment.Replies.Count);
        ContentView.AddSubview(_replyCountIndicator);
    }
}
}

以下是一些截图: Normal The reply indicator has now moved to another cell

1 个答案:

答案 0 :(得分:0)

DequeueReusableCell将从缓存中返回已存在的单元版本。它可能已经填充了先前使用的数据,因此您有责任确保正确重置任何数据字段等以反映当前单元格的状态。