Як видалити всі підгляди представлення даних у 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.Mallard, скільки разів потрібно повторити, що цей метод і питання стосуються MacOS, а не iOS?
Фогмайстер

Відповіді:


358

EDIT: (спасибі Jeremiah / Rollo)

На сьогодні найкращий спосіб зробити це у 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() }

18

Це має бути найпростішим рішенням.

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

(див. Видалення всіх підпереглядів? для інших методів)


Зверніть увагу, що це питання MacOS, і ця відповідь працює лише для MacOS . Він не працює на iOS.


Це, безумовно, найпростіший спосіб ... deleteFromSuperview автоматично викликається для кожного перегляду, який більше не знаходиться в масиві підпогляду.
Крістофер Свайсі

2
@datay yes Їх немає, але є велика різниця між NSView(OS X) та UIView(iOS).
Султан

@ Султан, ти маєш рацію. Я прийшов сюди за відповіді Swift для UIView і не прочитав увесь ваш фрагмент коду;)
datay yes

1
Swift 4 видає помилку: Неможливо призначити властивість: 'subviews' - властивість лише для отримання. :(
Вільям Т. Маллард

1
@AmrAngry Знову повторюю, це завжди було питання для Mac OS NSView, не для iOS і UIView. Тільки людям не байдуже читати питання та теги, тому відповіді на нього заповнили iOS.
Султан

10

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

Щоб виправити це, я зробив:

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

Роблячи .copy (), я міг виконати видалення кожного підперегляду, змінюючи масив self.subviews. Це пояснюється тим, що скопійований масив (subView) містить усі посилання на об'єкти і не мутується.

EDIT: У вашому випадку я думаю, ви б використали:

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
чому карта? передбачити, можливо? subviews.forEach {$ 0.removeFromSuperview ()}
Запорожченко Олександр

1
Так, ти прав @ Олександр, я думаю, коли я писав це, я не брав кави
YannSteph

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

Швидкий 3

Якщо ви додасте тег до свого перегляду, ви можете видалити певний вигляд.

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

чому ні view.subviews.filter({$0.tag != 321}).forEach({$0.removeFromSuperview()})?
AlexanderZ

3

Швидкий 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()
 }

@David Так, так, я намагався тримати його якомога ближче до початкового коду 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()}

Я думаю, що цей підхід є більш зрозумілим, ніж "однолінійки", використовуючи карту або forEach . Короткі руки Еогеасп і карта може бути важко зрозуміти, як логіка більш абстрактно.


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.