Jak usunąć wszystkie podglądy widoku w Swift?


176

Szukam prostej metody usuwania naraz wszystkich podglądów podrzędnych z superwizji zamiast usuwania ich jeden po drugim.

//I'm trying something like this, but is not working
let theSubviews : Array = container_view.subviews
for (view : NSView) in theSubviews {
    view.removeFromSuperview(container_view)
}

Czego mi brakuje?

AKTUALIZACJA

Moja aplikacja ma plik main container_view. Muszę dodać różne inne widoki jako podglądy container_view, aby zapewnić rodzaj nawigacji.

Tak więc, kiedy klikam przycisk „otwierania” określonej strony, muszę usunąć wszystkie podglądy i dodać nową.

UPDATE 2 - Działające rozwiązanie (OS X)

Chyba Apple to naprawiło.

Teraz jest to łatwiejsze niż kiedykolwiek, wystarczy zadzwonić:

for view in containerView.subviews{
    view.removeFromSuperview()
}

2
Chciałbym zaznaczyć, że odpowiedź @ sulthan, choć zakopana w szmatach, jest lepszą odpowiedzią: stackoverflow.com/questions/24312760/ ...
Christopher Swasey

@ChristopherSwasey Swift 4 wyświetla błąd: Nie można przypisać do właściwości: „subviews” to właściwość tylko do pobrania. :(
William T. Mallard

2
@ WilliamT.Mallard ile razy trzeba powtarzać, że ta metoda i pytanie dotyczy MacOS, a nie iOS?
Fogmeister

Odpowiedzi:


358

EDYCJA: (dzięki Jeremiah / Rollo)

Zdecydowanie najlepszym sposobem na zrobienie tego w Swift na iOS jest:

view.subviews.forEach({ $0.removeFromSuperview() }) // this gets things done
view.subviews.map({ $0.removeFromSuperview() }) // this returns modified array

^^ Te funkcje są fajne!

let funTimes = ["Awesome","Crazy","WTF"]
extension String { 
    func readIt() {
        print(self)
    }
}

funTimes.forEach({ $0.readIt() })

//// KONIEC EDYCJI

Po prostu zrób to:

for view in self.view.subviews {
    view.removeFromSuperview()
}

Lub jeśli szukasz konkretnej klasy

for view:CustomViewClass! in self.view.subviews {
        if view.isKindOfClass(CustomViewClass) {
            view.doClassThing()
        }
    }

W Xcode 7.0 beta 6 generuje to ostrzeżenie: „wynik wywołania„ mapy ”jest nieużywany”. Mam nadzieję, że zostanie to naprawione w ostatecznej wersji.
Ferschae Naej

Ja też to zauważyłem! Zaktualizuję post, gdy Xcode wyjdzie z wersji beta, a problem będzie nadal występował.
Bseaborn

8
Ostrzeżenie, result of call to 'map' is unused nie jest błędem. Array.mapw większości języków zwróci zmodyfikowaną tablicę. Równoważną metodą, która nie zwraca tablicy, byłaby view.subviews.forEach.
Rollo

for view:CustomViewClass! in self.view.subviews where view.isKindOfClass(CustomViewClass) { view.doClassThing() }
iTSangar

Twierdzę, że jest to „zdecydowanie najlepszy sposób na zrobienie tego w Swift”, zobacz stackoverflow.com/a/24314054/1974224
Cristik

41

W przypadku iOS / Swift, aby pozbyć się wszystkich podglądów podrzędnych, których używam:

for v in view.subviews{
   v.removeFromSuperview()
}

aby pozbyć się wszystkich podglądów podrzędnych danej klasy (np. UILabel), używam:

for v in view.subviews{
   if v is UILabel{
      v.removeFromSuperview()
   }
}

31

Kod można napisać prościej w następujący sposób.

view.subviews.forEach { $0.removeFromSuperview() }

18

To powinno być najprostsze rozwiązanie.

let container_view: NSView = ...
container_view.subviews = []

(zobacz Usunąć wszystkie podglądy? aby zapoznać się z innymi metodami)


Zwróć uwagę, że jest to pytanie dotyczące systemu MacOS, a ta odpowiedź działa tylko w przypadku systemu MacOS . Nie działa na iOS.


Jest to zdecydowanie najprostszy sposób ... removeFromSuperview jest wywoływana automatycznie dla każdego widoku, którego nie ma już w tablicy subviews.
Christopher Swasey

2
@datayeah Nie są, ale jest duża różnica między NSView(OS X) i UIView(iOS).
Sulthan

@Sulthan masz rację. Przyszedłem tutaj po szybką odpowiedź na UIView i nie przeczytałem całego fragmentu kodu;)
datayeah

1
Swift 4 wyświetla błąd: nie można przypisać do usługi: „podglądy” to właściwość tylko do pobrania. :(
William T. Mallard

1
@AmrAngry Ponownie, powtarzam, zawsze było to pytanie dotyczące systemu Mac OS NSView, a nie iOS i UIView. Tylko ludziom nie zależy na czytaniu pytania i tagów, dlatego zostało wypełnione odpowiedziami na iOS.
Sulthan

10

Nie wiem, czy udało ci się to rozwiązać, ale ostatnio miałem podobny problem, w którym pętla For za każdym razem pozostawiała jeden widok. Okazało się, że dzieje się tak, ponieważ self.subviews zostało zmutowane (być może) podczas wywołania removeFromSuperview ().

Aby to naprawić, zrobiłem:

let subViews: Array = self.subviews.copy()
for (var subview: NSView!) in subViews
{
    subview.removeFromSuperview()
}

Wykonując .copy (), mogłem usunąć każdy podwidok, jednocześnie modyfikując tablicę self.subviews. Dzieje się tak, ponieważ skopiowana tablica (subViews) zawiera wszystkie odniesienia do obiektów i nie jest zmieniona.

EDYCJA: W twoim przypadku myślę, że użyłbyś:

let theSubviews: Array = container_view.subviews.copy()
for (var view: NSView!) in theSubviews
{
    view.removeFromSuperview()
}

Działa dobrze! Dzięki
Alberto Bellini

Witam, spróbuj wykonać następujące czynności, chociaż istnieje prawdopodobnie znacznie bardziej elegancki sposób, aby to zrobić: let subViewsArray: Array = (parentView.subviews as NSArray).copy() as Array<NSView>
Adam Richards

9

Spróbuj tego:

for view in container_view.subviews {
    view.removeFromSuperview()
}

9

Rozszerzenie do usuwania wszystkich podglądów podrzędnych, jest szybko usuwane.

import Foundation
import UIKit

extension UIView {
    /// Remove allSubView in view
    func removeAllSubViews() {
        self.subviews.forEach({ $0.removeFromSuperview() })
    }

}

1
dlaczego mapa? może każdy? subviews.forEach {$ 0.removeFromSuperview ()}
Zaporozhchenko Oleksandr

1
Tak, masz rację @Aleksandr, myślę, że kiedy to pisałem, nie
piłem

6

Spróbuj tego:

var subViews = parentView.subviews as Array<UIView>

      for someView in subViews
      {
          someView.removeFromSuperview()
      }

AKTUALIZACJA : Jeśli masz ochotę na przygodę, możesz rozszerzyć UIView, jak pokazano poniżej:

extension UIView
{
    func removeAllSubViews()
    {
       for subView :AnyObject in self.subviews
       {
            subView.removeFromSuperview()
       }
    }

}

I nazwij to tak:

parentView.removeAllSubViews()

2 małe rzeczy: pracuję na osx, więc byłby to <NSView>, prawda? Następnie otrzymuję komunikat „błąd krytyczny: indeks tablicy poza zakresem”: /
Alberto Bellini,

Tak, myślę, że na OSX to NSView. Gdzie otrzymujesz błąd krytyczny?
azamsharp

Czy na pewno Twój widok nadrzędny zawiera elementy podrzędne?
azamsharp

Tak ! Jeśli zrobię println (parentView.subviews), otrzymam 1
Alberto Bellini

To jest dziwne! Zwykle poza zakresem oznacza, że ​​uzyskujesz dostęp do indeksu, który nie istnieje i zwykle uważam, że jest to spowodowane użyciem pętli for z indeksami takimi jak i ++.
azamsharp

5

W xcodebeta6 to się udało.

    var subViews = self.parentView.subviews
    for subview in subViews as [UIView]   {
        subview.removeFromSuperview()
    }

To jest iOS. Potrzebuję rozwiązania dla OS X
Alberto Bellini,

Świetne rozwiązanie dla IOS +1
inVINCEable

3

Napisałem to rozszerzenie:

extension UIView {
    func lf_removeAllSubviews() {
        for view in self.subviews {
            view.removeFromSuperview()
        }
    }
}

Aby można było używać self.view.lf_removeAllSubviews w UIViewController. Umieszczę to w szybkiej wersji mojego https://github.com/superarts/LFramework później, kiedy będę miał większe doświadczenie w swift (jak dotąd 1 dzień expa i tak, dla API zrezygnowałem z podkreślenia).


3

Szybki 3

Jeśli dodasz tag do widoku, możesz usunąć określony widok.

for v in (view?.subviews)!
{
    if v.tag == 321
    {
         v.removeFromSuperview()
    }
 }

dlaczego nie view.subviews.filter({$0.tag != 321}).forEach({$0.removeFromSuperview()})?
AlexanderZ

3

Szybki 5

Tworzę 2 różne metody usuwania widoku podrzędnego. I jest dużo łatwiejszy w użyciu, jeśli je umieścimyextension

extension UIView {
    /// Remove all subview
    func removeAllSubviews() {
        subviews.forEach { $0.removeFromSuperview() }
    }

    /// Remove all subview with specific type
    func removeAllSubviews<T: UIView>(type: T.Type) {
        subviews
            .filter { $0.isMember(of: type) }
            .forEach { $0.removeFromSuperview() }
    }
}

2

Twoja składnia jest nieco nieprawidłowa. Upewnij się, że przesyłasz jawnie.

 let theSubviews : Array<NSView> = container_view.subviews as Array<NSView>
 for view in theSubviews {
     view.removeFromSuperview()
 }

@David Tak, starałem się, aby był jak najbliżej początkowego kodu FoxNos.
Jack

2

musisz tego spróbować

func clearAllScrollSubView ()
{
    let theSubviews = itemsScrollView.subviews

    for (var view) in theSubviews
    {

        if view is UIView
        {
            view.removeFromSuperview()
        }

    }
}

To jest UI, a nie NS. Tutaj mówimy o OS X. Jeśli to działa nawet z nim, zastępując interfejs użytkownika NS, mój błąd, miałeś rację :)
Alberto Bellini

1

Do usuwania tylko podglądów podrzędnych określonej klasy - był to jedyny kod Swift, który działał dla mnie w Xcode6.1.1. Zakładając, że jedyne widoki podrzędne, które chcesz usunąć, są typu UIButton ...

for subView in nameofmysuperview.subviews {
    if subView.isKindOfClass(UIButton) {
        subView.removeFromSuperview()
    }
}

1

Jedna linijka:

while(view.subviews.count > 0) {(view.subviews[0] as NSView).removeFromSuperview()}

Myślę, że to podejście jest bardziej czytelne niż „ jednoliniowe ” przy użyciu map lub forEach . Skrócona ręka foreach i mapa może być trudna do zrozumienia, ponieważ logika jest bardziej abstrakcyjna.


1

Dla Swift 3

Zrobiłem co następuje, ponieważ samo usunięcie z superview nie spowodowało usunięcia przycisków z tablicy.

    for k in 0..<buttons.count {

      buttons[k].removeFromSuperview()

    }


    buttons.removeAll()

1

Wypróbuj to, przetestowałem to:

  let theSubviews = container_view.subviews
  for subview in theSubviews {
      subview.removeFromSuperview()
  }

1

Dla Swift 4.+

extension UIView {
     public func removeAllSubViews() {
          self.subviews.forEach({ $0.removeFromSuperview() })

}

Mam nadzieję, że to jest dla ciebie pełne.


-2

czy próbowałeś czegoś takiego

for o : AnyObject in self.subviews {
     if let v = o as? NSView {
         v.removeFromSuperview()
     }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.