모든 Subviews를 삭제하는 방법 [Swift 5]

15149 단어 Xcode12iOS14Swift5
안녕하세요, @Zhalen 입니다. 읽는 방법은 "차렌"입니다.

이 기사에서 알 수 있는 것



"Subview의 Subview의 Subview의 ..."를 모두 지우십시오.

라는 귀찮은 것 같은 처리를 짧은 익스텐션으로 기술할 수 있습니다.

Usage



그리고 그것은

self.view.removeAllSubviews()

이것 한 번으로 할 수 있습니다.

확장



이것이 그 내용입니다.

extension UIView {
    func removeAllSubviews() {
        if type(of: self) == UIStackView.self {
            (self as! UIStackView).arrangedSubviews.forEach { (arrangedSubview) in arrangedSubview.removeAllSubviewsForEach() }
        }
        self.subviews.forEach { (subview) in subview.removeAllSubviewsForEach() }
    }
    func removeAllSubviewsForEach() {
        if type(of: self) == UIStackView.self {
            if (self as! UIStackView).arrangedSubviews.isEmpty {
                self.removeFromSuperview()
            } else {
                (self as! UIStackView).arrangedSubviews.forEach { (arrangedSubview) in arrangedSubview.removeAllSubviewsForEach() }
            }
        }
        if self.subviews.isEmpty {
            self.removeFromSuperview()
        } else {
            self.subviews.forEach { (subview) in subview.removeAllSubviewsForEach()
            }
        }
    }
}


Mechanism



메커니즘은 다음과 같습니다.

우선 각각의 View를 원, view의 상하 관계를 왼쪽에서 오른쪽의 막대로 표현하면, 일반적인 view의 관계는 이런 느낌으로 표현할 수 있습니다.



점선은 임의 개·임의 회를 나타냅니다.

즉 이 경우는, 어느 하나의 view에 임의의 subview가 타고 있어, 한층 더 그 관계가 임의회 반복되고 있다고 하는 것입니다.

이것을 패턴별로 살펴보고 최종 결론(위)에 도달합니다.

정의: 층



큰 것은 아니지만, 다소 어색함을 방지하기 위해 단어를 정의합니다. 직관적으로는, 뷰 아래에 몇중의 view가 타고 있는가 하는 것이 됩니다.

view 단독으로만, 아무것도 subview가 타고 있지 않은 상태를 「0층의 view」라고 정의합니다.
view에 (임의의) subview가 타고 있어, 각각이 0층의 view일 때, 그 view를 「1층의 view」라고 부릅니다.

view에 (임의의) subview가 타고 있고, 그 안에 1층의 view가 존재할 때, 그 view를 「2층의 view」라고 부릅니다.

일반적으로
view에 (임의의) subview가 타고 있고, 그 안에 n-1층의 view가 존재할 때, 그 view를 「n층의 view」라고 부릅니다.

··· 아니, 반대로 다소 귀엽다(웃음)
직관적으로는, 그림에서 말하는 왼쪽에서 오른쪽에 걸쳐서 몇중 있는가 하는 것이 됩니다.

패턴 1:1층





먼저 가장 간단한 경우를 생각해 봅시다.

이 예의 그림은 한 뷰에 세 개의 뷰가 타고 있는 상태를 나타냅니다. 더 이상 아래로 계속되지 않으므로이 view는 1 층입니다.

이 경우 조사하면 정상적으로 나옵니다.
view.subviews.forEach { subview in
    subview.removeFromSuperview()
}

라는 식으로 subview 각각에 removeFromSuperview() 를 걸면 할 수 있습니다.

패턴 2: n층



n층의 그림의 적절한 예입니다.


우선, 이 메소드를 생각합니다.

extension UIView {
    func removeAllSubviews() {
        guard !self.subviews.isEmpty else { self.removeFromSuperview() }
        self.subviews.forEach { (subview) in subview.removeAllSubviews() }
    }
}

이 메소드를 실행하면,もしsubviewsが存在すればそのそれぞれに対して同じ操作を繰り返すもしsubviewsが存在しなければ、自分を消す라는 것이 되기 때문에 맨 아래의 계층에서 순차적으로 지워 갈 수가 있습니다.

따라서 모든 subviews를 지울 수는 있지만 자신도 함께 사라집니다.

그렇다면, 1계층하의 subview 각각에게, 이 메소드를 실행시키면 좋지 않을까가 된다( もし自分自身だったら消さない 그렇다면, 우선 제일 먼저 자신을 어딘가에 보존해 남겨야 한다. 인수 로 지정하면 view.removeAllSubviews(view)
그러면 이렇게 됩니다.

extension UIView {
    func removeAllSubviews() {
        self.subviews.forEach { (subview) in subview.removeAllSubviewsForEach() }
    }
    func removeAllSubviewsForEach() {
        guard !self.subviews.isEmpty else { self.removeFromSuperview() }
        self.subviews.forEach { (subview) in subview.removeAllSubviewsForEach()
    }
}


조금 중복입니다.

패턴 3: n층(arrangedSubviews 포함)





일반적으로 패턴 2 메서드로 충분하지만 UIStackView를 사용하면 그렇지 않습니다. 왜냐하면 UIStackView 에는 subviews 는 아니고 arrangedSubviews 도 지정해야 하고 , 그 분의 분기를 할 필요가 있기 때문입니다.

예제 다이어그램에서 두꺼운 점선은 addArrangedSubview 에 의해 추가된 것과 관련이 있습니다.

패턴 2의 경우에 덧붙여 분기하면 좋기 때문에

extension UIView {
    func removeAllSubviews() {
        if type(of: self) == UIStackView.self {
            (self as! UIStackView).arrangedSubviews.forEach { (arrangedSubview) in arrangedSubview.removeAllSubviewsForEach() }
        }
        self.subviews.forEach { (subview) in subview.removeAllSubviewsForEach() }
    }
    func removeAllSubviewsForEach() {
        if type(of: self) == UIStackView.self {
            if (self as! UIStackView).arrangedSubviews.isEmpty {
                self.removeFromSuperview()
            } else {
                (self as! UIStackView).arrangedSubviews.forEach { (arrangedSubview) in arrangedSubview.removeAllSubviewsForEach() }
            }
        }
        if self.subviews.isEmpty {
            self.removeFromSuperview()
        } else {
            self.subviews.forEach { (subview) in subview.removeAllSubviewsForEach()
            }
        }
    }
}

됩니다. guard 의 부분을 if 로 하여 もしUIStackViewだったら、arrangedSubviewsそれぞれに対してremoveAllSubviewsForEachをかける 라는 분기를 추가했습니다. 이것으로 완성

Written by @Zhalen



읽어 주셔서 감사합니다. 배가 너무 줄어 두통.

좋은 웹페이지 즐겨찾기