iOS 中 UITableView 中的下拉列表
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33186659/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Drop-Down List in UITableView in iOS
提问by Meet Doshi
How to Create this type of tableview in iOS??
如何在 iOS 中创建这种类型的 tableview?
Here, If we tap on 1st row 'Account', then automatically it scrolled with some more rows which is showing in Image. And if again we tap on Account, then that view will be hidden.
在这里,如果我们点击第一行“帐户”,它会自动滚动显示在图像中的更多行。如果我们再次点击帐户,则该视图将被隐藏。
采纳答案by Nicolas Miari
You could have Account as a cell that expands on tap to reveal three buttons ("Profile", "Activate Account", "Change Password"), but that creates a problem: tapping around each of the three buttons will count as "user selected the Account cell" and trigger -tableView:didSelectRowAtIndexPath:
with the resulting expand/collapse of the cell.
您可以将帐户作为一个单元格,在点击时展开以显示三个按钮(“个人资料”、“激活帐户”、“更改密码”),但这会产生一个问题:点击三个按钮中的每一个都将计为“用户选择”帐户单元格”并触发单元格-tableView:didSelectRowAtIndexPath:
的展开/折叠。
Or you could make each of the hidden options ("Profile", "Activate Account", "Change Password") a separate table view cell. But I don't know how you could animate the three cells as a wholeexpanding and contracting (instead of each expanding separately from zero height to fully expanded).
或者您可以将每个隐藏选项(“配置文件”、“激活帐户”、“更改密码”)设为单独的表格视图单元格。但我不知道如何将三个单元格作为一个整体扩展和收缩进行动画处理(而不是每个单元格分别从零高度扩展到完全扩展)。
So, perhaps the best solution is to:
因此,也许最好的解决方案是:
- Have the evencells (indices: 0, 2, 4...) to fulfil both the role of "Menu title" and "Toggle menu open/close" (towards the associated odd cells described below).
- Interleave the (initially collapsed) "menu body" cells, each with one button per option (e.g. "Profile", "Activate Account", "Change Password"), laid out vertically, in the odd indices (1, 3, 5...). Use target-action to respond to the user selecting each option/button.
- Implement the table view delegate method so that only the even cells (menu headers) are selectable, and implement selection logic to expand/collapse the corresponding odd cell (inside -tableView:didSelectRowAtIndexPath:). For example, selecting the cell at index 0 ("Account") results in expanding/collapsing the cell at index 1 (menu with options "Profile", "Activate Account", "Change Password").
- 让偶数单元格(索引:0、2、4...)同时扮演“菜单标题”和“切换菜单打开/关闭”的角色(针对下面描述的相关奇数单元格)。
- 交错排列(最初折叠的)“菜单正文”单元格,每个单元格每个选项有一个按钮(例如“个人资料”、“激活帐户”、“更改密码”),垂直排列,以奇数索引(1、3、5。 ...)。使用 target-action 来响应用户选择每个选项/按钮。
- 实现表格视图委托方法,以便只有偶数单元格(菜单标题)是可选的,并实现选择逻辑来展开/折叠相应的奇数单元格(在 -tableView:didSelectRowAtIndexPath: 中)。例如,选择索引 0 处的单元格(“帐户”)会导致展开/折叠索引 1 处的单元格(带有“配置文件”、“激活帐户”、“更改密码”选项的菜单)。
It is not the most elegant use of UITableView, but will get the job done.
这不是 UITableView 最优雅的用法,但可以完成工作。
回答by Meet Doshi
You could easily set up a cell to LOOK like a header, and setup the tableView: didSelectRowAtIndexPath
to expand or collapse the section it is within manually.If I'd store an array of booleans corresponding the the "expended" value of each of your sections. You could then have the tableView:didSelectRowAtIndexPath
on each of your custom header rows toggle this value and then reload that specific section.
您可以轻松地将单元格设置为看起来像标题,并设置tableView: didSelectRowAtIndexPath
手动展开或折叠它所在的部分。如果我要存储与每个部分的“消耗”值相对应的布尔数组。然后,您可以tableView:didSelectRowAtIndexPath
在每个自定义标题行上切换此值,然后重新加载该特定部分。
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) {
///it's the first row of any section so it would be your custom section header
///put in your code to toggle your boolean value here
mybooleans[indexPath.section] = !mybooleans[indexPath.section];
///reload this section
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
}
}
You'd then setup your number numberOfRowsInSection
to check the mybooleans
value and return either 1 if the section isn't expanded, or 1+ the number of items in the section, if it is expanded.
然后,您numberOfRowsInSection
可以设置您的数字来检查mybooleans
值,如果该部分未展开,则返回 1,如果展开,则返回 1+ 部分中的项目数。
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (mybooleans[section]) {
///we want the number of people plus the header cell
return [self numberOfPeopleInGroup:section] + 1;
} else {
///we just want the header cell
return 1;
}
}
You would also have to update your cellForRowAtIndexPath
to return a custom header cell for the first row in any section
.
您还必须更新您的cellForRowAtIndexPath
以返回 any 中第一行的自定义标题单元格section
。
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
is the better way to provide your "own custom header", as that's exactly what it's designed to do.
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
是提供“自己的自定义标题”的更好方法,因为这正是它的设计目的。
For more details, Refer this Answeror this PKCollapsingTableViewSections.
有关更多详细信息,请参阅此答案或此PKCollapsingTableViewSections。
Also, You can get this type of tableviews using setIndentationLevel
. Please refer this DemoCodefor this example. I think this the best solution for Drop-Down tableviews.
此外,您可以使用setIndentationLevel
. 有关此示例,请参阅此DemoCode。我认为这是下拉表格视图的最佳解决方案。
If you want to make a simple header and cell drop down, then please refer STCollapseTableView.
如果你想制作一个简单的标题和单元格下拉菜单,请参考STCollapseTableView。
Hope, this is what you're looking for. Any concern get back to me. :)
希望,这就是你要找的。有任何问题都可以回复我。:)
回答by Cristik
The easier and most natural way to implement this if via table view cells. No expanding cell views, no section headers, plain and simply cells (we're in a table view after all).
如果通过表格视图单元格来实现这一点,则是最简单、最自然的方法。没有扩展的单元格视图,没有节标题,简单的单元格(毕竟我们在表格视图中)。
The design is as following:
设计如下:
- using a MVVM approach, create a
CollapsableViewModel
class that holds the information needed to configure the cell: label, image - besides the above one, there are two extra fields:
children
, which is an array ofCollapsableViewModel
objects, andisCollapsed
, which holds the state of the drop down - the view controller holds a reference to the hierarchy of
CollapsableViewModel
, as well as a flat list containing the view models that will be rendered on the screen (thedisplayedRows
property) - whenever a cell is tapped, check if it has children, and add or remove rows in both
displayedRows
and in the table view, via theinsertRowsAtIndexPaths()
anddeleteRowsAtIndexPaths()
functions.
- 使用 MVVM 方法,创建一个
CollapsableViewModel
包含配置单元格所需信息的类:标签、图像 - 除了上面的,还有两个额外的字段:
children
,它是一个CollapsableViewModel
对象数组,和isCollapsed
,它保存下拉的状态 - 视图控制器持有对 的层次结构的引用
CollapsableViewModel
,以及包含将在屏幕上呈现的视图模型的平面列表(displayedRows
属性) - 每当点击单元格时,检查它是否有子项,并
displayedRows
通过insertRowsAtIndexPaths()
和deleteRowsAtIndexPaths()
函数在表格视图和表格视图中添加或删除行。
The Swift code is as following (note that the code makes use only of the label
property of the view model, to keep it clean):
Swift 代码如下(注意代码仅使用label
视图模型的属性,以保持其干净):
import UIKit
class CollapsableViewModel {
let label: String
let image: UIImage?
let children: [CollapsableViewModel]
var isCollapsed: Bool
init(label: String, image: UIImage? = nil, children: [CollapsableViewModel] = [], isCollapsed: Bool = true) {
self.label = label
self.image = image
self.children = children
self.isCollapsed = isCollapsed
}
}
class CollapsableTableViewController: UITableViewController {
let data = [
CollapsableViewModel(label: "Account", image: nil, children: [
CollapsableViewModel(label: "Profile"),
CollapsableViewModel(label: "Activate account"),
CollapsableViewModel(label: "Change password")]),
CollapsableViewModel(label: "Group"),
CollapsableViewModel(label: "Events", image: nil, children: [
CollapsableViewModel(label: "Nearby"),
CollapsableViewModel(label: "Global"),
]),
CollapsableViewModel(label: "Deals"),
]
var displayedRows: [CollapsableViewModel] = []
override func viewDidLoad() {
super.viewDidLoad()
displayedRows = data
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return displayedRows.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CellIdentifier") ?? UITableViewCell()
let viewModel = displayedRows[indexPath.row]
cell.textLabel!.text = viewModel.label
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
let viewModel = displayedRows[indexPath.row]
if viewModel.children.count > 0 {
let range = indexPath.row+1...indexPath.row+viewModel.children.count
let indexPaths = range.map { IndexPath(row: class CollapsableViewModel {
let label: String
let image: UIImage?
let children: [CollapsableViewModel]
var isCollapsed: Bool
var needsSeparator: Bool = true
init(label: String, image: UIImage? = nil, children: [CollapsableViewModel] = [], isCollapsed: Bool = true) {
self.label = label
self.image = image
self.children = children
self.isCollapsed = isCollapsed
for child in self.children {
child.needsSeparator = false
}
self.children.last?.needsSeparator = true
}
}
, section: indexPath.section) }
tableView.beginUpdates()
if viewModel.isCollapsed {
displayedRows.insert(contentsOf: viewModel.children, at: indexPath.row + 1)
tableView.insertRows(at: indexPaths, with: .automatic)
} else {
displayedRows.removeSubrange(range)
tableView.deleteRows(at: indexPaths, with: .automatic)
}
tableView.endUpdates()
}
viewModel.isCollapsed = !viewModel.isCollapsed
}
}
The Objective-C counterpart is easy to translate, I added the Swift version only as it's shorter and more readable.
Objective-C 版本很容易翻译,我添加 Swift 版本只是因为它更短且更易读。
With a couple of small changes, the code can be used to generate drop down lists of multiple levels.
通过一些小的更改,该代码可用于生成多个级别的下拉列表。
Edit
编辑
People asked me about the separators, this can be achieved by adding a custom class CollapsibleTableViewCell
which get's configured with a view model (finally, move the cell configuration logic from the controller to where it belongs - the cell). Credits for the separator logic only for some of the cells go to people answering thisSO question.
人们问我关于分隔符的问题,这可以通过添加一个CollapsibleTableViewCell
使用视图模型配置的自定义类来实现(最后,将单元配置逻辑从控制器移动到它所属的位置 - 单元)。仅用于某些单元格的分隔符逻辑的积分归于回答此SO 问题的人。
Firstly, update the model, add a needsSeparator
property that tells the table view cell to render or not the separator:
首先,更新模型,添加一个needsSeparator
属性来告诉表格视图单元格是否呈现分隔符:
class CollapsibleTableViewCell: UITableViewCell {
let separator = UIView(frame: .zero)
func configure(withViewModel viewModel: CollapsableViewModel) {
self.textLabel?.text = viewModel.label
if(viewModel.needsSeparator) {
separator.backgroundColor = .gray
contentView.addSubview(separator)
} else {
separator.removeFromSuperview()
}
}
override func layoutSubviews() {
super.layoutSubviews()
let separatorHeight = 1 / UIScreen.main.scale
separator.frame = CGRect(x: separatorInset.left,
y: contentView.bounds.height - separatorHeight,
width: contentView.bounds.width-separatorInset.left-separatorInset.right,
height: separatorHeight)
}
}
Then, add the cell class:
然后,添加单元类:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = (tableView.dequeueReusableCell(withIdentifier: "CollapsibleTableViewCell") as? CollapsibleTableViewCell) ?? CollapsibleTableViewCell(style: .default, reuseIdentifier: "CollapsibleTableViewCell")
cell.configure(withViewModel: displayedRows[indexPath.row])
return cell
}
cellForRowAtIndexPath
would then need to be modified to return this kind of cells:
cellForRowAtIndexPath
然后需要修改以返回这种单元格:
class ClsMenuGroup: NSObject {
// We can also add Menu group's name and other details here.
var isSelected:Bool = false
var arrMenus:[ClsMenu]!
}
One last step, remove the default table view cell separators - either from xib or from code (tableView.separatorStyle = .none
).
最后一步,从 xib 或代码 ( tableView.separatorStyle = .none
) 中删除默认的表格视图单元格分隔符。
回答by HarshIT
Here is an MVCbased solution.
这是一个基于MVC的解决方案。
Create a Model class ClsMenuGroup for your Sections
为您的部分创建一个模型类 ClsMenuGroup
class ClsMenu: NSObject {
var strMenuTitle:String!
var strImageNameSuffix:String!
var objSelector:Selector! // This is the selector method which will be called when this menu is selected.
var isSelected:Bool = false
init(pstrTitle:String, pstrImageName:String, pactionMehod:Selector) {
strMenuTitle = pstrTitle
strImageNameSuffix = pstrImageName
objSelector = pactionMehod
}
}
Create a Model class ClsMenu for your Rows
为您的行创建模型类 ClsMenu
class YourViewController: UIViewController, UITableViewDelegate {
@IBOutlet var tblMenu: UITableView!
var objTableDataSource:HDTableDataSource!
var arrMenuGroups:[AnyObject]!
// MARK: - View Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
if arrMenuGroups == nil {
arrMenuGroups = Array()
}
let objMenuGroup = ClsMenuGroup()
objMenuGroup.arrMenus = Array()
var objMenu = ClsMenu(pstrTitle: "Manu1", pstrImageName: "Manu1.png", pactionMehod: "menuAction1")
objMenuGroup.arrMenus.append(objMenu)
objMenu = ClsMenu(pstrTitle: "Menu2", pstrImageName: "Menu2.png", pactionMehod: "menuAction2")
objMenuGroup.arrMenus.append(objMenu)
arrMenuGroups.append(objMenuGroup)
configureTable()
}
func configureTable(){
objTableDataSource = HDTableDataSource(items: nil, cellIdentifier: "SideMenuCell", configureCellBlock: { (cell, item, indexPath) -> Void in
let objTmpGroup = self.arrMenuGroups[indexPath.section] as! ClsMenuGroup
let objTmpMenu = objTmpGroup.arrMenus[indexPath.row]
let objCell:YourCell = cell as! YourCell
objCell.configureCell(objTmpMenu) // This method sets the IBOutlets of cell in YourCell.m file.
})
objTableDataSource.sectionItemBlock = {(objSection:AnyObject!) -> [AnyObject]! in
let objMenuGroup = objSection as! ClsMenuGroup
return (objMenuGroup.isSelected == true) ? objMenuGroup.arrMenus : 0
}
objTableDataSource.arrSections = self.arrMenuGroups
tblMenu.dataSource = objTableDataSource
tblMenu.reloadData()
}
// MARK: - Tableview Delegate
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let objTmpGroup = self.arrMenuGroups[indexPath.section] as! ClsMenuGroup
let objTmpMenu = objTmpGroup.arrMenus[indexPath.row]
if objTmpMenu.objSelector != nil && self.respondsToSelector(objTmpMenu.objSelector) == true {
self.performSelector(objTmpMenu.objSelector) // Call the method for the selected menu.
}
tableView.reloadData()
}
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let arrViews:[AnyObject] = NSBundle.mainBundle().loadNibNamed("YourCustomSectionView", owner: self, options: nil)
let objHeaderView = arrViews[0] as! UIView
objHeaderView.sectionToggleBlock = {(objSection:AnyObject!) -> Void in
let objMenuGroup = objSection as! ClsMenuGroup
objMenuGroup.isSelected = !objMenuGroup.isSelected
tableView.reloadData()
}
return objHeaderView
}
// MARK: - Menu methods
func menuAction1(){
}
func menuAction2(){
}
}
Create groups array in your ViewController
在您的 ViewController 中创建组数组
class DataObject
{
let name : String
let imageURL : NSURL?
private(set) var children : [DataObject]
init(name : String, imageURL : NSURL?, children: [DataObject]) {
self.name = name
self.imageURL = imageURL
self.children = children
}
convenience init(name : String) {
self.init(name: name, imageURL: nil, children: [DataObject]())
}
}
I have used HDTableDataSource in place of Tableview's data source methods. You may find example of HDTableDataSourcefrom Github.
我使用 HDTableDataSource 代替了 Tableview 的数据源方法。你可以从 Github找到HDTableDataSource 的例子。
Advantages of above code is
- You can anytime change the order of any menu or section or interchange menu and section, without changing other functions.
- You will not need to add long code of else if ladder in your tableview's delegate methods
- You can specify icon, title or other attribute for your menu item separately like adding badge count, changing selected menu's color etc.
- You may also use multiple cells or sections by applying minor changes to existing code
上面代码的优点是
- 您可以随时更改任何菜单或部分的顺序或交换菜单和部分,而无需更改其他功能。
- 您将不需要在 tableview 的委托方法中添加 else if 梯子的长代码
- 您可以分别为菜单项指定图标、标题或其他属性,例如添加徽章计数、更改所选菜单的颜色等。
- 您还可以通过对现有代码进行细微更改来使用多个单元格或部分
回答by Alexander Perechnev
Usually I do it by setting the row height. For example, you have two menu items with drop-down lists:
通常我通过设置行高来做到这一点。例如,您有两个带有下拉列表的菜单项:
- Menu 1
- Item 1.1
- Item 1.2
- Item 1.3
- Menu 2
- Item 2.1
- Item 2.2
- 菜单 1
- 项目 1.1
- 项目 1.2
- 项目 1.3
- 菜单 2
- 项目 2.1
- 项目 2.2
So you have to create a table view with 2 sections. The first section contains 4 rows (Menu 1 and it's items) and the seconds section contains 3 rows (Menu 2 and it's items).
所以你必须创建一个包含 2 个部分的表格视图。第一部分包含 4 行(菜单 1 及其项目),第二部分包含 3 行(菜单 2 及其项目)。
You always set height only for first row in section. And if user clicks on the first row, you expand this section rows by settings the height and reload this section.
您始终只为部分中的第一行设置高度。如果用户单击第一行,您可以通过设置高度扩展此部分行并重新加载此部分。
回答by Trung Phan
the easy way to do this is use UITableView section header as cell-> and set number of row is 0 and section.count for collapse and expand state.
最简单的方法是使用 UITableView 部分标题作为单元格-> 并设置行数为 0 和 section.count 用于折叠和展开状态。
.This is TableViewSection Header, isExpand -> section.count else return 0.
-Normal cell
-Normal cell
-Normal cell
.This is TableViewSection Header, isExpand -> section.count else return 0.
-Normal cell
-Normal cell
-Normal cell
.这是TableViewSection Header,isExpand -> section.count else return 0。
- 正常细胞
- 正常细胞
- 正常细胞
.这是TableViewSection Header,isExpand -> section.count else return 0。
- 正常细胞
- 正常细胞
- 正常细胞
回答by Rafa? Augustyniak
There is no built in control for tree-view like views in iOS framework - UIKit. As it was pointed out by other users, probably the simplest solution (without using any external libraries) is to add some custom logic to the UITableView
's delegate and data source to mimic desired behaviour.
在 iOS 框架UIKit 中没有像树视图那样的内置控件。正如其他用户所指出的那样,可能最简单的解决方案(不使用任何外部库)是向UITableView
的委托和数据源添加一些自定义逻辑以模拟所需的行为。
Fortunately, there are some open source libraries which allow you to implemented desired tree view like view without worrying about the details of expand/collapse operations. There are a couple of themavailable for iOS platform. In most cases these libraries just wrap UITableView
and provide you with programmer-friendly interface which allow you to focus on your problem and not on implementation details of the tree view.
幸运的是,有一些开源库允许您实现所需的树状视图,如视图,而无需担心展开/折叠操作的细节。有几个可用于 iOS 平台。在大多数情况下,这些库只是包装UITableView
并为您提供程序员友好的界面,使您可以专注于您的问题,而不是树视图的实现细节。
Personally, I'm the author of RATreeViewlibrary which purpose it to minimalize the cost needed to create tree view like views on iOS. You can check out example projects (available in Objective-cand Swift) to check how this control works and behaves. Using my control, it is really simple to create the view you want:
就我个人而言,我是RATreeView库的作者,它旨在最大限度地减少在 iOS 上创建树视图(如视图)所需的成本。您可以查看示例项目(在Objective-c和Swift 中可用)来检查此控件的工作方式和行为方式。使用我的控件,创建您想要的视图非常简单:
DataObject
struct will be used to keep information about the tree view node - it will be responsible for keeping information about the title of the cell, its image (if cell has image) and its children (if cell has children).
DataObject
struct 将用于保存有关树视图节点的信息 - 它将负责保存有关单元格标题、其图像(如果单元格有图像)及其子项(如果单元格有子项)的信息。
protocol TreeTableViewCell {
func setup(withTitle title: String, imageURL: NSURL?, isExpanded: Bool)
}
class ChildTreeTableViewCell : UITableViewCell, TreeTableViewCell {
func setup(withTitle title: String, imageURL: NSURL?, isExpanded: Bool) {
//implementation goes here
}
}
class RootTreeTableViewCell : UITableViewCell, TreeTableViewCell {
func setup(withTitle title: String, imageURL: NSURL?, isExpanded: Bool) {
//implementation goes here
}
}
- We will declare protocol
TreeTableViewCell
and implement two cells which conforms to that protocol. One of these cells will be used to display root items and another one will be used to display children of the root items.
- 我们将声明协议
TreeTableViewCell
并实现两个符合该协议的单元。这些单元格之一将用于显示根项目,另一个将用于显示根项目的子项。
let profileDataObject = DataObject(name: "Profile")
let privateAccountDataObject = DataObject(name: "Private Account")
let changePasswordDataObject = DataObject(name: "Change Password")
let accountDataObject = DataObject(name: "Account", imageURL: NSURL(string: "AccountImage"), children: [profileDataObject, privateAccountDataObject, changePasswordDataObject])
let groupDataObject = DataObject(name: "Group", imageURL: NSURL(string: "GroupImage"), children: [])
let eventDataObject = DataObject(name: "Event", imageURL: NSURL(string: "EventImage"), children: [])
let dealsDataObject = DataObject(name: "Deals", imageURL: NSURL(string: "DealsImage"), children: [])
data = [accountDataObject, groupDataObject, eventDataObject, dealsDataObject]
- In out view controller (MVC) or view model (MVVM) we define data structure responsible for backup up our tree view.
- 在视图控制器 (MVC) 或视图模型 (MVVM) 中,我们定义了负责备份树视图的数据结构。
func treeView(treeView: RATreeView, numberOfChildrenOfItem item: AnyObject?) -> Int {
if let item = item as? DataObject {
return item.children.count //return number of children of specified item
} else {
return self.data.count //return number of top level items here
}
}
func treeView(treeView: RATreeView, child index: Int, ofItem item: AnyObject?) -> AnyObject {
if let item = item as? DataObject {
return item.children[index] //we return child of specified item here (using provided `index` variable)
} else {
return data[index] as AnyObject //we return root item here (using provided `index` variable)
}
}
func treeView(treeView: RATreeView, cellForItem item: AnyObject?) -> UITableViewCell {
let cellIdentifier = item ? “TreeTableViewChildCell” : “TreeTableViewCellRootCell”
let cell = treeView.dequeueReusableCellWithIdentifier(cellIdentifier) as! TreeTableViewCell
//TreeTableViewCell is a protocol which is implemented by two kinds of
//cells - the one responsible for root items in the tree view and another
//one responsible for children. As we use protocol we don't care
//which one is truly being used here. Both of them can be
//configured using data from `DataItem` object.
let item = item as! DataObject
let isExpanded = treeView.isCellForItemExpanded(item) //this variable can be used to adjust look of the cell by determining whether cell is expanded or not
cell.setup(withTitle: item.name, imageURL: item.imageURL, expanded: isExpanded)
return cell
}
- Next we will need to implement couple of methods from the data source of the
RATreeView
.
- 接下来,我们需要从
RATreeView
.
@interface TestTableViewController ()
{
BOOL showMenu;
}
@implementation TestTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"accountMenu"];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"accountSubMenu"];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 0) {
// Account Menu
return 1;
}
if (showMenu) {
// Profile/Private Account/Change Password
return 3;
}
// Hidden Account Menu
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
if (indexPath.section == 0) {
cell = [tableView dequeueReusableCellWithIdentifier:@"accountMenu" forIndexPath:indexPath];
cell.textLabel.text = @"Account";
}
else
{
cell = [tableView dequeueReusableCellWithIdentifier:@"accountSubMenu" forIndexPath:indexPath];
switch (indexPath.row) {
case 0:
cell.textLabel.text = @"Profile";
break;
case 1:
cell.textLabel.text = @"Private Account";
break;
case 2:
cell.textLabel.text = @"Change Password";
break;
default:
break;
}
}
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0) {
// Click on Account Menu
showMenu = !showMenu;
[tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
Notice that using my library you don't have to care about expanding and collapsing of the cell - it is handled by the RATreeView
. You are responsible only for the data which is used to configure cells - the rest is handled by the control itself.
请注意,使用我的库,您不必关心单元格的展开和折叠 - 它由RATreeView
. 您只对用于配置单元格的数据负责 - 其余部分由控件本身处理。
回答by V? Ng?c Giang
Hope it help :)
希望它有帮助:)
回答by luckyShubhra
You need a Collapsable TableView. In order to achieve that, in your TableView you must keep track of which sections are collapsed (contracted) and which of them are expanded. For this you need to maintain a set of indices of sections that are expanded, or a boolean array where the value of each index indicates if the corresponding section is expanded or not. Check for the values at the specific index while assigning height to a certain row. Check this linkfor more help.
您需要一个可折叠的 TableView。为了实现这一点,在您的 TableView 中,您必须跟踪折叠(收缩)哪些部分以及展开哪些部分。为此,您需要维护一组展开的部分的索引,或者一个布尔数组,其中每个索引的值指示相应的部分是否被展开。在为特定行分配高度时检查特定索引处的值。查看此链接以获取更多帮助。
You can learn about Sectional TableViews here.
您可以在此处了解分段 TableView 。
There are third party libraries available on Github that can save you from the hustel. Have a look at CollapsableTableViewor CollapsableTable-Swift
Github 上有第三方库可以让你远离喧嚣。看看 CollapsableTableView或CollapsableTable-Swift
回答by Bhavuk Jain
If you don't like to use any external library, then you can make 2 custom cells. One that shows before expanding and the other one after expanding (with different identifiers). And when you click the cell, check if the cell is expanded or not. If not, use the expanded cell identifier otherwise the non expanded cell identifier.
如果您不喜欢使用任何外部库,那么您可以制作 2 个自定义单元格。一个在展开前显示,另一个在展开后显示(具有不同的标识符)。当您单击单元格时,检查单元格是否展开。如果不是,则使用扩展单元标识符,否则使用非扩展单元标识符。
It's the best and clean way to make an expanded table view cell.
这是制作扩展表格视图单元格的最佳且干净的方法。