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

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

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

31

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

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

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.


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

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

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

}

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()

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

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).


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

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

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

@ 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()
        }

    }
}

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

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.


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()

1

Experimente isso, eu testei isso:

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

1

Para Swift 4.+

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

}

Espero que este seja completo para você.


-2

você tentou algo como

for o : AnyObject in self.subviews {
     if let v = o as? NSView {
         v.removeFromSuperview()
     }
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.