首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >自定义UITableViewCell:第一行没有内容

自定义UITableViewCell:第一行没有内容
EN

Stack Overflow用户
提问于 2017-04-27 23:13:27
回答 2查看 613关注 0票数 19

我正在尝试为评论和回复面板创建一个两层的UITableView实现。第一层包含所有顶级评论,如果有对该评论的回复,就会有一个指示器。当你点击一个顶层的注释单元格时,面板会在视图中显示一个新的UITableView。第一个单元格是用户点击的评论,下面是针对该评论的每个回复的单元格。

我通过使用两个不同的UITableViews和两个不同的UITableViewSources (但它们共享相同的基类)来实现。当用户点击顶层评论时,管理表格(CommentPanelViewController)的控制器将旧视图(顶层评论)动画移出视线,而新视图(回复)进入视线。

问题:

当我点击顶层评论时,除了它的指示器,什么也没有显示。所有其他回复都显示得很好,但顶级评论没有文本,没有作者,也没有时间戳。

为了保持简明和易于理解,我将只发布必要的代码。顶层的评论视图工作得很好,只有回复视图有错误,所以我们将从那里开始:

CommentSource -基础表源

public abstract class CommentSource : UITableViewSource
{
    protected List<Comment> _data;

    public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
    {
        var comment = _data[indexPath.Row];
        var cell = tableView.DequeueReusableCell(CellId)
            as CommentCell ?? new CommentCell(new NSString("CellId"), CommentLineCount,
            comment.Replies != null && comment.Replies.Count > 0);

        cell.SelectionStyle = UITableViewCellSelectionStyle.None;
        cell.LayoutMargins = UIEdgeInsets.Zero;
        cell.SeparatorInset = UIEdgeInsets.Zero;
        cell.SetNeedsUpdateConstraints();
        cell.UpdateConstraintsIfNeeded();
        cell.UpdateCell(comment);
        cell.DrawIndicator(comment);

        DrawAccessories(comment, cell);

        return cell;
    }

    protected virtual void DrawAccessories(Comment comment, CommentCell cell) { }

    protected abstract int CommentLineCount { get; }

    protected abstract string CellId { get; }

    public override nint RowsInSection(UITableView tableview, nint section) => _data?.Count ?? 0;

    public void UpdateData(IEnumerable<Comment> comments)
    {
        _data = OrderComments(comments);
    }

    private static List<Comment> OrderComments(IEnumerable<Comment> comments) =>
        comments?.OrderBy(x => x.CreatedDateTime).ToList();
}

CommentViewSource -顶级评论的来源

public class CommentViewSource : CommentSource
{
    protected override int CommentLineCount => 3;
    protected override string CellId => "CommentCell";

    public Action<Comment, bool> CommentSelected { get; set; }

    public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
    {
        var commentCell = tableView.CellAt(indexPath) as CommentCell;
        CommentSelected(_data[indexPath.Row], commentCell != null && commentCell.IsEllipsed);
    }

    protected override void DrawAccessories(Comment comment, CommentCell cell)
    {
        base.DrawAccessories(comment, cell);
        if (comment.Replies.Count > 0)
        {
            cell.DrawReplyCountIndicator(comment);
        }
    }
}

ReplyViewSource -回复的来源

public class ReplyViewSource : CommentSource
{
    protected override int CommentLineCount => 0;

    protected override string CellId => "ReplyCell";
}

因此,当选择顶级注释时,将调用处理的CommentViewSource.CommentSelected的CommentViewSource.RowSelected:

CommentPanelViewController.Constructor:

public CommentPanelViewController(CommentViewSource commentSource,
    CommentSource replySource, Action dismissHandler)
{
    _isReplyVisible = false;
    _commentSource = commentSource;
    _commentSource.CommentSelected += (comment, isEllipsed) =>
    {
        if (comment.Replies.Count <= 0 && !isEllipsed) { return; }

        var replies = new List<Comment>(comment.Replies);
        if (!replies.Contains(comment))
        {
            replies.Insert(0, comment);
        }
        _replySource.UpdateData(replies);
        _replyView.Table.ReloadData();
        AnimateReplyView(true);
    };
    _replySource = replySource;

    ..........
 }

现在是最大的一个,定制的UITableViewCell。此类用于回复和顶级评论:

CommentCell

public sealed class CommentCell : UITableViewCell
{
    private const string CustomCommentCss =
        "<style>*{{font-family:{0};font-size:{1};color:{2};}}span{{font-weight:600;}}</style>";
    private readonly bool _hasReplies;
    private readonly UILabel _creatorLabel;
    private readonly UILabel _commentLabel;
    private readonly UILabel _dateLabel;
    private readonly UIFont _font;
    private bool _didUpdateConstraints;
    private UIView _indicator;
    private ReplyCountIndicatorView _replyCountIndicator;

    public CommentCell(NSString cellId, int numberOfLines, bool hasReplies) :
        base(UITableViewCellStyle.Default, cellId)
    {
        _hasReplies = hasReplies;
        _didUpdateConstraints = false;
        SelectionStyle = UITableViewCellSelectionStyle.None;

        var textColor = Globals.ColorDark;

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

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

    public bool IsEllipsed => _commentLabel.Text.StringSize(
        _commentLabel.Font).Width > 3 * _commentLabel.Bounds.Size.Width;

    public override void UpdateConstraints()
    {
        base.UpdateConstraints();
        _creatorLabel.SetContentCompressionResistancePriority(1000, UILayoutConstraintAxis.Vertical);
        _commentLabel.SetContentCompressionResistancePriority(1000, UILayoutConstraintAxis.Vertical);
        _dateLabel.SetContentCompressionResistancePriority(1000, UILayoutConstraintAxis.Vertical);
        _replyCountIndicator?.SetContentCompressionResistancePriority(1000, UILayoutConstraintAxis.Vertical);

        if (_didUpdateConstraints || (_replyCountIndicator == null && _hasReplies)) { return; }

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

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

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

                _dateLabel.Frame.Top == _commentLabel.Frame.Bottom + Globals.MarginGrid / 4 &&
                _dateLabel.Frame.Left == _creatorLabel.Frame.Left &&
                _dateLabel.Frame.Right == _creatorLabel.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(() =>
                _creatorLabel.Frame.Top == ContentView.Frame.Top + Globals.MarginGrid &&
                _creatorLabel.Frame.Left == ContentView.Frame.Left + leftMargin &&
                _creatorLabel.Frame.Right == ContentView.Frame.Right - Globals.MarginGrid &&

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

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

        _didUpdateConstraints = true;
    }

    public void UpdateCell(Comment comment)
    {
        // update the comment author
        _creatorLabel.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();

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

    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()
            };
            AddSubview(_indicator);
        }

        // otherwise, draw the general comment indicator
        else
        {
            var size = comment.IsReply ? ReplyIndicator.DotSize : AnnotationIndicator.Size;
            _indicator = comment.IsReply ?
                new ReplyIndicator
                {
                    Frame = new CGRect(Globals.MarginGrid + size.Width / 2,
                        Globals.MarginGrid + size.Height / 2, ReplyIndicator.DotSize.Width,
                        ReplyIndicator.DotSize.Height)
                } as UIView :
                new UIImageView
                {
                    Image = UIImage.FromFile("general_annotation_indicator.png"),
                    Frame = new CGRect(Globals.MarginGrid, Globals.MarginGrid, size.Width, size.Height)
                };
            AddSubview(_indicator);
        }
    }

    public void DrawReplyCountIndicator(Comment comment)
    {
        if (_replyCountIndicator != null) { return; }

        _replyCountIndicator = new ReplyCountIndicatorView(comment.Replies.Count);
        ContentView.AddSubview(_replyCountIndicator);

        _didUpdateConstraints = false;
        UpdateConstraints();
    }
}

以下是该问题的一些屏幕截图:

EN

回答 2

Stack Overflow用户

发布于 2017-05-10 01:59:26

您不需要使用两个表格视图,您可以尝试使用一个表格,将顶级评论作为部分,所有回复作为该部分的单元格。

票数 1
EN

Stack Overflow用户

发布于 2017-05-16 21:38:11

正如Pradeep所说,一个包含单元格的表视图将是正确的选择。但话虽如此,还是有很多条件的。因此,您的数据结构应该能够处理它。

  1. 使用单元格(回复或评论)类型的枚举创建字典数组,并填充accordingly.
  2. You可以在GetCell方法中显示/隐藏分隔符的值。
  3. 如果将来需要像Facebook那样显示回复,甚至可以使用缩进。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43661676

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档