¿Cómo eliminar todas las subvistas de una vista en Swift?

176

Estoy buscando un método simple para eliminar a la vez todas las subvistas de una supervista en lugar de eliminarlas una por 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)
}

¿Qué me estoy perdiendo?

ACTUALIZAR

Mi aplicación tiene una principal container_view. Tengo que agregar otras vistas diferentes como subvistas container_viewpara proporcionar una especie de navegación.

Entonces, cuando hago clic en el botón para "abrir" una página en particular, necesito eliminar todas las subvistas y agregar una nueva.

ACTUALIZACIÓN 2: una solución de trabajo (OS X)

Supongo que Apple lo arregló.

Ahora es más fácil que nunca, solo llame:

for view in containerView.subviews{
    view.removeFromSuperview()
}
Alberto Bellini
fuente
2
Me gustaría señalar que la respuesta de @ sulthan, aunque está enterrada con los trapos, es la respuesta superior: stackoverflow.com/questions/24312760/…
Christopher Swasey
@ChristopherSwasey Swift 4 da un error: No se puede asignar a la propiedad: 'subviews' es una propiedad de solo obtención. :(
William T. Mallard
2
@ WilliamT.Mallard ¿cuántas veces tiene que repetirse que este método y esta pregunta son sobre MacOS y no sobre iOS?
Fogmeister

Respuestas:

358

EDITAR: (gracias Jeremiah / Rollo)

Con mucho, la mejor manera de hacer esto en Swift para iOS es:

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

^^ ¡Estas características son divertidas!

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

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

//// FIN EDITAR

Solo haz esto:

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

O si estás buscando una clase específica

for view:CustomViewClass! in self.view.subviews {
        if view.isKindOfClass(CustomViewClass) {
            view.doClassThing()
        }
    }
Bseaborn
fuente
En Xcode 7.0 beta 6 esto genera una advertencia: "el resultado de la llamada al 'mapa' no está en uso". Espero que esto se solucione en la versión final.
Ferschae Naej
¡También me di cuenta de eso! Actualizaré la publicación una vez que Xcode salga de la versión beta y el problema aún persista.
Bseaborn
8
La advertencia, result of call to 'map' is unused no es un error. Array.mapen la mayoría de los idiomas devolverá la matriz modificada. Sería el método equivalente que no devuelve una matriz view.subviews.forEach.
Rollo
for view:CustomViewClass! in self.view.subviews where view.isKindOfClass(CustomViewClass) { view.doClassThing() }
iTSangar
Yo diría que esta es "De lejos la mejor manera de hacer esto en Swift", vea stackoverflow.com/a/24314054/1974224
Cristik
41

Para iOS / Swift, para deshacerme de todas las subvistas que uso:

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

para deshacerme de todas las subvistas de una clase particular (como UILabel) utilizo:

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

El código se puede escribir más simple de la siguiente manera.

view.subviews.forEach { $0.removeFromSuperview() }
mishimay
fuente
18

Esta debería ser la solución más simple.

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

(ver ¿ Eliminar todas las subvistas? para otros métodos)


Tenga en cuenta que esta es una pregunta de MacOS y esta respuesta solo funciona para MacOS . No funciona en iOS.

Sulthan
fuente
Definitivamente esta es la forma más simple ... removeFromSuperview se llama automáticamente para cada vista que ya no está en la matriz de subvistas.
Christopher Swasey
2
@datayeah No lo son, pero hay una gran diferencia entre NSView(OS X) y UIView(iOS).
Sulthan
@Sulthan tienes razón. Vine aquí para obtener la respuesta rápida de UIView y no leí todo el fragmento de código;)
datayeah
1
Swift 4 da un error: No se puede asignar a la propiedad: 'subviews' es una propiedad de solo obtención. :(
William T. Mallard
1
@AmrAngry Nuevamente, repito, esta siempre fue una pregunta de Mac OS NSView, no para iOS y UIView. Solo a las personas no les importa leer la pregunta y las etiquetas, por lo tanto, se llenó de respuestas iOS.
Sulthan
10

No sé si logró resolver esto, pero recientemente he tenido un problema similar en el que el bucle For dejó una vista cada vez. Descubrí que esto se debía a que self.subviews estaba mutado (tal vez) cuando se llamó a removeFromSuperview ().

Para arreglar esto hice:

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

Al hacer .copy (), podría realizar la eliminación de cada subvista mientras mutaba la matriz self.subviews. Esto se debe a que la matriz copiada (subViews) contiene todas las referencias a los objetos y no está mutada.

EDITAR: en su caso, creo que usaría:

let theSubviews: Array = container_view.subviews.copy()
for (var view: NSView!) in theSubviews
{
    view.removeFromSuperview()
}
Adam Richards
fuente
Funciona bien! Gracias
Alberto Bellini
Hola, intente lo siguiente, aunque probablemente haya una forma mucho más elegante de hacer esto: let subViewsArray: Array = (parentView.subviews as NSArray).copy() as Array<NSView>
Adam Richards
9

Prueba esto:

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

Extensión para eliminar todas las subvistas, se elimina rápidamente.

import Foundation
import UIKit

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

}
YannSteph
fuente
1
¿Por qué mapa? foreach tal vez? subviews.forEach {$ 0.removeFromSuperview ()}
Zaporozhchenko Oleksandr el
1
Sí, tienes razón @Aleksandr, creo que cuando estaba escribiendo esto, no había tomado mi café
YannSteph
6

Prueba esto:

var subViews = parentView.subviews as Array<UIView>

      for someView in subViews
      {
          someView.removeFromSuperview()
      }

ACTUALIZACIÓN : Si te sientes aventurero, puedes hacer una extensión en la UIView como se muestra a continuación:

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

}

Y llámalo así:

parentView.removeAllSubViews()
azamsharp
fuente
2 pequeñas cosas: estoy trabajando en osx, por lo tanto, sería <NSView> ¿verdad? Entonces, obtengo un "error fatal: índice de matriz fuera de rango": /
Alberto Bellini
Sí, creo que en OSX es NSView. ¿De dónde sacas el error fatal?
azamsharp
¿Estás seguro de que tu vista principal tiene elementos secundarios?
azamsharp
Si! Si hago una impresión (parentView.subviews) obtengo 1
Alberto Bellini
¡Eso es extraño! Por lo general, fuera de rango significa que está accediendo a un índice que no existe y, por lo general, creo que se debe al uso de un bucle for con índices como i ++.
azamsharp
5

En xcodebeta6 esto funcionó.

    var subViews = self.parentView.subviews
    for subview in subViews as [UIView]   {
        subview.removeFromSuperview()
    }
hatebyte
fuente
Eso es iOS. Necesito una solución para OS X
Alberto Bellini
Gran solución para IOS +1
inVINCEable el
3

Escribí esta extensión:

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

Para que pueda usar self.view.lf_removeAllSubviews en un UIViewController. Pondré esto en la versión rápida de mi https://github.com/superarts/LFramework más tarde, cuando tenga más experiencia en swift (1 día de experiencia hasta ahora, y sí, para la API, dejé el guión bajo).

superarts.org
fuente
3

Swift 3

Si agrega una etiqueta a su vista, puede eliminar una vista específica.

for v in (view?.subviews)!
{
    if v.tag == 321
    {
         v.removeFromSuperview()
    }
 }
uplearnedu.com
fuente
¿por qué no view.subviews.filter({$0.tag != 321}).forEach({$0.removeFromSuperview()})?
AlexanderZ
3

Swift 5

Creo 2 métodos diferentes para eliminar la subvista. Y es mucho más fácil de usar si los ponemos enextension

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
fuente
2

Su sintaxis está ligeramente apagada. Asegúrate de emitir explícitamente.

 let theSubviews : Array<NSView> = container_view.subviews as Array<NSView>
 for view in theSubviews {
     view.removeFromSuperview()
 }
Jack
fuente
@David Sí, traté de mantenerlo lo más cerca posible del código inicial de FoxNos.
Jack
2

Tienes que intentarlo

func clearAllScrollSubView ()
{
    let theSubviews = itemsScrollView.subviews

    for (var view) in theSubviews
    {

        if view is UIView
        {
            view.removeFromSuperview()
        }

    }
}
Ahmed Zaytoun
fuente
Eso es UI no NS. Aquí estamos hablando de OS X. Si eso funciona incluso reemplazando la interfaz de usuario con NS, es malo, tenías razón :)
Alberto Bellini
1

Para eliminar solo subvistas de una clase específica, este fue el único código Swift que funcionó para mí en Xcode6.1.1. Suponiendo que las únicas subvistas que desea eliminar son de tipo UIButton ...

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

Un trazador de líneas:

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

Creo que este enfoque es más legible que los "one-liners" usando map o forEach . El foreach y el mapa cortos pueden ser difíciles de entender, ya que la lógica es más abstracta.

eonista
fuente
1

Para Swift 3

Hice lo siguiente porque solo eliminar de la supervista no borró los botones de la matriz.

    for k in 0..<buttons.count {

      buttons[k].removeFromSuperview()

    }


    buttons.removeAll()
Esperanza
fuente
1

Prueba esto, probé esto:

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

por Swift 4.+

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

}

Espero que este sea el uso completo para ti.

Masoud Heydari
fuente
-2

intentaste algo como

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