web-dev-qa-db-ja.com

Swift:特定のタイプのすべてのサブビューを取得し、配列に追加します

UIViewにカスタムクラスのボタンがあり、それらを簡単にアクセスできるように配列に追加します。特定のクラスのすべてのサブビューを取得し、それをSwiftの配列に追加する方法はありますか?

35
Kenji Crosland

filter演算子を使用するis関数は、特定のクラスのアイテムをフィルターできます。

let myViews = view.subviews.filter{$0 is MyButtonClass}

MyButtonClassは、フィルタリングされるカスタムクラスです。

65
vadian

どうぞ

    extension UIView {

    /** This is the function to get subViews of a view of a particular type 
*/
    func subViews<T : UIView>(type : T.Type) -> [T]{
        var all = [T]()
        for view in self.subviews {
            if let aView = view as? T{
                all.append(aView)
            }
        }
        return all
    }


/** This is a function to get subViews of a particular type from view recursively. It would look recursively in all subviews and return back the subviews of the type T */
        func allSubViewsOf<T : UIView>(type : T.Type) -> [T]{
            var all = [T]()
            func getSubview(view: UIView) {
                if let aView = view as? T{
                all.append(aView)
                }
                guard view.subviews.count>0 else { return }
                view.subviews.forEach{ getSubview(view: $0) }
            }
            getSubview(view: self)
            return all
        }
    }

次のように呼び出すことができます

let allSubviews = view.allSubViewsOf(type: UIView.self)
let allLabels = view.allSubViewsOf(type: UILabel.self)
27
Mohammad Sadiq

これを再帰的に行う(つまり、すべてのサブビューのビューもフェッチする)には、次の汎用関数を使用できます。

private func getSubviewsOf<T : UIView>(view:UIView) -> [T] {
    var subviews = [T]()

    for subview in view.subviews {
        subviews += getSubviewsOf(view: subview) as [T]

        if let subview = subview as? T {
            subviews.append(subview)
        }
    }

    return subviews
}

ビュー階層内のすべてのUILabelを取得するには、次のようにします。

let allLabels : [UILabel] = getSubviewsOf(view: theView)
17
ullstrm

私は今それをテストすることはできませんが、これはSwift 2:

view.subviews.flatMap{ $0 as? YourView }

YourViewの配列を返します

カウントを取得するためのテスト済みの典型的な例を次に示します。

countDots = allDots!.view.subviews.flatMap{$0 as? Dot}.count
11
Kametrixom

これらの特定のサブビューを更新/アクセスする場合は、これを使用します。

for (index,button) in (view.subviews.filter{$0 is UIButton}).enumerated(){
    button.isHidden = false
}
5
Zaid Pathan
func allSubViews(views: [UIView]) {
    for view in views {
        if let tf = view as? UITextField {
             // Do Something
        }
        self.allSubViews(views: view.subviews)
    }
}

self.allSubViews(views: self.view.subviews)
3
Mustafa Alqudah

Swift 4.1から、新しいcompactMapを使用できます(flatMapは廃止されました): https://developer.Apple.com/documentation/Swift/sequence/2950916-compactmap =(内部の例を参照)

あなたの場合、次を使用できます:

let buttons:[UIButton] = stackView.subviews.compactMap{ $0 as? UIButton }

また、マップを使用してすべてのボタンに対してアクションを実行できます。

let _ = stackView.subviews.compactMap{ $0 as? UIButton }.map { $0.isSelected = false }
2
Diego Carrera

この場合、first.wherefilter.countよりも効率的なSwiftのfilter.isEmpty構文を使用できると思います。

filterを使用すると、基礎となる配列が作成されるため、効果的ではないため、大きなコレクションがあると想像してください。

ビューのsubViewsコレクションに特定の種類のクラスが含まれているかどうかを確認するだけで、これを使用できます

let containsBannerViewKind = view.subviews.first(where: { $0 is BannerView }) != nil

これは、このビューのsubViewsコレクションでBannerViewクラスに最初に一致するものを見つけます。したがって、これが当てはまる場合は、さらにロジックを実行できます。

リファレンス: https://github.com/realm/SwiftLint/blob/master/Rules.md#first-where

1
Vinh Nguyen

UIViewにはsubViewsという名前のプロパティがあり、APIを見ることができます。

0
Siam

これの私のバリエーションを投稿しましょう)しかし、これは、Tの最初を見つけます

extension UIView {

    func firstSubView<T: UIView>(ofType type: T.Type) -> T? {
        var resultView: T?
        for view in subviews {
            if let view = view as? T {
                resultView = view
                break
            }
            else {
                if let foundView = view.firstSubView(ofType: T.self) {
                    resultView = foundView
                    break
                }
            }
        }
        return resultView
    }
}
0
Mike Glukhov