Como remover todas as subvisões de uma visualização no Swift?

176

Estou procurando um método simples para remover de uma vez todas as subvisões de uma superview em vez de removê-las uma a uma.

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

O que estou perdendo?

ATUALIZAR

Meu aplicativo tem um principal container_view. Tenho que adicionar outras visualizações diferentes como subvisões container_viewpara fornecer uma espécie de navegação.

Portanto, ao clicar no botão para "abrir" uma página específica, preciso remover todas as sub-visualizações e adicionar a nova.

ATUALIZAÇÃO 2 - Uma solução funcional (OS X)

Eu acho que a Apple consertou.

Agora é mais fácil do que nunca, basta ligar para:

for view in containerView.subviews{
    view.removeFromSuperview()
}
Alberto Bellini
fonte
2
Eu gostaria de ressaltar resposta que @ de Sulthan, enquanto enterrado com os trapos, é a resposta superiores: stackoverflow.com/questions/24312760/...
Christopher Swasey
@ChristopherSwasey Swift 4 apresenta um erro: Não é possível atribuir à propriedade: 'subviews' é uma propriedade get-only. :(
William T. Mallard
2
@ WilliamT.Mallard quantas vezes é necessário repetir que esse método e pergunta são sobre o MacOS e não o iOS?
Fogmeister

Respostas:

358

EDIT: (obrigado Jeremiah / Rollo)

De longe, a melhor maneira de fazer isso no Swift for iOS é:

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

^^ Esses recursos são divertidos!

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

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

//// END EDIT

Apenas faça o seguinte:

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

Ou se você estiver procurando por uma classe específica

for view:CustomViewClass! in self.view.subviews {
        if view.isKindOfClass(CustomViewClass) {
            view.doClassThing()
        }
    }
Bseaborn
fonte
No Xcode 7.0 beta 6, isso gera um aviso: "o resultado da chamada para 'map' não é utilizado". Espero que isso seja corrigido na versão final.
Ferschae Naej
Eu percebi isto também! Atualizarei a postagem assim que o Xcode sair da versão beta e o problema ainda persistir.
Bseaborn
8
O aviso,, result of call to 'map' is unused não é um erro. Array.mapna maioria dos idiomas retornará a matriz modificada. O método equivalente que não retorna uma matriz seria view.subviews.forEach.
Rollo
for view:CustomViewClass! in self.view.subviews where view.isKindOfClass(CustomViewClass) { view.doClassThing() }
ITSangar
Eu diria que esta é "De longe a melhor maneira de fazer isso no Swift", consulte stackoverflow.com/a/24314054/1974224
Cristik
41

Para iOS / Swift, para me livrar de todas as subvisões que eu uso:

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

para me livrar de todas as subvisões de uma classe específica (como UILabel), eu uso:

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

O código pode ser escrito mais simples da seguinte maneira.

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

Essa deve ser a solução mais simples.

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

(consulte Remover todas as subvisões? para outros métodos)


Observe que esta é uma pergunta do MacOS e esta resposta funciona apenas para o MacOS . Não funciona no iOS.

Sulthan
fonte
Esta é definitivamente a maneira mais simples ... removeFromSuperview é chamado automaticamente para cada visualização que não está mais na matriz de subviews.
Christopher Swasey
2
@datayeah Eles não existem, mas há uma grande diferença entre NSView(OS X) e UIView(iOS).
precisa saber é o seguinte
@Sulthan, você está certo. Eu vim aqui para a resposta Swift para o UIView e não lemos todo o seu trecho de código;)
datayeah
1
O Swift 4 apresenta um erro: Não é possível atribuir à propriedade: 'subviews' é uma propriedade get-only. :(
William T. Mallard
1
@AmrAngry Mais uma vez, repito, essa sempre foi uma pergunta do Mac OS, pois NSViewnão iOS e UIView. Somente as pessoas não se importam de ler a pergunta e as tags, portanto, ela foi preenchida com respostas para iOS.
Sulthan
10

Não sei se você conseguiu resolver isso, mas recentemente tive um problema semelhante em que o loop For deixava uma visualização a cada vez. Eu descobri que isso acontecia porque as self.subviews foram alteradas (talvez) quando o removeFromSuperview () foi chamado.

Para consertar isso eu fiz:

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

Ao fazer .copy (), eu poderia executar a remoção de cada subvisão enquanto modificava a matriz self.subviews. Isso ocorre porque a matriz copiada (subViews) contém todas as referências aos objetos e não é alterada.

EDIT: No seu caso, acho que você usaria:

let theSubviews: Array = container_view.subviews.copy()
for (var view: NSView!) in theSubviews
{
    view.removeFromSuperview()
}
Adam Richards
fonte
Funciona muito bem! Obrigado
Alberto Bellini
Olá, tente o seguinte, embora provavelmente há uma maneira muito mais elegante de fazer isso: let subViewsArray: Array = (parentView.subviews as NSArray).copy() as Array<NSView>
Adam Richards
9

Tente o seguinte:

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

Extensão para remover todas as subvisões, é removida rapidamente.

import Foundation
import UIKit

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

}
YannSteph
fonte
1
porque mapear? foreach talvez? subviews.forEach {$ 0.removeFromSuperview ()}
Zaporozhchenko Oleksandr
1
Sim, você direita @Aleksandr eu acho que quando eu estava escrevendo isso, eu não tinha tomar o meu café
YannSteph
6

Tente o seguinte:

var subViews = parentView.subviews as Array<UIView>

      for someView in subViews
      {
          someView.removeFromSuperview()
      }

ATUALIZAÇÃO : Se você estiver se sentindo aventureiro, poderá fazer uma extensão no UIView, como mostrado abaixo:

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

}

E chame assim:

parentView.removeAllSubViews()
azamsharp
fonte
2 pequenas coisas: estou trabalhando no osx, portanto, seria <NSView> certo? Então, estou recebendo "erro fatal: índice de matrizes fora do intervalo": /
Alberto Bellini
Sim, acho que no OSX é o NSView. Onde você obtém o erro fatal?
azamsharp
Tem certeza de que sua visualização pai possui elementos filhos?
azamsharp
Sim ! Se eu fizer uma println (parentView.subviews) i get 1
Alberto Bellini
Isso é estranho! Geralmente fora do intervalo significa que você está acessando um índice que não existe e geralmente acredito que seja causado pelo uso de um loop for com índices como o i ++.
azamsharp
5

No xcodebeta6, isso funcionou.

    var subViews = self.parentView.subviews
    for subview in subViews as [UIView]   {
        subview.removeFromSuperview()
    }
hatebyte
fonte
Isso é iOS. Eu preciso de uma solução para OS X
Alberto Bellini
Ótima solução para IOS +1
inVINCEable
3

Eu escrevi esta extensão:

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

Para que você possa usar self.view.lf_removeAllSubviews em um UIViewController. Vou colocar isso na versão rápida do meu https://github.com/superarts/LFramework mais tarde, quando tiver mais experiência no swift (1 dia de exp até agora e, sim, para a API, perdi o sublinhado).

superarts.org
fonte
3

Swift 3

Se você adicionar uma tag à sua visualização, poderá remover uma visualização específica.

for v in (view?.subviews)!
{
    if v.tag == 321
    {
         v.removeFromSuperview()
    }
 }
uplearnedu.com
fonte
por que não view.subviews.filter({$0.tag != 321}).forEach({$0.removeFromSuperview()})?
AlexanderZ
3

Swift 5

Eu crio 2 métodos diferentes para remover a subview. E é muito mais fácil usar se os colocarmosextension

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

Sua sintaxe está um pouco desativada. Certifique-se de transmitir explicitamente.

 let theSubviews : Array<NSView> = container_view.subviews as Array<NSView>
 for view in theSubviews {
     view.removeFromSuperview()
 }
Jack
fonte
@ David Sim, eu tentei mantê-lo o mais próximo possível do código inicial do FoxNos.
19414 Jack
2

você tem que tentar isso

func clearAllScrollSubView ()
{
    let theSubviews = itemsScrollView.subviews

    for (var view) in theSubviews
    {

        if view is UIView
        {
            view.removeFromSuperview()
        }

    }
}
Ahmed Zaytoun
fonte
Essa é a interface do usuário, não o NS. Aqui estamos falando de OS X. Se isso funciona mesmo com ele, substituindo UI com NS, meu mau, você estava certo :)
Alberto Bellini
1

Para remover apenas as subvisões de uma classe específica - esse foi o único código Swift que funcionou para mim no Xcode6.1.1. Supondo que as únicas subvisões que você deseja remover sejam do tipo UIButton ...

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

Uma linha:

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

Eu acho que essa abordagem é mais legível do que os "one-liners" usando map ou forEach . Mão curta foreach e mapa pode ser difícil de compreender, como a lógica é mais abstrato.

eonista
fonte
1

Para Swift 3

Fiz o seguinte, porque apenas remover da superview não apagou os botões da matriz.

    for k in 0..<buttons.count {

      buttons[k].removeFromSuperview()

    }


    buttons.removeAll()
Esperança
fonte
1

Experimente isso, eu testei isso:

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

Para Swift 4.+

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

}

Espero que este seja completo para você.

Masoud Heydari
fonte
-2

você tentou algo como

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