如何使序列迭代从UIView视图层次结构到根的所有祖先(超级视图)?

问题描述 投票:2回答:4

我希望UIView有一个属性,它返回层次结构中视图的所有祖先的序列。这对于找到与特定类型匹配的最近的目的非常有用:

let tableView = cell.ancestors.first(where: { $0 is UITableView })

实施ancestors财产的好方法是什么?

ios swift cocoa-touch uikit
4个回答
2
投票

使用来自Swift标准库的sequence(first:next:)函数,也可以实现更短的解决方案:

extension UIView {
    var ancestors: AnySequence<UIView> {
        return AnySequence<UIView>(
            sequence(first: self, next: { $0.superview }).dropFirst())
    }
}

1
投票

您可以实现符合Sequence的类型,并添加在扩展中返回它的属性。 Sequence通常需要一个makeIterator()方法,它返回一个符合IteratorProtocol的类型,但在这种情况下,我们可以使序列充当它自己的迭代器并为两者使用一种类型,这使事情变得非常简单:

斯威夫特3:

struct AncestorSequenceIterator: Sequence, IteratorProtocol {
    var current: UIView
    mutating func next() -> UIView? {
        guard let next = current.superview else { return nil }
        current = next
        return next
    }
}

extension UIView {
    var ancestors: AncestorSequenceIterator {
        return AncestorSequenceIterator(current: self)
    }
}

1
投票

您可以创建扩展并返回IteratorProtocol,以便能够执行第一个(where :)比较,如此,

extension UIView {

    var ancestors: AnyIterator<UIView> {
        var current: UIView = self

        return AnyIterator<UIView> {
            guard let parent = current.superview else {
                return nil
            }
            current = parent
            return parent

        }
    }
}

由于AnyIterator本身符合Sequence,因此您在上面显示的语句应该可以正常工作。

let tableView = cell.ancestors.first(where: { $0 is UITableView })

0
投票

Paulo Mattos的实现很好,但是对于您的特定用途,您可能需要这样的东西:

extension UIView {
    func nearestAncestor<T: UIView>(ofType type: T.Type) -> T? {
        if let me = self as? T { return me }
        return superview?.nearestAncestor(ofType: type)
    }
}

然后你可以像这样使用它:

guard let tableView = cell.nearestAncestor(ofType: UITableView.self) else { return }
// tableView at this point is type UITableView
© www.soinside.com 2019 - 2024. All rights reserved.