Tag: uitableview

使用Swift泛型处理单元动作

给iOS开发人员一个 表格视图 ,他将编写10多个有关如何处理单元格操作的实现。 由于我们在Chili Labs中经常处理表格和集合,因此我想提出一个通用的解决方案,以解决项目中的单元动作。 我之前的文章中介绍的使用单元配置器的解决方案效果很好。 因此,将其作为基本模式可能是一个好主意。 首先,让我们添加TableDirector类,该类将存储单元配置器,并将成为UITableView的委托和数据源。 首先,我们需要向CellAction枚举中再添加一种情况,并返回其hashValue。 这里最具挑战性的事情是如何将自定义操作传递给CellActionProxy对象。 可以通过NotificationCenter发送通知来完成。 我们可以为CellAction枚举添加扩展,以方便地发送通知。 动作数据将存储在结构中,并通过userInfo参数发送。 最后,我们需要在TableDirector类中订阅并处理通知。 现在我们可以调用“跟随”动作并进行处理。 而已! 现在,我们有了一种机制,可以通用地处理任何单元操作。 进行少量修改,即可用于处理UICollectionViewCell操作。

测试UITableViews数据源(第1部分)

在移动开发中,测试应用程序是一项非常重要的任务,特别是当您的产品需要经常发货并且您不是一个人的团队时。 但是,即使自第一天起就不应该将持续集成作为目标,但我们都知道,在现实世界中,我们大多数人都会跳入已经由其他人启动并且具有许多未经测试的代码的项目。 考虑到这一点,这将是我的第一篇有关代码测试及其有关在Swift中测试UITableView组件的文章。 更具体地说,有关如何测试UITableViewDataSource。 我选择该主题的主要原因是我花了大部分工作时间在Swift中进行开发,并且UITableViews是所有iOS应用程序中使用的最基本的组件之一。 代码结构 有关此项目的代码可在此处找到,并且由一个包含UITableView的单屏应用程序组成。 由于UITableViews是非常复杂的组件,并且我们可以使用许多不同的方式,因此本示例重点介绍如何测试所需的UITableViewDataSource方法,这些方法是: 如果下载并运行代码,您将看到一个空行的屏幕,该屏幕可滚动,但没有太多显示。 我曾经认为我需要查看自己所做的所有事情才能正确测试它。 一段时间后,我意识到可以分离逻辑和UI并分别对其进行测试。 这听起来像是显而易见的推理,但有时实践并不像理论那么容易。 TL; DR如果您对测试部分比对项目本身更感兴趣,请参考“ 测试”部分 。 AppDelegate.swift 这是我们应用程序的起点。 它有很多样板,通常我们不需要触摸它就可以开始开发任何东西。 但是,在这种情况下,我想将UIViewController与情节提要隔离,因此我插入了一个函数来手动设置RootViewController : 和功能: 该函数的作用是创建一个TodoListViewController实例并将其设置为我们的窗口rootViewController 。 通过这样做,我们将应用程序直接加载到我们要测试的UIViewController中 。 作为本文的补充,我们还将看到如何使用UI Test来测试是否正确加载了初始视图控制器。 TodoListAdapter.swift 由于我们要正确测试UITableViewDataSource ,因此最好将其与UIViewController分离。 为此,我们创建一个单独的类来实现数据源协议。 该适配器类也可以用于实现UITableView的委托,但这超出了本文的范围。 现在,让我们集中讨论如何实现数据源。 由于我们的适配器的主要目标是实现UITableViewDataSource协议,因此我们需要将该接口添加到适配器的声明中。 我们还需要添加一个NSObject 接口,因为UITableViewDataSource 需要符合NSObjectProtocol 太: 常数 为了能够利用iOS内存优化的优势,我们应该为UITableViewCells分配一个标识符,该标识符将使它们在需要时出队并再次使用,而不是每次都进行新分配。 由于我们的适配器将负责管理UITableView内容,因此让我们在其中添加一个常量,使我们可以在具有相同标识符的代码库之间保持一致。 变数 由于我们想将数据与UIViewController分离,所以我们创建一个变量以将我们的数据存储在适配器中,并创建一个适当的初始化器来接收该数据: 这样,每次创建适配器时,我们都可以为其分配用于呈现UITableView的数据 。 另外,这对于测试非常有用,因为我们可以根据需要在适配器内部直接模拟数据。 为简单起见,我们的数据将为Strings数组。 在以后的文章中,我将更好地解释如何在适配器内处理不同的数据类型,但是现在使用Strings就足够了。 UITableViewDataSource 从根本上说,在测试UITableViewDataSource时,我们希望能够检查数据是否正确加载。 就像我之前说过的那样,有两种方法需要实现: tableView(UITableView,numberOfRowsInSection:Int) 此方法负责定义UITableView具有的数据的行数。 由于我们要在表视图中显示所有数据,因此我们将使其返回数据数组计数。 […]

使用自动布局和自动尺寸为UITableViewCell动画大小和文本更改

在我最近的iOS项目中,我有一个视图,其中内容显示为垂直可滚动的卡,并且每个卡都可以扩展以显示更多详细信息。 我已经将整个解决方案建模为UITableView ,其中每个单元格包含垂直堆叠的子视图(由于iOS 8的支持,我无法使用UIStackView ),并且每个子视图都使用其自己的视图模型进行了初始化(但这只是实现细节)。 在最终视图中,层次结构看起来类似于下图。 通过单击“ 更多和更少”按钮,“ 描述”字段在短文本和长文本之间切换。 从iOS 8开始,UITableView提供了一种自动管理UITableViewCell高度的简便方法,而无需手动计算并为每个单元格提供高度。 通过将行高设置为自动并提供估计的行高来完成 tableView.rowHeight = UITableViewAutomaticDimension tableView.estimatedRowHeight = 124 您只需要确保设置正确的约束即可,这意味着,例如,如果UILabel正确计算了其大小,便可以将其超级视图推到所需的大小。 这意味着您不能例如设置高度限制,最终应该从上到下固定标签。 我的情况非常简单,我只是将UILabel固定在每一侧。 当涉及到动画时,无需考虑高度就非常简单。 您只需更新文本并设置动画大小即可。 因此,代码如下所示: //细胞 @IBAction功能按钮MoreTouched(_发送方:UIButton){ labelDescription.text = longText 委托?.contentDidChange(cell:self) } //代表 扩展TableViewController:CellDelegate { func contentDidChange(cell:Cell){ UIView.animate(withDuration:1){ self.tableView.beginUpdates() self.tableView.endUpdates() } } } 结果是有效的,但存在一些缺陷。 文本立即更改,整个表格都具有动画效果。 但是,文本在垂直方向居中,在我看来,这不是故意的。 我想实现“更多显示”行为。

如何通过发送TableView / CollectionView数据源函数来简化UIViewControllers。

如何通过发送TableView / CollectionView数据源函数来简化UIViewControllers。 我非常喜欢小型UIViewControllers。 我总是尝试寻找使我的ViewController尽可能精简的不同方法。 使ViewController变大的主要可能性之一是在View Controller中拧紧UITableView或UICollectionView数据源函数。 首先,了解视图控制器需要在表视图或集合视图中显示哪些数据是必需的。 绝对不需要。 相反,如果视图控制器仅将该工作交给另一个对象,情况将会如何。 这个对象负责有关表视图/集合视图的所有事情。 让我们用一些基本的例子来研究它。 感谢您阅读这个故事。 希望您喜欢这篇文章。 快乐编码!

具有自动布局的表标题视图

请给我代码! 我一直在寻找如何在表格标题视图中使用自动布局。 设置表视图的tableHeaderView感觉就像将视图扔在一个黑洞中。 我们不知道它与层次结构中其他视图的关系。 最终,我找到了一种无需使用显式框架即可对我有效的解决方案。 注意:我将UIViewController和UITableView用作子视图,而不是UITableViewController。 要点: 1)设置表标题视图,2)将标题视图的centerX,width和top锚固定到表视图, 3)在表标题视图上调用layoutIfNeeded以更新其大小,4)*再次设置表视图标题。 脚步 在viewDidLoad() : 进行容器视图。 在此处添加所有内容。 确保正确设置约束以使其根据需要增长。 将tableHeaderView设置为容器 加 容器(现在为tableHeaderView)到表格视图的centerX,宽度和顶部锚点。 通过调用layoutIfNeeded()第一次更新标题视图框架,然后再次设置表标题视图。 就是这样。 // …在viewDidLoad()中 // 1。 让containerView = UIView() containerView.translatesAutoresizingMaskIntoConstraints = false // headerView是您的实际内容。 containerView.addSubview(headerView) // 2。 self.tableView.tableHeaderView = containerView // 3。 containerView.centerXAnchor.constraint(equalTo:self.tableView.centerXAnchor).isActive = true containerView.widthAnchor.constraint(equalTo:self.tableView.widthAnchor).isActive = true containerView.topAnchor.constraint(equalTo:self.tableView.topAnchor).isActive = true // 4。 self.tableView.tableHeaderView?.layoutIfNeeded() self.tableView.tableHeaderView = self.tableView.tableHeaderView […]

iOS UITableViewCell,UICollectionViewCell,UITableViewHeaderFooterView和UICollectionReusableView出队和注册-使用Swift协议和泛型

如果您是iOS开发人员,则每天都会遇到UITableView和UICollectionView。 您将需要使用在静态位置声明的丑陋标识符字符串来注册Cell或UITableViewHeaderFooterView或UICollectionReusableView重用单元格。 所以你的代码将是这样的 完成ReusableView.swift类以包含在项目中: 希望这将帮助您减少代码混乱,并简化注册和重用TableView和CollectionView单元格,HeaderFooterViews和ReusableSupplementary视图的使用,而无需在每个单元格类中维护难看的静态字符串常量。

如何将加载更多数据功能添加到UITableView

Load More Data View用于表示内部带有活动指示器的加载状态。 No More Data View用来表示不再有标签和按钮的数据状态,尝试再次加载更多数据。 接下来,将2个视图LoadMoreDataView和NoMoreDataView连接到LoadMoreDataView ,如下所示: 我们将编写一些方法来处理show加载更多数据状态或不显示更多数据状态的情况,如下所示: 接下来,我们需要更新fetchData方法以显示加载更多数据视图或不加载更多数据视图,如下所示: 接下来,当按下“重Try Again按钮时,我们将调用fetchData方法: 现在,尝试运行该应用程序,一切都将按预期运行。 您可以在此处下载完成的项目。

使用Swift创建自定义UITableViewCell

在 programmingwithswift.github.io上 查看我的其他帖子 UITableViews是iOS开发中最常用的视图之一。 大多数时候,您会想创建自定义UITableViewCells,因此在本教程中,我将向您展示如何创建自定义UITableViewCells。 在开始之前,我假设您已经有一个UITableView设置。 步骤1:建立新的Cocoa Touch类别 步骤2:设计单元 对于单元格设计,我将将高度设置为60,然后添加UITextField和UIButton。 稍后,我们将它们连接到UITableViewCell视图类。 将高度设置为60,请参见下图: 然后将UITextField和UIButton拖放到该视图中。 这就是我的风格。 下面是UITextField约束设置的图像: UIButton约束如下: 步骤3:向UITableView注册新的自定义UITableViewCell 注册新的自定义表格视图单元格。 在用于表视图的视图控制器中添加一个名为registerTableViewCells()的函数。 确保您有权访问表格视图。 您将需要使用tableview来注册新单元格。 您的函数应如下所示: 此代码正在注册一个新的自定义UITableViewCell。 在第一行中,我们创建一个新的UINib实例,第一个参数是nibName。 这必须是您创建的新单元格的名称,即文件名。 在第二行中,我们告诉UITableView我们要向其注册哪些新的自定义单元格,我们需要传递之前在该行中创建的UINib实例,然后需要为新单元格提供重用标识符。 在这种情况下,我只是使用文件名作为重用标识符,但是您可以根据需要提供任何名称。 步骤4:调用registerTableViewCells方法 为了调用上面创建的函数,我在viewDidLoad()函数中对其进行了调用。 我的viewDidLoad()函数如下所示: 步骤5:更新CellForRowAtIndexPath函数 为了使用新的单元格,您需要将以下代码添加到cellForRow委托方法中 只要确保使用您为类命名的名称和重用标识符来更新标识符和类名即可。 就是这样! 现在,您可以运行该应用程序,并且应该会在表格视图中看到自定义的UITableViewCell。 现在我们只需要在新单元格上连接UITextField和UIButton。 连接这些控件时,我们要做的只是打印您在文本字段中键入的文本。 步骤6:为UITextField和UIButton创建出口和功能 在此步骤中,您将需要创建您的商店。 我在下面提供了一张图像,该图像显示了我所做的事情。 完成创建网点后,您将需要创建一个新功能,如下图所示。 此函数将从文本字段获取值。 您现在应该可以运行该项目。 运行它时,应该显示一个自定义UITableViewCell。 您还应该能够在文本字段中键入一些内容,当您点击按钮时,它应该在Xcode的控制台中打印您在文本字段中键入的任何文本。

UITableView iOS中的自定义单元格

自定义UITableViewCell可以允许使用功能强大,动态且响应迅速的界面。 通过广泛的自定义并结合其他技术,您可以执行以下操作:更改特定的属性或界面元素,以便在单元中进行更改或设置动画或绘制图素;在用户滚动浏览时有效地加载视频,甚至从用户下载时显示图片网络。 这里的可能性几乎是无限的。 以下是自定义单元格的简单示例: 在包含tableView的UIViewController中,注册新的自定义单元格的类(请参见下文)。 请注意,仅当您未在表视图的界面中设计带有情节提要的单元格时,才有必要。 迅速 覆盖func viewDidLoad(){ super.viewDidLoad() //注册单元格类 tableView.register(CustomTableViewCell.self,forCellReuseIdentifier: CustomTableViewCell.identifier) } 如果您选择使用XIB文件,请改为registerNib //注册笔尖 tableView.register(UINib(nibName:CustomTableViewCell.identifier,bundle:nil), forCellReuseIdentifier:CustomTableViewCell.identifier) 现在您的tableView知道了您的自定义单元,您可以在cellForRowAtIndexPath中将其出队: 迅速 func tableView(tableView:UITableView,cellForRowAtIndexPath indexPath:NSIndexPath)-> UITableViewCell { //加载CustomTableViewCell。 确保此处提供的标识符与您的单元格中的标识符匹配 让单元格:CustomTableViewCell = tableView.dequeueReusableCellWithIdentifier(CustomTableViewCell.identifier)为! CustomTableViewCell //这就是神奇的地方-在自己的单元格上设置自定义属性 cell.customLabel.text =“我的自定义单元” 返回单元 }

添加滑动以删除UITableViewCell

添加以下两个功能: func tableView(tableView:UITableView,canEditRowAtIndexPath indexPath:NSIndexPath)->布尔{ 返回真 } func tableView(tableView:UITableView,commitEditingStyle editorStyle:UITableViewCellEditingStyle,forRowAtIndexPath indexPath:NSIndexPath){ 如果(editingStyle == UITableViewCellEditingStyle.Delete){ //处理删除(通过从数组中删除数据并更新tableview) } } Swift 3.0: 覆盖func tableView(_ tableView:UITableView,canEditRowAt indexPath:IndexPath)->布尔{ 返回真 }重写func tableView(_ tableView:UITableView,提交editingStyle:UITableViewCellEditingStyle,forRowAt indexPath:IndexPath){ 如果(editingStyle == UITableViewCellEditingStyle.delete){ //处理删除(通过从数组中删除数据并更新tableview) } } 在3.0+中,这些需要被覆盖