Tag: Uitableviewcell

WBSwiftyMenu

WBSwipeableCell用于在TableViewCell和CollectionViewCell中显示选项菜单。 我们制作了此菜单,以在单个单元格中显示多个选项。 Apple在一个单元格中最多支持3个项目,但是在我们的控制器中,您可以添加3个以上的项目。 我已经从这个控制器中获取了这个想法-> https://github.com/SwipeCellKit/SwipeCellKit 背景 我已经为tableviewcell和collectionviewcell使用了许多菜单,但是它们都有一些局限性。 WBSwipeableCell用于菜单项过多且需要在一个视图中显示的地方。 示范 菜单垂直布局 对于Vertical菜单布局,我们需要实现MenuViewDelegate协议的一种可选委托方法,如下所示 func menuView(_ view:MenuView,menuLayoutForRowAtIndexPath indexPath:IndexPath)-> MenuLayout { 返回.vertical } 菜单方块布局 对于Square菜单布局,我们需要实现MenuViewDelegate协议的一种可选委托方法,如下所示 func menuView(_ view:MenuView,menuLayoutForRowAtIndexPath indexPath:IndexPath)-> MenuLayout { 返回.square } 菜单水平布局 对于水平菜单布局,我们需要实现MenuViewDelegate协议的一种可选委托方法,如下所示 func menuView(_ view:MenuView,menuLayoutForRowAtIndexPath indexPath:IndexPath)-> MenuLayout { 返回水平 } 有关此控制器的详细信息,可以在Github上进行检查:https://github.com/mwaqasbhati/WBSwipeableCell 我希望大家分叉它,并帮助我改进此库。

编写一次-在整个项目中随处使用,无条件-无修改

视力: 更少的代码,更少的错误,更少的测试用例 任务: 通过在极端情况下减少每种情况下的项目代码,减少错误的可能性并提高可伸缩性。 挑战是什么? 您是否曾经考虑过为整个项目只编​​写一次表视图委托和数据源? 一旦您完成了在一个位置编写代码的工作,即实现数据源和创建表视图的委托方法,就不需要在整个项目中实现数据源和表视图的委托的视图控制器,就必须在一个位置编写仅放置一次并使用很多次,当您将使用不同的单元设计开发新的屏幕时,不需要任何条件或修改。 您的可重用代码也必须可在其他项目中使用,而无需任何修改或条件。 您的解决方案必须是框架级别的解决方案,而不是项目级别的解决方案。 您无需在此处创建框架,但我的上下文是,您不能限制用户使用他/她自己的现有基类(如果他/她已经在项目中),例如UIViewController和UITabelViewCell的基类。 您不得限制用户访问Apple的UIKit提供的API来创建表视图或表视图单元格,应允许用户使用纯代码或XIB或情节提要创建表视图或单元格。 用户-正在使用您的可重用组件的用户 在常规编码中,每当在视图控制器中确认UITableViewDatasource时,编译器都会要求您提供两个必需的方法cellForRowAtIndexPath: 和 numberOfRowsInSection: 如果您错过了这两种方法中的任何一种,则会出现编译时错误。 您的可重用组件必须允许用户在需要时无限制地在view controller手动编写委托和数据源方法。 这意味着如果用户只想编写cellForRowAtIndexPath: 具有自定义逻辑且未实现numberOfRowsInSection:如果用户想要在cellForRowAtIndexPath:自定义逻辑,则该方法必须起作用cellForRowAtIndexPath: 只要。 同样,所有UITableViewDelegate方法也是如此。 不允许使用闭包或块或obj-c运行时 , 它只能通过委托模式来实现。 开始考虑挑战。 如何参加这项挑战? 推动自我,学习新事物并成为赢家。 1.只需填写此Google表单: https : //goo.gl/forms/zj2YrQu3H1LTbEKw2 2.为您的解决方案提供适当的步骤或Readme.md,因此我可以通过创建新的视图控制器,新的单元格和新的数据模型或字典来测试您的组件,从而对其进行测试。 3.解决方案提交: https : //goo.gl/forms/RIgCO1EAqmHgPGPN2 优胜者的奖金是多少? 获奖者将获得151.00 USD的奖金。 可能会增加到200.00 USD或更多,具体取决于参与者和获胜者的总数。 如果将有不止一名获奖者,我将按获奖者人数分配奖金。 如果有两名获胜者,则奖金为151.00美元 ,则每位获胜者将为151/2美元或更多 。 获奖者将如何获得奖金? 贝宝 UPI付款 Paytm | 免费|电话支付| G Pay(Google pay)应用 […]

UITableViewCell配置实践

假设我们的足球俱乐部模型具有以下界面: 足球俱乐部数据模型 根据俱乐部的属性值,我们的业务逻辑应确定进度的颜色和相应的装饰文字(正,负或破折号)。 1.门面式单元 苹果公司提供的本机UITableViewCell正是这种样式。 它提供了3个公共访问器来呈现内容: textLabel , detailTextLabel, imageView 。 但是,通常,我们需要更多的UI元素和自定义。 因此,我们可以将子视图添加到单元格的内容视图中,也可以创建UITableViewCell的自定义子类并添加必要的公共属性: 外墙样式的单元头文件 因此,业务逻辑由其数据源在外部进行管理: 外墙样式单元格配置 用户选择将按照以下方式处理: 外墙样式的用户选择逻辑 外墙风格的优点: 本机样式(Apple提供的样式)。 简单灵活,将来可以支持。 单元从外部填充,对业务逻辑一无所知。 外墙样式的缺点: 所有访问器都是公共的,这提供了低级别的封装。 要确定选择哪个足球俱乐部用户,您必须在数据源中执行其他搜索操作。 在动态数据更改的情况下,对数据源的附加搜索似乎是不可靠的,并且对于数据源不是PODS(普通旧数据源😏)的情况则很复杂,即它包含许多不同的模型,部分并且具有不均匀的结构。 2. VIPER样式的单元 我想用这种方式命名这种样式,因为它具有VIPER拱形固有的一些功能。 Cell仅提供设置值的公共方法,所有访问器都封装在“ .m”文件中: VIPER样式的单元公共API 在单元的实现中为访问器设置了相应的值。 从外面看起来像: per蛇式电池配置 VIPER风格的优点: 最高级别的封装。 单元从外部填充,对业务逻辑一无所知。 VIPER风格的缺点: 1.对于具有大量UI元素的“超载”单元格,与fe Facade样式的单元格相比,您的头文件将是双倍大小的(要设置标签的字体,文本和文本颜色,您必须向VIPER添加3种单独的方法样式的单元格公共API)。 在这里,我只引用Robert C. Martin在他的“ Clean Code”一书中提到的第4个简单设计规则: 最小的类和方法。 高等级的方法有时是无意义的教条主义的结果​​。 …我们的目标是使整个系统保持较小,同时还要使函数和类保持较小。 2.由于它不存储指向模型的指针-您将必须通过在数据源中进行附加搜索来确定选择了哪个足球俱乐部用户。 3.通过复杂数据源进行其他搜索会降低将来对应用程序的支持的简便性。 3. MVVM样式的单元 这种风格的主要特点是: 1)使用ViewModel,它关心业务逻辑并用数据填充单元格; […]

快速了解UITableViewCell可重用性

总览 表格视图在单个列中显示项目列表。 UITableView是UIScrollView的子类,尽管UITableView仅允许垂直滚动,但它允许用户滚动表。 组成表格中各个项目的单元格是UITableViewCell对象; UITableView使用这些对象绘制表的可见行。 Tableview不会在每次调用行单元格时都初始化单元格,它会重用 em。 明显!! every‍♂️每个人都知道,但问题是“ 如何?” ”。 诸如TableView之类的Apple API使用称为“ 对象池 ”的东西来进行管理。 对象池 对象池是一种设计模式,它可以重复使用🔄一组预初始化的对象,或者可以说它维护了实际需要的对象池,然后又一次又一次地重复使用它。 Tableview充当池的客户端,当它请求对象时,池将从池中返回一个实际项目,该项目可重复使用,而不是每次都初始化一个新对象。 当客户端完成对象处理后,该对象将返回到池中以供重用。 对象池用于提高性能,因为没有创建或销毁对象,而是将它们从池中抽出并在使用后返回给对象,从而节省了更多时间和内存复杂性。 在TableView的情况下很容易理解。 创建单元时,它是从池中提取的,在完成其工作时,或者万一可以说,在TableView中完成显示将返回到池中。 对象池的实现: 让我们尝试为自己创建对象池。 让我们创建一个可用于约束通用池项的协议。 协议可重复使用{ 函数重用() } 我们可以在协议中添加重用函数,在该协议中,当元素从池中重用时,我们可以重置视图以重用它,并重设视图(​​reuse)。 类ResuableCell:UITableViewCell,可重用{ 函数重用(){…} } 现在我们可以建立对象池了。 Pool { 私有let maxElement:Int 私人让生产者:()-> T public init(maxElementCount:Int,producer:@escaping()-> T){ 自我生产者=工厂 self.maxElement = maxElementCount } } maxElement是我们要在池中进行初始化的元素的最大数量,就像我们在TableView中具有numberOfRows或numberOfSections一样。 生产者函数需要告诉我们如何制作通用元素 我们需要再添加两个绘制和释放功能,例如在TableView中,该单元格在屏幕上显示后将被释放。 Pool { 私有let maxElement:Int […]

卸下电池样板

斯威夫特3.0 在iOS中,单元与可重复使用性的标识符相关联。 一个主要的难题是跟踪哪个小区标识符应该与哪个小区相关联。 借助协议的强大功能,开发人员不再需要手动创建这些标识符。 我们可以在内部将类名用作单元格标识符,并且可以通过包装程序处理所有此类。 一个可命名的协议将解决这个问题。 可命名 协议可命名{ 静态var名称:字符串{get} } 扩展名为{ 静态变量名称:字符串{ 返回字符串(描述:自我) } } 扩展UIView:可命名的{} 请注意,所有UIView都可以访问NameProtocol。 现在,我们可以使用类的名称作为单元格标识符。 碰巧的是,UICollectionViewCell继承了UICollectionReusableView的子类,而UICollectionReusableView继承了UIView的子类。 另外,UITableViewCell子类为UIView。 因此,我们的单元已经可以命名了! 寄存器 现在,我们可以使用类名直接在代码中注册单元格。 为了帮助删除更多样板,请将以下方法添加到UITableView扩展中。 func register(cells:[UITableViewCell.Type]){ cells.forEach { registerClass($0, forCellReuseIdentifier : $0.name) : $0.name) } } 现在,我们可以以简洁的格式优雅地整齐地注册我们的单元格。 您不再需要跟踪那些令人讨厌的标识符! 出队 现在已经注意了寄存器部分,让我们看一下出队。 将以下方法添加到您的UITableView扩展。 func dequeueReusableCell (对于indexPath:IndexPath)-> T { 返回dequeueReusableCell(withIdentifier:T.name,for:indexPath)为! Ť } 这将使用正确的标识符使单元出队。 同样,此包装器将返回适当的UITableViewCell子类。 行动中 在ViewControllers的viewDidLoad中,您可以注册单元格。 tableView.register([firstTableViewCell.self]) 在cellForRowAtIndexPath中,可以使用出队包装器。 […]

使用一流的对象创建具有多种单元格类型的UITableViews

问题 在AI公司工作时,您总是会做很多技术演示,以在野外使用某种技术。 现代算法往往具有很多您想尝试的参数,有时工作的结果只能由人类认可,尤其是当它与任何类型的图像处理/计算机视觉或AR / ML类型相关时应用程序,您必须用眼睛检查结果。 这通常导致必须创建一堆屏幕上的按钮/滑块,以便可以对核心逻辑进行参数设置,并查看新的超参数如何影响结果。 在进行了几次这样的演示之后,我决定创建一个自定义调试菜单,您可以在其中以声明方式添加几个选项,然后观察更改。 我一天通过分叉现有的调试工具Dotzu制作了原型。 项目仍处于起步阶段,但现在或多或少可以满足我的需求。 您可以在公共仓库中使用它。 以下是取得的成果的小演示: 现在,有趣的部分。 我们创建一个UITableViewController子类,在其故事板上没有单元原型: 所有的魔力都进入了它的实现。 让我们来看看: 在最底部,我们声明要呈现的模型数组 这是最有趣的部分。 由于一流的类型对象不可比,因此我们使用Swift标准库中的 ObjectIdentifier结构为每个Type对象创建Hashable / Equatable代理对象。 我们声明一个字典和两个方便的方法来注册并从中获取类型。 由于它是重复的代码部分,因此可能应将其移至称为TypeRegister或类似名称的单独类中。 3.在viewDidLoad()方法中,我们使用一个小的辅助方法将单元格类型注册到表视图中。 4.接下来,我们将关联的Model-View对注册到我们的类型字典中。 5.在cellForRowAt中:我们从数组中获得一个模型,为其确定一个单元格类型,并出列适当类型的单元格。 6.最后,我们告诉UITableView使用自动布局来计算单元格的高度,因为它可以从一个选项到另一个选项。 而已! 现在,您有了UITableView的60行代码的超灵活实现,可以处理其中无限数量的模型。 用法 框架的使用非常简单。 您所要做的就是通过调用一种方法来一次初始化调试菜单(通常在AppDelegate中): DebugMenu.sharedManager.enable() 然后以声明的方式声明您的选项(通常在控制器的viewDidLoad中 ): 通话开始的结果可以在故事开始的视频中看到 由于该仓库专用于调试,因此您可能希望使用#if DEBUG…#endif子句覆盖与DebugMenu的所有交互。 最后的话 由于UI工程不是我每天都会做的事情,因此,我很想听听您对这项技术的反馈,并希望听到关于如何做得更好的任何指导。 希望您喜欢阅读! 不要忘了在GitHub上使用仓库,并在Twitter上关注我。

UITableViewCells的带有复选按钮的多行选择(以编程方式)

UITableViewCells具有流行的附件类型“ .checkmark”和导航的“编辑”按钮项中众所周知的编辑功能。 但是,“邮件和消息”应用程序中鲜为人知的功能之一是显示用于多行选择的圆形复选框的选项。 通过互联网组合在一起解决此问题后,希望我可以省去您的精力! 这是有关如何完成的快速演示: 在继续之前,我想提醒您仔细查看如何以编程方式添加tableView和导航栏。 您可以检查AppDelegate.swift和ViewController.swift以获取详细信息。 在viewDidLoad()中,添加以下两行。 第一行向导航控制器添加了一个编辑按钮,第二行实现了显示动画复选框的内置功能,该复选框允许用户一次选择多个单元格。 tableView.allowsMultipleSelectionDuringEditing = true self.navigationItem.rightBarButtonItem = editButtonItem 3.因为我们有不同的部分,所以我们需要实现以下功能: 4.我们只想编辑第一部分的行 5.现在我们需要告诉应用程序删除我们选择的行 6.请记住,由于tableView是子视图,因此我们需要显式更新其编辑状态 7.在底部添加带有删除按钮的工具栏 8.通过遍历所有选定的行并将其删除来实现删除按钮 您可以在此处下载整个示例应用程序:https://github.com/mrachamallu/MultiSelectExample

快速的文字游戏,第二部分

在本文的第一部分中,我介绍了一些基本的代码来生成UITableView,其中的重要内容是拖放简短论文的主要内容。 当然,如果没有可编辑的表格视图,它的用途将非常有限,所以我认为我要做第二部分。 UITableView的最终目标应像这样,可以内联编辑,插入和删除条目。 首先,我们需要设置一个自定义UITableCell类,其中包含一个UITextField,代码如下所示。 类myTableViewCell:UITableViewCell,UITextFieldDelegate { 让标签:UITextField var listItems:myItem? { didSet { label.text = listItems!.text } } 所需的init(coder aDecoder:NSCoder){ fatalError(“ init(coder :)尚未实现”) } 覆盖init(样式:UITableViewCellStyle,复用标识符:字符串?){ 标签= UITextField(框架:CGRect.null) label.textColor = UIColor.black label.font = UIFont.systemFont(ofSize:16) super.init(样式:样式,reuseIdentifier:reuseIdentifier) label.delegate =自我 label.contentVerticalAlignment = UIControlContentVerticalAlignment.center addSubview(label) } 让leftMarginForLabel:CGFloat = 16.0 覆盖func layoutSubviews(){ super.layoutSubviews() label.frame = CGRect(x:leftMarginForLabel,y:0,width:bounds.size.width — leftMarginForLabel,高度:bounds.size.height) } func textFieldShouldReturn(_ textField:UITextField)-> […]

让我们做得更好:UITableViewCell

每个iOS开发人员都会创建UITableViewCells,但让我们做得更好。 根据我的实践,这里有五个原则。 TL; DR 在自己的小腿上做; 将用户界面设为私有; 不要配置模型; 让他们暗恋; 重用之前重设。 完整示例应用程序的源代码: https : //github.com/alekseishirokov/medium-01-better-uitableviewcell 每次在情节提要中创建新的UITableViewController时,XCode都会创建一个空单元格原型。 这导致开发人员使用此模板将UI元素直接放置到此单元格视图中。 但这是一个坏习惯。 迟早,您的项目经理会要求您使用完全相同的单元格设计,但要使用另一个表。 当他们告诉我不仅要在人员的详细信息视图中还必须在部门的详细信息视图中显示文档列表时,我已经摆脱了这种行为。 我文档的单元格原型包含10个UILabel,2个UIImageViews和一堆棘手的约束。 尽管XCode具有复制粘贴命令,但这并不容易。 让我们做得更好:在自己的xib文件中创建UITableViewCell并在所需的任何表中重复使用。 这很容易做到。 按Cmd + N创建一个新文件。 然后选择iOS → Cocoa Touch Class 。 然后在下拉菜单的子类中选择UITableViewCell ,输入类名,并选中“ 同时创建XIB文件”复选框。 XCode创建两个文件: DocumentTableViewCell.swift和DocumentTableViewCell.xib 。 使用xib文件将UI元素放入单元格视图中。 使用swift文件将IBOutlet与这些UI元素绑定。 然后,您可以在表视图控制器中使用此DocumentTableViewCell ,如下所示: 这意味着我需要重构每个使用我的DocumentTableViewCell的表视图控制器,如下所示: 如今,我做得更好。 我将UI出口声明为单元格视图专用。 我仅使用configure方法将数据传递给UI元素: 在表视图控制器中,您只需将文档的优先级作为参数传递给configure方法。 直觉是, 优先级是数据,取决于单元格视图如何显示数据。 同样,在单元设计发生更改的情况下,也无需重构表视图控制器。 即使在教程中,也通常通过将模型对象传递给configure方法来用数据填充单元格: 这似乎是一个优雅的解决方案,但事实并非如此。 这会将单元格的视图与模型对象耦合在一起。 单元格视图取决于模型对象的结构。 但是,我们坚持的MVC模式就是将视图和模型分离。 我倾向于将数据作为单独的参数传递给configure方法: […]

将UITextView嵌入UITableViewCell中

在Workable,我们有一个称为评估的功能。 部分原因是可以填写面试套件,如下所示。 当我们开始研究如何实现此功能时,出现的一个想法是使用堆栈视图,但是用户创建了采访工具包,因此它们的大小可能会有所不同。 因此,我们选择使用UITableView作为此屏幕的主干。 毕竟它只是UITableViewCell中的UITextView,对吗? 在本文中,我将尝试列出我们面临的所有问题以及如何解决这些问题。 在演练结束时,将附上完整的解决方案。 在单元格内添加UITextView 我们创建了一个原型单元,并添加了UITextView,如下所示。 另外,不要忘记在UITextView的属性检查器中关闭 Scrolling Enabled属性。 这使UITextView具有取决于文本的固有内容大小,或者接近于我们稍后发现的文本大小。 现在,我们希望能够编辑文本。 简单,只需启用UITextView的`Editable`属性即可。 但是我们有一个小问题,我们希望UITableViewCell跟随UITextView的高度。 我们可以从单元格创建一个回调,以通知我们任何文本更改,如下所示: 在TextTableViewCell.swift中 @IBOutlet弱var textView:UITextView! var textChanged:(((String)-> Void)? 覆盖func awakeFromNib(){ super.awakeFromNib() textView.delegate =自我 } func textChanged(action:@escaping(String)-> Void){ self.textChanged =操作 } func textViewDidChange(_ textView:UITextView){ textChanged?(textView.text) } 在TableTableViewController.swift-> cellForRow中 cell.textChanged {[weak tableView](newText:String)在 } 注意:不要忘了在此闭包的捕获列表中使tableView变弱,因为您将得到一个保留周期。 tableView->单元格(UI),单元格-> tableView(关闭) 我们唯一要做的就是重新加载单元。 我们有多种方法可以做到这一点,因此我们将尝试最常见的一种方法tableView.reloadData()。 cell.textChanged {[weak tableView](_)in //可能的解决方案:1 […]