Как удалить все подпредставления вида в 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()
        }
    }

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

31

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

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

19

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

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

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


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


Это, безусловно, самый простой способ ... 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()
}

9

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

import Foundation
import UIKit

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

}

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

2 мелочи: я работаю над osx, поэтому было бы <NSView> правильно? Затем я получаю «фатальную ошибку: индекс массива вне диапазона»: /
Альберто Беллини

Да, я думаю, что на OSX это NSView. Где вы берете роковую ошибку?
azamsharp

Вы уверены, что ваше родительское представление имеет дочерние элементы?
azamsharp

Ага ! Если я сделаю println (parentView.subviews), я получу 1
Альберто Беллини

Это странно! Обычно вне диапазона означает, что вы обращаетесь к индексу, который не существует, и обычно я считаю, что это вызвано использованием цикла for с индексами, такими как i ++.
azamsharp


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 я отказался от подчеркивания).


3

Swift 3

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

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

почему нет 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() }
    }
}

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

1

Один лайнер:

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

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


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

1

Для Swift 4.+

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

}

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


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.