iOS中UITableView的下拉列表

43

在此输入图片描述

如何在iOS中创建这种类型的TableView?

当我们点击第一行“账户”时,它会自动滚动并显示图像中显示的更多行。如果再次点击“账户”,那么该视图将被隐藏。

12个回答

2
根据@sticker的回答,您可以在运行时绑定

objc_setAssociatedObject

用于节索引,并使用他的逻辑。在使用标题视图上的tapgesture时,您可以获取节索引。
objc_getAssociatedObject.

UITapGestureRecognizer *singleTapRecogniser = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(gestureHandler:)] autorelease];
[singleTapRecogniser setDelegate:self];
singleTapRecogniser.numberOfTouchesRequired = 1;
singleTapRecogniser.numberOfTapsRequired = 1;   
[sectionHeaderView addGestureRecognizer:singleTapRecogniser];

如果您需要任何第三方库,可以尝试使用这个解决方案。

2
我喜欢@Cristik的解决方案,一段时间以前我也遇到了同样的问题,我的解决方案基于相同的原则;所以根据我当时的需求,我提出如下建议:
  1. 为了使它更加通用,表格的项不应该从专门为扩展功能而专门设计的类中继承,而是应该有一个定义必要属性的协议

  2. 我们可以扩展的级别数量上不应该有限制。因此,表格可以具有选项、子选项、子子选项等。

  3. 表格视图应使用任何常用动画(而不是reloadData)来显示或隐藏单元格

  4. 扩展操作不一定要附加到用户选择单元格上,例如单元格可以有一个UISwitch

实现的简化版本(https://github.com/JuanjoArreola/ExpandableCells)如下:

首先是协议:

protocol CellDescriptor: class {
    var count: Int { get }
    var identifier: String! { get }
}

一个不可展开的单元格始终只有一个计数:
extension CellDescriptor {
    var count: Int { return 1 }
}

随后是可扩展单元格协议:
protocol ExpandableCellDescriptor: CellDescriptor {
    var active: Bool { get set }
    var children: [CellDescriptor] { get set }

    subscript(index: Int) -> CellDescriptor? { get }
    func indexOf(cellDescriptor: CellDescriptor) -> Int?
}

Swift 的一个很酷的特性是我们可以在协议扩展中编写一些实现,所有符合协议的类都可以使用默认实现,因此我们可以像这样编写 countsubscriptindexOf 实现,以及其他一些有用的函数:

extension ExpandableCellDescriptor {
    var count: Int {
        var total = 1
        if active {
            children.forEach({ total += $0.count })
        }
        return total
    }

    var countIfActive: Int {
        ...
    }

    subscript(index: Int) -> CellDescriptor? {
        ...
    }

    func indexOf(cellDescriptor: CellDescriptor) -> Int? {
        ...
    }

    func append(cellDescriptor: CellDescriptor) {
        children.append(cellDescriptor)
    }
}

完整的实现在文件CellDescriptor.swift中。
此外,在同一文件中,有一个名为CellDescriptionArray的类,它实现了ExpandableCellDescriptor,并且不会单独显示单元格。
现在,任何类都可以符合先前的协议,而无需继承特定的类。对于GitHub上的示例代码,我创建了几个类:Option和ExpandableOption,这是ExpandableOption的样子:
class ExpandableOption: ExpandableCellDescriptor {

    var delegate: ExpandableCellDelegate?

    var identifier: String!
    var active: Bool = false {
        didSet {
            delegate?.expandableCell(self, didChangeActive: active)
        }
    }

    var children: [CellDescriptor] = []
    var title: String?
}

这是UITableViewCell的一个子类:

class SwitchTableViewCell: UITableViewCell, CellDescrptionConfigurable {

    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var switchControl: UISwitch!

    var cellDescription: CellDescriptor! {
        didSet {
            if let option = cellDescription as? ExpandableOption {
                titleLabel.text = option.title
                switchControl.on = option.active
            }
        }
    }

    @IBAction func activeChanged(sender: UISwitch) {
       let expandableCellDescriptor = cellDescription as! ExpandableCellDescriptor
       expandableCellDescriptor.active = sender.on
    }
}

请注意,您可以根据自己的喜好配置单元格及其类,可以添加图像、标签、开关等等;没有限制,也不需要更改协议。

最后,在TableViewController中创建选项树:

var options = CellDescriptionArray()

override func viewDidLoad() {
   super.viewDidLoad()

   let account = ExpandableOption(identifier: "ExpandableCell", title: "Account")
   let profile = Option(identifier: "SimpleCell", title: "Profile")
   let isPublic = ExpandableOption(identifier: "SwitchCell", title: "Public")
   let caption = Option(identifier: "SimpleCell", title: "Anyone can see this account")
   isPublic.append(caption)
   account.append(profile)
   account.append(isPublic)
   options.append(account)

   let group = ExpandableOption(identifier: "ExpandableCell", title: "Group")
   group.append(Option(identifier: "SimpleCell", title: "Group Settings"))
   options.append(group)
   ...
}

实现的其余部分现在非常简单:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
   return options.count
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
   let option = options[indexPath.row]!
   let cell = tableView.dequeueReusableCellWithIdentifier(option.identifier, forIndexPath: indexPath)

   (cell as! CellDescrptionConfigurable).cellDescription = option
   (option as? ExpandCellInformer)?.delegate = self
   return cell
}

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    guard let option = options[indexPath.row] else { return }
    guard let expandableOption = option as? ExpandableOption else { return }
    if expandableOption.identifier == "ExpandableCell" {
        expandableOption.active = !expandableOption.active
    }
}

func expandableCell(expandableCell: ExpandableCellDescriptor, didChangeActive active: Bool) {
    guard let index = options.indexOf(expandableCell) else { return }
    var indexPaths = [NSIndexPath]()
    for row in 1..<expandableCell.countIfActive {
        indexPaths.append(NSIndexPath(forRow: index + row, inSection: 0))
    }
    if active {
        tableView.insertRowsAtIndexPaths(indexPaths, withRowAnimation: UITableViewRowAnimation.Fade)
    } else {
        tableView.deleteRowsAtIndexPaths(indexPaths, withRowAnimation: UITableViewRowAnimation.Fade)
    }
}

这段代码看起来很长,但大部分只需要编写一次。用于正确绘制表格视图所需的大部分信息都存在于CellDescriptor.swift文件中,单元格配置代码存在于UITableViewCell子类中,而TableViewController本身的代码相对较少。

希望这能有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接