Come rimuovere tutte le visualizzazioni secondarie di una vista in Swift?


176

Sto cercando un metodo semplice per rimuovere immediatamente tutte le sottoview da una superview invece di rimuoverle una per una.

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

Cosa mi manca

AGGIORNARE

La mia app ha un main container_view. Devo aggiungere diverse altre visualizzazioni come sottoview container_viewper fornire una sorta di navigazione.

Pertanto, quando faccio clic sul pulsante per "aprire" una determinata pagina, devo rimuovere tutte le visualizzazioni e aggiungere quella nuova.

AGGIORNAMENTO 2 - Una soluzione funzionante (OS X)

Immagino che Apple l'abbia risolto.

Ora è più facile che mai, basta chiamare:

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

2
Vorrei sottolineare che la risposta di @ sulthan, seppellita con gli stracci, è la risposta superiore: stackoverflow.com/questions/24312760/…
Christopher Swasey,

@ChristopherSwasey Swift 4 restituisce un errore: Impossibile assegnare alla proprietà: "sottopagine" è una proprietà di sola acquisizione. :(
William T. Mallard,

2
@ WilliamT.Mallard quante volte è necessario ripetere che questo metodo e questa domanda riguardano MacOS e non iOS?
Fogmeister,

Risposte:


358

EDIT: (grazie Jeremiah / Rollo)

Di gran lunga il modo migliore per farlo in Swift per iOS è:

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

^^ Queste funzionalità sono divertenti!

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

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

//// END EDIT

Basta fare questo:

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

O se stai cercando una classe specifica

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

In Xcode 7.0 beta 6 questo genera un avviso: "il risultato della chiamata a 'map' non è utilizzato". Spero che questo venga risolto nella versione finale.
Ferschae Naej,

L'ho notato anch'io! Aggiornerò il post quando Xcode uscirà dalla beta e il problema persiste ancora.
Bseaborn,

8
L'avvertimento, result of call to 'map' is unused non è un errore. Array.mapnella maggior parte delle lingue restituirà l'array modificato. Il metodo equivalente che non restituisce un array sarebbe view.subviews.forEach.
Rollo,

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

Direi che questo è "di gran lunga il modo migliore per farlo a Swift", vedi stackoverflow.com/a/24314054/1974224
Cristik

41

Per iOS / Swift, per sbarazzarsi di tutte le visualizzazioni secondarie che utilizzo:

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

per sbarazzarsi di tutte le sottoview di una particolare classe (come UILabel) che uso:

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

31

Il codice può essere scritto più semplice come segue.

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

19

Questa dovrebbe essere la soluzione più semplice.

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

(vedi Rimuovere tutte le visualizzazioni secondarie? per altri metodi)


Nota che questa è una domanda MacOS e questa risposta funziona solo per MacOS . Non funziona su iOS.


Questo è sicuramente il modo più semplice ... removeFromSuperview viene chiamato automaticamente per ogni vista che non è più nell'array delle viste secondarie.
Christopher Swasey,

2
@datayeah Non lo sono, ma c'è una grande differenza tra NSView(OS X) e UIView(iOS).
Sulthan,

@Sulthan hai ragione. Sono venuto qui per la risposta rapida per UIView e non ho letto l'intero frammento di codice;)
datayeah

1
Swift 4 genera un errore: Impossibile assegnare alla proprietà: "sottopagine" è una proprietà di sola acquisizione. :(
William T. Mallard,

1
@AmrAngry Ancora una volta, ripeto, questa è sempre stata una domanda su Mac OS NSView, non per iOS e UIView. Solo le persone non si preoccupano di leggere la domanda e i tag, quindi è stata riempita con le risposte iOS.
Sulthan,

10

Non so se sei riuscito a risolverlo, ma di recente ho riscontrato un problema simile in cui il ciclo For ha lasciato una vista ogni volta. Ho scoperto che ciò era dovuto al fatto che il self.subviews era mutato (forse) quando veniva chiamato removeFromSuperview ().

Per risolvere questo ho fatto:

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

Facendo .copy (), potrei eseguire la rimozione di ogni sottoview mutando l'array self.subviews. Questo perché l'array copiato (sottoview) contiene tutti i riferimenti agli oggetti e non è mutato.

EDIT: Nel tuo caso penso che useresti:

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

Funziona bene! Grazie
Alberto Bellini,

Ciao, prova quanto segue, anche se probabilmente c'è un modo molto più elegante per farlo: let subViewsArray: Array = (parentView.subviews as NSArray).copy() as Array<NSView>
Adam Richards,

9

Prova questo:

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

9

Estensione per rimuovere tutte le visualizzazioni secondarie, viene rapidamente rimossa.

import Foundation
import UIKit

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

}

1
perché mappa? foreach forse? subviews.forOach {$ 0.removeFromSuperview ()}
Zaporozhchenko Oleksandr

1
Sì hai ragione @Aleksandr penso che quando stavo scrivendo questo, non avevo preso il mio caffè
YannSteph

6

Prova questo:

var subViews = parentView.subviews as Array<UIView>

      for someView in subViews
      {
          someView.removeFromSuperview()
      }

AGGIORNAMENTO : se ti senti avventuroso, puoi estendere l'UIView come mostrato di seguito:

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

}

E chiamalo così:

parentView.removeAllSubViews()

2 piccole cose: sto lavorando su OSX, quindi sarebbe <NSView> giusto? Quindi, visualizzo "errore irreversibile: indice array fuori intervallo": /
Alberto Bellini,

Sì, penso su OSX è NSView. Dove viene visualizzato l'errore fatale?
Azamsharp,

Sei sicuro che la vista padre abbia elementi figlio?
Azamsharp,

Si! Se realizzo una stampa (parentView.subviews) ottengo 1
Alberto Bellini,

Questo è strano! Di solito fuori portata significa che stai accedendo a un indice che non esiste e di solito credo che sia causato dall'uso di un ciclo for con indici come i ++.
Azamsharp,

5

In xcodebeta6 questo ha funzionato.

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

Questo è iOS. Ho bisogno di una soluzione per OS X
Alberto Bellini,

Ottima soluzione per IOS +1
INVINCE

3

Ho scritto questa estensione:

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

In modo che tu possa usare self.view.lf_removeAllSubviews in un UIViewController. Lo inserirò nella versione rapida del mio https://github.com/superarts/LFramework più tardi, quando avrò più esperienza in swift (1 day exp finora, e sì, per API ho rinunciato alla sottolineatura).


3

Swift 3

Se aggiungi un tag alla tua vista, puoi rimuovere una vista specifica.

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

perchè no view.subviews.filter({$0.tag != 321}).forEach({$0.removeFromSuperview()})?
AlexanderZ,

3

Swift 5

Creo 2 metodi diversi per rimuovere la subview. Ed è molto più facile da usare se li inseriamoextension

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

La sintassi è leggermente disattivata. Assicurati di lanciare esplicitamente.

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

@David Sì, ho provato a tenerlo il più vicino possibile al codice iniziale di FoxNos.
Jack,

2

devi provare questo

func clearAllScrollSubView ()
{
    let theSubviews = itemsScrollView.subviews

    for (var view) in theSubviews
    {

        if view is UIView
        {
            view.removeFromSuperview()
        }

    }
}

Questa è UI non NS. Qui stiamo parlando di OS X. Se funziona anche con esso sostituendo l'interfaccia utente con NS, mio ​​male, avevi ragione :)
Alberto Bellini,

1

Per aver rimosso solo le subview di una classe specifica - questo è stato l'unico codice Swift che ha funzionato per me in Xcode6.1.1. Supponendo che le uniche visualizzazioni secondarie che si desidera rimuovere siano di tipo UIButton ...

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

1

One-liner:

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

Penso che questo approccio sia più leggibile dei "one-liner" usando map o forEach . Foreach e map hand short possono essere difficili da capire, poiché la logica è più astratta.


1

Per Swift 3

Ho fatto come segue perché la semplice rimozione dalla superview non ha cancellato i pulsanti dall'array.

    for k in 0..<buttons.count {

      buttons[k].removeFromSuperview()

    }


    buttons.removeAll()

1

Prova questo, ho provato questo:

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

1

Per Swift 4.+

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

}

spero che questo sia pieno per te.


-2

hai provato qualcosa del genere

for o : AnyObject in self.subviews {
     if let v = o as? NSView {
         v.removeFromSuperview()
     }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.