热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用UITableViewAutomaticDimension更新UITableViewCell后的生涩滚动

如何解决《使用UITableViewAutomaticDimension更新UITableViewCell后的生涩滚动》经验,为你挑选了3个好方法。

我正在构建一个具有用户提交帖子的Feed视图的应用.此视图具有UITableView自定义UITableViewCell实现.在这个单元格中,我有另一个UITableView用于显示注释.要点是这样的:

Feed TableView
  PostCell
    Comments (TableView)
      CommentCell
  PostCell
    Comments (TableView)
      CommentCell
      CommentCell
      CommentCell
      CommentCell
      CommentCell

初始订阅源将下载3条评论进行预览,但如果有更多评论,或者用户添加或删除评论,我想PostCell通过添加或删除CommentCells评论表内部来更新Feed表视图内的位置的PostCell.我目前正在使用以下帮助程序来完成此任务:

// (PostCell.swift) Handle showing/hiding comments
func animateAddOrDeleteComments(startRow: Int, endRow: Int, operation: CellOperation) {
  let table = self.superview?.superview as UITableView

  // "table" is outer feed table
  // self is the PostCell that is updating it's comments
  // self.comments is UITableView for displaying comments inside of the PostCell
  table.beginUpdates()
  self.comments.beginUpdates()

  // This function handles inserting/removing/reloading a range of comments
  // so we build out an array of index paths for each row that needs updating
  var indexPaths = [NSIndexPath]()
  for var index = startRow; index <= endRow; index++ {
    indexPaths.append(NSIndexPath(forRow: index, inSection: 0))
  }

  switch operation {
  case .INSERT:
    self.comments.insertRowsAtIndexPaths(indexPaths, withRowAnimation: UITableViewRowAnimation.None)
  case .DELETE:
    self.comments.deleteRowsAtIndexPaths(indexPaths, withRowAnimation: UITableViewRowAnimation.None)
  case .RELOAD:
    self.comments.reloadRowsAtIndexPaths(indexPaths, withRowAnimation: UITableViewRowAnimation.None)
  }

  self.comments.endUpdates()
  table.endUpdates()

  // trigger a call to updateConstraints so that we can update the height constraint 
  // of the comments table to fit all of the comments
  self.setNeedsUpdateConstraints()
}

override func updateConstraints() {
  super.updateConstraints()
  self.commentsHeight.cOnstant= self.comments.sizeThatFits(UILayoutFittingCompressedSize).height
}

这样就完成了更新.帖子已更新到位,并PostCell在预期内添加或删除了评论.我PostCells在feed表中使用自动调整大小.PostCell扩展的注释表显示所有注释,但动画有点不稳定,并且在进行单元格更新动画时,表格会向上和向下滚动十几个像素.

调整大小时的跳跃有点烦人,但后来我的主要问题出现了.现在,如果我在Feed中向下滚动,滚动就像以前一样平滑,但是如果我在单元格上方向上滚动,我只是在添加注释后调整大小,Feed会在到达Feed的顶部之前向后跳几次.我iOS8为Feed 设置了自动调整大小的单元格,如下所示:

// (FeedController.swift)
// tableView is the feed table containing PostCells
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 560

如果我删除了estimatedRowHeight,只要单元格高度发生变化,表格就会滚动到顶部.我现在感觉很困惑,作为一个新的iOS开发人员,可以使用你可能有的任何提示.



1> dosdos..:

这是我发现解决此类问题的最佳解决方案(滚动问题+ reloadRows + iOS 8 UITableViewAutomaticDimension);

它包括将每个高度保持在字典中并更新它们(在字典中),因为tableView将显示单元格.

然后,您将在- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath方法中返回已保存的高度.

你应该实现这样的事情:

Objective-C的

- (void)viewDidLoad {
    [super viewDidLoad];

    self.heightAtIndexPath = [NSMutableDictionary new];
    self.tableView.rowHeight = UITableViewAutomaticDimension;
}

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSNumber *height = [self.heightAtIndexPath objectForKey:indexPath];
    if(height) {
        return height.floatValue;
    } else {
        return UITableViewAutomaticDimension;
    }
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    NSNumber *height = @(cell.frame.size.height);
    [self.heightAtIndexPath setObject:height forKey:indexPath];
}

斯威夫特3

@IBOutlet var tableView : UITableView?
var heightAtIndexPath = NSMutableDictionary()

override func viewDidLoad() {
    super.viewDidLoad()

    tableView?.rowHeight = UITableViewAutomaticDimension
}

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    if let height = heightAtIndexPath.object(forKey: indexPath) as? NSNumber {
        return CGFloat(height.floatValue)
    } else {
        return UITableViewAutomaticDimension
    }
}

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    let height = NSNumber(value: Float(cell.frame.size.height))
    heightAtIndexPath.setObject(height, forKey: indexPath as NSCopying)
}


对我来说,它仍然不起作用,我有一个自定义的imageView,并根据宽度和高度的尺寸来更新其高度约束.即使缓存了单元格高度,滚动仍然会跳跃,特别是在具有与屏幕上当前高度不同的新单元格滚动到屏幕之前.
@dosdos上帝保佑你,老兄!
对我来说这是一个更好的解决方 它完美地运作
真正简单有效的解决方案.谢谢!

2> Gabriel Cart..:

我们遇到了同样的问题.它来自对单元格高度的错误估计,导致SDK强制导致较高的高度,这会导致向上滚动时单元格的跳跃.根据您构建单元的方式,解决此问题的最佳方法是实现该UITableViewDelegate方法- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath

只要您的估计非常接近细胞高度的实际值,这几乎可以消除跳跃和急动.这是我们实现它的方式,你将得到逻辑:

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
    // This method will get your cell identifier based on your data
    NSString *cellType = [self reuseIdentifierForIndexPath:indexPath];

    if ([cellType isEqualToString:kFirstCellIdentifier])
        return kFirstCellHeight;
    else if ([cellType isEqualToString:kSecondCellIdentifier])
        return kSecondCellHeight;
    else if ([cellType isEqualToString:kThirdCellIdentifier])
        return kThirdCellHeight;
    else {
        return UITableViewAutomaticDimension;
    }
}

添加了Swift 2支持

func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    // This method will get your cell identifier based on your data
    let cellType = reuseIdentifierForIndexPath(indexPath)

    if cellType == kFirstCellIdentifier 
        return kFirstCellHeight
    else if cellType == kSecondCellIdentifier
        return kSecondCellHeight
    else if cellType == kThirdCellIdentifier
        return kThirdCellHeight
    else
        return UITableViewAutomaticDimension  
}


@BryanAlger是对的.自动行高度不适用于具有大量高度差异的行的表.要获得可靠的平滑滚动,必须在heightForRowAtIndexPath方法中提供正确的结果,最好使用缓存的行高.否则,当tableView需要更新它的contentSize时,你会变得急躁,特别是在推送或显示另一个视图控制器并返回的情况下.不幸的是,自动行高仅适用于具有几行的简单tableView.
你尝试过我上面描述的方法吗?这是应该使用iOS 8的方式,不应该计算高度,因为框架已经处理它.如果实现heightForRowAtIndexPath方法,则只是覆盖SDK的行为.
在您实现heightForRowAtIndexPath的情况下,您没有使用自动单元格高度维度的功能.当然,实现它会起作用,但是你的细胞不是动态的.

3> 小智..:

dosdos的答案在Swift 2中为我工作

宣布伊娃

var heightAtIndexPath = NSMutableDictionary()

在func viewDidLoad()中

func viewDidLoad() {
  .... your code
  self.tableView.rowHeight = UITableViewAutomaticDimension
}

然后添加以下两种方法:

override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
   let height = self.heightAtIndexPath.objectForKey(indexPath)
   if ((height) != nil) {
     return CGFloat(height!.floatValue)
   } else {
    return UITableViewAutomaticDimension
   }
 }

override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
  let height = cell.frame.size.height
  self.heightAtIndexPath.setObject(height, forKey: indexPath)
}

SWIFT 3:

var heightAtIndexPath = [IndexPath: CGFloat]()

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return self.heightAtIndexPath[indexPath] ?? UITableViewAutomaticDimension
}

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    self.heightAtIndexPath[indexPath] = cell.frame.size.height
}


推荐阅读
  • 本题来自WC2014,题目编号为BZOJ3435、洛谷P3920和UOJ55。该问题描述了一棵不断生长的带权树及其节点上小精灵之间的友谊关系,要求实时计算每次新增节点后树上所有可能的朋友对数。 ... [详细]
  • 本文介绍了如何使用JavaScript的Fetch API与Express服务器进行交互,涵盖了GET、POST、PUT和DELETE请求的实现,并展示了如何处理JSON响应。 ... [详细]
  • Redux入门指南
    本文介绍Redux的基本概念和工作原理,帮助初学者理解如何使用Redux管理应用程序的状态。Redux是一个用于JavaScript应用的状态管理库,特别适用于React项目。 ... [详细]
  • 本文介绍如何从字符串中移除大写、小写、特殊、数字和非数字字符,并提供了多种编程语言的实现示例。 ... [详细]
  • JavaScript中的数组是数据集合的核心结构之一,内置了多种实用的方法。掌握这些方法不仅能提高开发效率,还能显著提升代码的质量和可读性。本文将详细介绍数组的创建方式及常见操作方法。 ... [详细]
  • 在编译BSP包过程中,遇到了一个与 'gets' 函数相关的编译错误。该问题通常发生在较新的编译环境中,由于 'gets' 函数已被弃用并视为安全漏洞。本文将详细介绍如何通过修改源代码和配置文件来解决这一问题。 ... [详细]
  • 本文探讨了如何通过预处理器开关选择不同的类实现,并解决在特定情况下遇到的链接器错误。 ... [详细]
  • 本文详细探讨了Android Activity中View的绘制流程和动画机制,包括Activity的生命周期、View的测量、布局和绘制过程以及动画对View的影响。通过实验验证,澄清了一些常见的误解,并提供了代码示例和执行结果。 ... [详细]
  • 在 Android 开发中,通过 Intent 启动 Activity 或 Service 时,可以使用 putExtra 方法传递数据。接收方可以通过 getIntent().getExtras() 获取这些数据。本文将介绍如何使用 RoboGuice 框架简化这一过程,特别是 @InjectExtra 注解的使用。 ... [详细]
  • 深入解析Spring启动过程
    本文详细介绍了Spring框架的启动流程,帮助开发者理解其内部机制。通过具体示例和代码片段,解释了Bean定义、工厂类、读取器以及条件评估等关键概念,使读者能够更全面地掌握Spring的初始化过程。 ... [详细]
  • HTML基础入门指南
    本文将深入浅出地介绍HTML的基础知识,包括其定义、开发工具、制定机构、特性、基本标签及更多实用内容。 ... [详细]
  • 微信小程序:授权登录与手机号绑定
    本文详细介绍了微信小程序中用户授权登录及绑定手机号的流程,结合官方指引和实际开发经验,提供了一套完整的实现方案,帮助开发者更好地理解和应用。 ... [详细]
  • 深入解析 Android IPC 中的 Messenger 机制
    本文详细介绍了 Android 中基于消息传递的进程间通信(IPC)机制——Messenger。通过实例和源码分析,帮助开发者更好地理解和使用这一高效的通信工具。 ... [详细]
  • 探讨ChatGPT在法律和版权方面的潜在风险及影响,分析其作为内容创造工具的合法性和合规性。 ... [详细]
  • 本文将继续探讨前端开发中常见的算法问题,重点介绍如何将多维数组转换为一维数组以及验证字符串中的括号是否成对出现。通过多种实现方法的解析,帮助开发者更好地理解和掌握这些技巧。 ... [详细]
author-avatar
我跟孔子一个姓
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有