如何在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)
}

我缺少什么?

更新

我的应用有一个main container_viewcontainer_view为了提供某种导航,我必须添加其他不同的视图作为子视图。

因此,当单击按钮“打开”特定页面时,我需要删除所有子视图并添加新的子视图。

更新2-可行的解决方案(OS X)

我猜苹果已经解决了。

现在,它比以往更容易了,只需致电:

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

2
我想指出的是,@ sulthan的答案,而陪葬破布,是优越的答案:stackoverflow.com/questions/24312760/...
克里斯托弗SWASEY

@ChristopherSwasey Swift 4给出了一个错误:无法分配给属性:'subviews'是一个只能获取的属性。:(
威廉·T·马拉德

2
@ WilliamT.Mallard此方法和问题与MacOS有关而不与iOS有关,必须重复多少次?
Fogmeister

Answers:


358

编辑:(感谢耶利米/罗洛)

到目前为止,在iOS的Swift中做到这一点的最佳方法是:

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退出Beta版后,我将更新帖子,问题仍然存在。
2015年

8
警告,result of call to 'map' is unused 不是错误。Array.map在大多数语言中,将返回修改后的数组。不返回数组的等效方法为view.subviews.forEach
Rollo 2015年

for view:CustomViewClass! in self.view.subviews where view.isKindOfClass(CustomViewClass) { view.doClassThing() }
iTSangar 2015年

我认为这是“到目前为止,在Swift中最好的方法”,请参见stackoverflow.com/a/24314054/1974224
Cristik,2016年

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。


这绝对是最简单的方法...对于不再位于subviews数组中的每个视图,都会自动调用removeFromSuperview。
Christopher Swasey,2015年

2
@datayeah不是,但是NSView(OS X)和UIView(iOS)之间有很大的区别。
Sulthan

@Sulthan你是对的。我是来UIView的Swift答案的,而没有阅读您的整个代码片段;)
datayeah 2016年

1
Swift 4给出了一个错误:无法分配给属性:'subviews'是一个只能获取的属性。:(
威廉·T·马拉德

1
@AmrAngry再次,我重复一遍,这始终是Mac OS的问题NSView,不是iOS和UIView。只有人们不在乎阅读问题和标签,因此它充满了iOS答案。
苏珊(Sulthan)

10

我不知道您是否能够解决此问题,但是最近我遇到了类似的问题,For循环每次都留下一个视图。我发现这是因为在调用removeFromSuperview()时self.subviews发生了突变(也许)。

为了解决这个问题,我做到了:

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

效果很好!谢谢
Alberto Bellini 2014年

您好,请尝试以下方法,尽管可能有更优雅的方法: let subViewsArray: Array = (parentView.subviews as NSArray).copy() as Array<NSView>
Adam Richards

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

1
是的,您说得对@Aleksandr,我想当我写这篇文章时,我还没有喝咖啡
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>对吗?然后,我收到“严重错误:数组索引超出范围”:/
Alberto Bellini 2014年

是的,我认为在OSX上是NSView。您从哪里得到致命错误?
azamsharp 2014年

您确定父视图包含子元素吗?
azamsharp 2014年

是的!如果我进行println(parentView.subviews),我会得到1
Alberto Bellini

真奇怪!通常超出范围意味着您正在访问一个不存在的索引,通常我认为这是由于使用了带有i ++之类的for循环引起的。
azamsharp 2014年


3

我写了这个扩展名:

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

这样您就可以在UIViewController中使用self.view.lf_removeAllSubviews。稍后,当我对Swift有了更多的经验时,我将把它放在我的https://github.com/superarts/LFramework的swift版本中(到目前为止有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。在这里,我们谈论的是OSX。如果即使通过将UI替换为NS仍然可以使用OS X,那么我的意思是,您是对的:)
Alberto Bellini 2014年

1

对于仅删除特定类的子视图-这是Xcode6.1.1中唯一对我有用的Swift代码。假设要删除的唯一子视图的类型为UIButton ...

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

1

单线:

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

我认为这种方法比使用mapforEach的“单线”更具可读性。简短的foreachmap可能很难理解,因为逻辑更加抽象。


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


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.