Как удалить все подпредставления вида в Swift?

176

Я ищу простой способ удалить сразу все подпредставления из суперпредставления вместо того, чтобы удалять их по одному.

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

Чего мне не хватает?

ОБНОВИТЬ

Мое приложение имеет основной container_view. Я должен добавить другие виды в качестве подпредставлений container_view, чтобы обеспечить своего рода навигацию.

Поэтому, когда я нажимаю кнопку, чтобы «открыть» определенную страницу, мне нужно удалить все подвиды и добавить новую.

ОБНОВЛЕНИЕ 2 - рабочее решение (OS X)

Я думаю, Apple исправила это.

Теперь это проще, чем когда-либо, просто позвоните:

for view in containerView.subviews{
    view.removeFromSuperview()
}
Альберто Беллини
источник
2
Я хотел бы отметить, что ответ @ sulthan, хотя он и похоронен с тряпками, является лучшим ответом: stackoverflow.com/questions/24312760/…
Кристофер Свази,
@ChristopherSwasey Swift 4 выдает ошибку: Невозможно присвоить свойству: «subviews» - свойство только для получения. :(
Уильям Т. Маллард
2
@ WilliamT. Маллард, сколько раз нужно повторить, что этот метод и вопрос касаются MacOS, а не iOS?
Fogmeister

Ответы:

358

РЕДАКТИРОВАТЬ: (спасибо Иеремия / Ролло)

Безусловно, лучший способ сделать это в Swift для iOS - это:

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

^^ Эти функции забавны!

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

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

//// КОНЕЦ РЕДАКТИРОВАНИЯ

Просто сделай это:

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

Или если вы ищете определенный класс

for view:CustomViewClass! in self.view.subviews {
        if view.isKindOfClass(CustomViewClass) {
            view.doClassThing()
        }
    }
Bseaborn
источник
В Xcode 7.0 beta 6 это генерирует предупреждение: «результат вызова 'map' не используется". Я надеюсь, что это будет исправлено в финальной версии.
Ferschae Naej
Я тоже это заметил! Я обновлю пост, как только Xcode выйдет из бета-версии и проблема все еще сохраняется.
Bseaborn
8
Предупреждение, result of call to 'map' is unused не является ошибкой. Array.mapв большинстве языков вернет измененный массив. Эквивалентный метод, который не возвращает массив, был бы view.subviews.forEach.
Rollo
for view:CustomViewClass! in self.view.subviews where view.isKindOfClass(CustomViewClass) { view.doClassThing() }
iTSangar
Я бы сказал , что это «Безусловно лучший способ сделать это в Swift», см stackoverflow.com/a/24314054/1974224
Cristik
41

Для iOS / Swift, чтобы избавиться от всех подпредставлений, которые я использую:

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

чтобы избавиться от всех подпредставлений определенного класса (например, UILabel), я использую:

for v in view.subviews{
   if v is UILabel{
      v.removeFromSuperview()
   }
}
tonethar
источник
31

Код может быть написан проще следующим образом.

view.subviews.forEach { $0.removeFromSuperview() }
mishimay
источник
19

Это должно быть самое простое решение.

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

(см. Удалить все подпредставления? для других методов)


Обратите внимание, что это вопрос MacOS, и этот ответ работает только для MacOS . Это не работает на iOS.

Sulthan
источник
Это, безусловно, самый простой способ ... removeFromSuperview автоматически вызывается для каждого представления, которого больше нет в массиве subviews.
Кристофер Свази
2
@datayeah Нет, но есть большая разница между NSView(OS X) и UIView(iOS).
Султан
@ Султан, ты прав. Я пришел сюда за ответом Swift для UIView и не прочитал весь ваш фрагмент кода;)
datayeah
1
Swift 4 выдает ошибку: Невозможно присвоить свойству: «subviews» - свойство только для получения. :(
Уильям Т. Маллард
1
@AmrAngry Опять же, повторюсь, это всегда был вопрос для Mac OS, а NSViewне для iOS и UIView. Только люди не хотят читать вопрос и теги, поэтому он заполнился ответами iOS.
Sulthan
10

Я не знаю, удалось ли вам решить эту проблему, но недавно я столкнулся с подобной проблемой, когда цикл For оставлял один просмотр каждый раз. Я обнаружил, что это произошло потому, что self.subviews был видоизменен (возможно) при вызове removeFromSuperview ().

Чтобы это исправить я сделал:

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

Выполнив .copy (), я мог выполнить удаление каждого подпредставления, изменяя массив self.subviews. Это потому, что скопированный массив (subViews) содержит все ссылки на объекты и не является мутированным.

РЕДАКТИРОВАТЬ: В вашем случае я думаю, что вы бы использовать:

let theSubviews: Array = container_view.subviews.copy()
for (var view: NSView!) in theSubviews
{
    view.removeFromSuperview()
}
Адам Ричардс
источник
Работает просто отлично! Спасибо
Альберто Беллини
Здравствуйте, попробуйте следующее, хотя, вероятно, есть гораздо более элегантный способ сделать это: let subViewsArray: Array = (parentView.subviews as NSArray).copy() as Array<NSView>
Адам Ричардс
9

Попробуй это:

for view in container_view.subviews {
    view.removeFromSuperview()
}
MattL
источник
9

Расширение для удаления всех подпредставлений, оно быстро удаляется.

import Foundation
import UIKit

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

}
YannSteph
источник
1
почему карта? foreach может быть? subviews.forEach {$ 0.removeFromSuperview ()}
Запорожченко Александр
1
Да, вы правы @Aleksandr Я думаю, что когда я писал это, мне не нужно было
пить
6

Попробуй это:

var subViews = parentView.subviews as Array<UIView>

      for someView in subViews
      {
          someView.removeFromSuperview()
      }

ОБНОВЛЕНИЕ : Если вы чувствуете себя предприимчивым, вы можете сделать расширение в UIView, как показано ниже:

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

}

И назовите это так:

parentView.removeAllSubViews()
azamsharp
источник
2 мелочи: я работаю над osx, поэтому было бы <NSView> правильно? Затем я получаю «фатальную ошибку: индекс массива вне диапазона»: /
Альберто Беллини
Да, я думаю, что на OSX это NSView. Где вы берете роковую ошибку?
azamsharp
Вы уверены, что ваше родительское представление имеет дочерние элементы?
azamsharp
Ага ! Если я сделаю println (parentView.subviews), я получу 1
Альберто Беллини
Это странно! Обычно вне диапазона означает, что вы обращаетесь к индексу, который не существует, и обычно я считаю, что это вызвано использованием цикла for с индексами, такими как i ++.
azamsharp
5

В xcodebeta6 это сработало.

    var subViews = self.parentView.subviews
    for subview in subViews as [UIView]   {
        subview.removeFromSuperview()
    }
hatebyte
источник
Это iOS. Мне нужно решение для OS X
Альберто Беллини
Отличное решение для IOS +1
inVINCEable
3

Я написал это расширение:

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

Так что вы можете использовать self.view.lf_removeAllSubviews в UIViewController. Я опубликую это в быстрой версии моей https://github.com/superarts/LFramework позже, когда у меня будет больше опыта в быстрой работе (пока 1 день опыта, и да, для API я отказался от подчеркивания).

superarts.org
источник
3

Swift 3

Если вы добавите тег к своему виду, вы можете удалить определенный вид.

for v in (view?.subviews)!
{
    if v.tag == 321
    {
         v.removeFromSuperview()
    }
 }
uplearnedu.com
источник
почему нет view.subviews.filter({$0.tag != 321}).forEach({$0.removeFromSuperview()})?
AlexanderZ
3

Swift 5

Я создаю 2 разных метода для удаления подпредставления. И это гораздо проще использовать, если мы поместим их вextension

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
источник
2

Ваш синтаксис немного выключен. Убедитесь, что вы разыгрываете явно.

 let theSubviews : Array<NSView> = container_view.subviews as Array<NSView>
 for view in theSubviews {
     view.removeFromSuperview()
 }
разъем
источник
@ Давид Да, я старался держать его как можно ближе к исходному коду FoxNos.
Джек
2

ты должен попробовать это

func clearAllScrollSubView ()
{
    let theSubviews = itemsScrollView.subviews

    for (var view) in theSubviews
    {

        if view is UIView
        {
            view.removeFromSuperview()
        }

    }
}
Ахмед Зайтоун
источник
Это UI, а не NS. Здесь мы говорим об OS X. Если это работает даже при замене пользовательского интерфейса на NS, мой плохой, вы были правы :)
Альберто Беллини
1

Для удаления только подпредставлений определенного класса - это был единственный код Swift, который работал для меня в Xcode6.1.1. Предполагая, что единственные подпредставления, которые вы хотите удалить, имеют тип UIButton ...

for subView in nameofmysuperview.subviews {
    if subView.isKindOfClass(UIButton) {
        subView.removeFromSuperview()
    }
}
gammachill
источник
1

Один лайнер:

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

Я думаю, что этот подход более читабелен, чем «однострочники», использующие map или forEach . Сокращенный foreach и map могут быть трудны для понимания, так как логика более абстрактна.

eonist
источник
1

Для Swift 3

Я сделал следующее, потому что просто удаление из суперпредставления не стирало кнопки из массива.

    for k in 0..<buttons.count {

      buttons[k].removeFromSuperview()

    }


    buttons.removeAll()
Надежда
источник
1

Попробуйте, я проверил это:

  let theSubviews = container_view.subviews
  for subview in theSubviews {
      subview.removeFromSuperview()
  }
Ezimet
источник
1

Для Swift 4.+

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

}

Я надеюсь, что это полно для вас.

Масуд Хейдари
источник
-2

ты пробовал что-то вроде

for o : AnyObject in self.subviews {
     if let v = o as? NSView {
         v.removeFromSuperview()
     }
}
Кристиан Дитрих
источник