我正在尝试为评论和回复面板创建一个两层的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();
}
}
以下是该问题的一些屏幕截图:
发布于 2017-05-10 01:59:26
您不需要使用两个表格视图,您可以尝试使用一个表格,将顶级评论作为部分,所有回复作为该部分的单元格。
发布于 2017-05-16 21:38:11
正如Pradeep所说,一个包含单元格的表视图将是正确的选择。但话虽如此,还是有很多条件的。因此,您的数据结构应该能够处理它。
https://stackoverflow.com/questions/43661676
复制相似问题