Comment supprimer toutes les sous-vues d'une vue dans Swift?

176

Je recherche une méthode simple pour supprimer à la fois toutes les sous-vues d'un superview au lieu de les supprimer une par une.

//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)
}

Qu'est-ce que je manque?

METTRE À JOUR

Mon application a un fichier principal container_view. Je dois ajouter différentes autres vues en tant que sous-vues container_viewafin de fournir une sorte de navigation.

Ainsi, lorsque je clique sur le bouton pour «ouvrir» une page particulière, je dois supprimer toutes les sous-vues et ajouter la nouvelle.

UPDATE 2 - Une solution de travail (OS X)

Je suppose qu'Apple l'a corrigé.

Maintenant, c'est plus facile que jamais, il suffit d'appeler:

for view in containerView.subviews{
    view.removeFromSuperview()
}
Alberto Bellini
la source
2
Je tiens à souligner que la réponse de @ sulthan, bien qu'enterrée avec les chiffons, est la réponse supérieure: stackoverflow.com/questions/24312760/...
Christopher Swasey
@ChristopherSwasey Swift 4 donne une erreur: Impossible d'affecter à la propriété: 'subviews' est une propriété en lecture seule. :(
William T.Mallard
2
@ WilliamT.Mallard combien de fois faut-il répéter que cette méthode et cette question concernent MacOS et non iOS?
Fogmeister

Réponses:

358

EDIT: (merci Jeremiah / Rollo)

La meilleure façon de le faire dans Swift pour iOS est de loin:

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

^^ Ces fonctionnalités sont amusantes!

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

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

//// FIN EDIT

Faites juste ceci:

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

Ou si vous recherchez une classe spécifique

for view:CustomViewClass! in self.view.subviews {
        if view.isKindOfClass(CustomViewClass) {
            view.doClassThing()
        }
    }
Bseaborn
la source
Dans Xcode 7.0 beta 6, cela génère un avertissement: "le résultat de l'appel à 'map' n'est pas utilisé". J'espère que cela sera corrigé dans la version finale.
Ferschae Naej
Je l'ai remarqué aussi! Je mettrai à jour le message une fois que Xcode sortira de la version bêta et que le problème persiste.
Bseaborn le
8
L'avertissement, result of call to 'map' is unused n'est pas une erreur. Array.mapdans la plupart des langues retournera le tableau modifié. La méthode équivalente qui ne renvoie pas de tableau serait view.subviews.forEach.
Rollo le
for view:CustomViewClass! in self.view.subviews where view.isKindOfClass(CustomViewClass) { view.doClassThing() }
iTSangar
Je dirais que c'est "de loin le meilleur moyen de le faire dans Swift", voir stackoverflow.com/a/24314054/1974224
Cristik
41

Pour iOS / Swift, pour me débarrasser de toutes les sous-vues que j'utilise:

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

pour me débarrasser de toutes les sous-vues d'une classe particulière (comme UILabel), j'utilise:

for v in view.subviews{
   if v is UILabel{
      v.removeFromSuperview()
   }
}
tonéthar
la source
31

Le code peut être écrit plus simplement comme suit.

view.subviews.forEach { $0.removeFromSuperview() }
mishimay
la source
19

Cela devrait être la solution la plus simple.

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

(voir Supprimer toutes les sous-vues? pour d'autres méthodes)


Notez qu'il s'agit d'une question MacOS et que cette réponse ne fonctionne que pour MacOS . Cela ne fonctionne pas sur iOS.

Sulthan
la source
C'est certainement le moyen le plus simple ... removeFromSuperview est automatiquement appelé pour chaque vue qui n'est plus dans le tableau des sous-vues.
Christopher Swasey
2
@datayeah Ils ne le sont pas, mais il y a une grande différence entre NSView(OS X) et UIView(iOS).
Sulthan
@Sulthan vous avez raison. Je suis venu ici pour la réponse Swift pour UIView et je n'ai pas lu l'intégralité de votre extrait de code;)
datayeah
1
Swift 4 donne une erreur: Impossible d'affecter à la propriété: 'subviews' est une propriété en lecture seule. :(
William T.Mallard
1
@AmrAngry Encore une fois, je le répète, c'était toujours une question Mac OS, pour NSView, pas pour iOS et UIView. Seules les personnes ne se soucient pas de lire la question et les balises, elles sont donc remplies de réponses iOS.
Sulthan
10

Je ne sais pas si vous avez réussi à résoudre cela, mais j'ai récemment rencontré un problème similaire où la boucle For laissait une vue à chaque fois. J'ai trouvé que c'était parce que self.subviews était muté (peut-être) lorsque le removeFromSuperview () était appelé.

Pour résoudre ce problème, j'ai fait:

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

En faisant .copy (), je pourrais effectuer la suppression de chaque sous-vue tout en faisant muter le tableau self.subviews. Cela est dû au fait que le tableau copié (sous-vues) contient toutes les références aux objets et n'est pas muté.

EDIT: Dans votre cas, je pense que vous utiliseriez:

let theSubviews: Array = container_view.subviews.copy()
for (var view: NSView!) in theSubviews
{
    view.removeFromSuperview()
}
Adam Richards
la source
Fonctionne très bien! Merci
Alberto Bellini
Bonjour, essayez ce qui suit bien qu'il y ait probablement une façon beaucoup plus élégante de le faire: let subViewsArray: Array = (parentView.subviews as NSArray).copy() as Array<NSView>
Adam Richards
9

Essaye ça:

for view in container_view.subviews {
    view.removeFromSuperview()
}
MattL
la source
9

Extension pour supprimer toutes les sous-vues, elle est rapidement supprimée.

import Foundation
import UIKit

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

}
YannSteph
la source
1
pourquoi la carte? foreach peut-être? subviews.forEach {$ 0.removeFromSuperview ()}
Zaporozhchenko Oleksandr
1
Oui tu as raison @Aleksandr je pense que quand j'écrivais ceci, je n'avais pas pris mon café
YannSteph
6

Essaye ça:

var subViews = parentView.subviews as Array<UIView>

      for someView in subViews
      {
          someView.removeFromSuperview()
      }

MISE À JOUR : Si vous vous sentez aventureux, vous pouvez créer une extension sur l'UIView comme indiqué ci-dessous:

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

}

Et appelez-le comme ceci:

parentView.removeAllSubViews()
azamsharp
la source
2 petites choses: je travaille sur osx, donc ce serait <NSView> non? Ensuite, je reçois une "erreur fatale: index de tableau hors de portée": /
Alberto Bellini
Oui, je pense que sur OSX c'est NSView. D'où vient l'erreur fatale?
azamsharp
Êtes-vous sûr que votre vue parent contient des éléments enfants?
azamsharp
Ouais! Si je fais un println (parentView.subviews) j'obtiens 1
Alberto Bellini
C'est étrange! Habituellement, hors de portée signifie que vous accédez à un index qui n'existe pas et je pense généralement que cela est dû à l'utilisation d'une boucle for avec des index comme i ++.
azamsharp
5

Dans xcodebeta6, cela a fonctionné.

    var subViews = self.parentView.subviews
    for subview in subViews as [UIView]   {
        subview.removeFromSuperview()
    }
haineux
la source
C'est iOS. J'ai besoin d'une solution pour OS X
Alberto Bellini
Excellente solution pour IOS +1
disponible
3

J'ai écrit cette extension:

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

Pour que vous puissiez utiliser self.view.lf_removeAllSubviews dans un UIViewController. Je mettrai cela dans la version swift de mon https://github.com/superarts/LFramework plus tard, quand j'aurai plus d'expérience dans swift (1 jour d'exp jusqu'à présent, et oui, pour l'API, j'ai abandonné le soulignement).

superarts.org
la source
3

Swift 3

Si vous ajoutez une balise à votre vue, vous pouvez supprimer une vue spécifique.

for v in (view?.subviews)!
{
    if v.tag == 321
    {
         v.removeFromSuperview()
    }
 }
uplearnedu.com
la source
pourquoi pas view.subviews.filter({$0.tag != 321}).forEach({$0.removeFromSuperview()})?
AlexanderZ
3

Swift 5

Je crée 2 méthodes différentes pour supprimer la sous-vue. Et c'est beaucoup plus facile à utiliser si nous les mettonsextension

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() }
    }
}
nahung89
la source
2

Votre syntaxe est légèrement décalée. Assurez-vous de lancer explicitement.

 let theSubviews : Array<NSView> = container_view.subviews as Array<NSView>
 for view in theSubviews {
     view.removeFromSuperview()
 }
Jack
la source
@David Oui, j'ai essayé de le garder aussi proche que possible du code initial de FoxNos.
Jack
2

Tu dois essayer ça

func clearAllScrollSubView ()
{
    let theSubviews = itemsScrollView.subviews

    for (var view) in theSubviews
    {

        if view is UIView
        {
            view.removeFromSuperview()
        }

    }
}
Ahmed Zaytoun
la source
C'est UI pas NS. Ici, nous parlons d'OS X. Si cela fonctionne même avec lui en remplaçant UI par NS, mon mauvais, vous aviez raison :)
Alberto Bellini
1

Pour supprimer uniquement les sous-vues d'une classe spécifique - c'était le seul code Swift qui fonctionnait pour moi dans Xcode6.1.1. En supposant que les seules sous-vues que vous souhaitez supprimer sont de type UIButton ...

for subView in nameofmysuperview.subviews {
    if subView.isKindOfClass(UIButton) {
        subView.removeFromSuperview()
    }
}
gammachill
la source
1

Bon mot:

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

Je pense que cette approche est plus lisible que les "one-liners" utilisant map ou forEach . Les raccourcis pourchaque et carte peuvent être difficiles à comprendre, car la logique est plus abstraite.

éoniste
la source
1

Pour Swift 3

J'ai fait comme suit car le simple fait de supprimer de superview n'effaçait pas les boutons du tableau.

    for k in 0..<buttons.count {

      buttons[k].removeFromSuperview()

    }


    buttons.removeAll()
Espérer
la source
1

Essayez ceci, j'ai testé ceci:

  let theSubviews = container_view.subviews
  for subview in theSubviews {
      subview.removeFromSuperview()
  }
Ezimet
la source
1

Pour Swift 4.+

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

}

j'espère que c'est une utilisation complète pour vous.

Masoud Heydari
la source
-2

as-tu essayé quelque chose comme

for o : AnyObject in self.subviews {
     if let v = o as? NSView {
         v.removeFromSuperview()
     }
}
Christian Dietrich
la source