如何在Swift中删除视图的所有子视图?

223

我正在寻找一种简单的方法,可以同时从父视图中删除所有子视图,而不是逐个删除它们。

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

我想苹果已经解决了这个问题。

现在比以往更容易了,只需调用:

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

2
我想指出@sulthan的答案,虽然被其他回答掩盖了,但是它是优秀的答案:https://dev59.com/CGAf5IYBdhLWcg3wwk4V#24314054 - Christopher Swasey
@ChristopherSwasey Swift 4 给出了一个错误:无法分配给属性:'subviews' 是只读属性。 :( - William T. Mallard
2
@WilliamT.Mallard,需要重复多少次才能说明这个方法和问题是关于MacOS而不是iOS的? - Fogmeister
22个回答

411

编辑:(感谢Jeremiah / Rollo)

在Swift for 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() })

就这样做:

//// END EDIT

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

或者,如果你正在寻找特定的类

for view:CustomViewClass! in self.view.subviews {
        if view.isKindOfClass(CustomViewClass) {
            view.doClassThing()
        }
    }

您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Ferschae Naej
我也注意到了!一旦Xcode退出beta版本并且问题仍然存在,我会更新帖子。 - Bseaborn
10
警告“未使用'map'的调用结果”不是错误。在大多数语言中,Array.map将返回修改后的数组。不返回数组的等效方法将是view.subviews.forEach - user916367
view.doClassThing() }```可以翻译为:在`self.view`的子视图中,对于每一个类型为`CustomViewClass`的视图`view`,执行`view.doClassThing()`方法。 - iTSangar
@Cristik,我错了!感谢你指出来。我确实混淆了两者。我会更新我的答案。 - Bseaborn
显示剩余4条评论

46

对于iOS/Swift,我使用以下代码来删除所有子视图:

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

我使用以下代码来清除特定类别(如UILabel)的所有子视图:

for v in view.subviews{
   if v is UILabel{
      v.removeFromSuperview()
   }
}

40

代码可以更简单地写成如下形式。

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

24

这应该是最简单的解决方案。

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

(其他方法请参见Remove all subviews?)


注意,这是一个适用于MacOS的问题,此答案仅适用于MacOS,在iOS上不适用。


2
@datayeah 它们不同,但NSView(OS X)和UIView(iOS)之间有很大的区别。 - Sulthan
我更倾向于创建一个扩展来实现removeAllSubviews()UIView上。更容易记住。 - Chen Li Yong
1
Swift 4 出现错误:无法分配给属性:'subviews' 是只读属性。 :( - William T. Mallard
@WilliamT.Mallard 这原本是一个 OS X 的问题,这就是 OS X 的答案。 - Sulthan
2
@AmrAngry 再次重申,这始终是一个关于 NSView 的 Mac OS 问题,而不是 iOS 和 UIView。只有那些不愿意仔细阅读问题和标签的人才会提供 iOS 的答案。 - Sulthan
显示剩余2条评论

23

Swift 5

我创建了两种不同的方法来移除子视图。如果我们将它们放在 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() }
    }
}

14

试试这个:

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

11

移除所有子视图的扩展,可以快速移除。

import Foundation
import UIKit

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

}

1
为什么使用map?foreach可能吗?subviews.forEach { $0.removeFromSuperview() } - Zaporozhchenko Oleksandr
1
是的,你说得对@Aleksandr。我想当我写这篇文章时,我还没有喝咖啡。 - YannSteph

11

我不知道你是否已经解决了这个问题,但我最近遇到了一个类似的问题,即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
你好,请尝试以下代码,虽然可能有更优雅的方法来实现这个:let subViewsArray: Array = (parentView.subviews as NSArray).copy() as Array<NSView> - Adam Richards

8
尝试一下这个:

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

两个小问题:我正在使用OSX,因此应该是<NSView>对吧?然后,我遇到了“致命错误:数组索引超出范围”:/ - Alberto
是的,在OSX上我认为它是NSView。你在哪里遇到了致命错误? - azamsharp
你确定你的父视图有子元素吗? - azamsharp
没错!如果我执行println(parentView.subviews),会得到1。 - Alberto
这很奇怪!通常超出范围意味着您正在访问不存在的索引,通常我认为这是使用类似i++的索引for循环引起的。 - azamsharp

7
在Xcode beta6中,这个问题得到了解决。
    var subViews = self.parentView.subviews
    for subview in subViews as [UIView]   {
        subview.removeFromSuperview()
    }

那是iOS。我需要一个OS X的解决方案。 - Alberto
IOS +1 大杀器 - inVINCEable

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接