我在UIView中有一个自定义类按钮,我想将它添加到一个数组中,以便它们易于访问。有没有办法获取特定类的所有子视图并将其添加到Swift中的数组?
答案 0 :(得分:61)
使用filter
运算符的is
函数可以过滤特定类的项目。
let myViews = view.subviews.filter{$0 is MyButtonClass}
MyButtonClass
是要过滤的自定义类。
答案 1 :(得分:25)
你去吧
extension UIView {
/** This is the function to get subViews of a view of a particular type
*/
func subViews<T : UIView>(type : T.Type) -> [T]{
var all = [T]()
for view in self.subviews {
if let aView = view as? T{
all.append(aView)
}
}
return all
}
/** This is a function to get subViews of a particular type from view recursively. It would look recursively in all subviews and return back the subviews of the type T */
func allSubViewsOf<T : UIView>(type : T.Type) -> [T]{
var all = [T]()
func getSubview(view: UIView) {
if let aView = view as? T{
all.append(aView)
}
guard view.subviews.count>0 else { return }
view.subviews.forEach{ getSubview(view: $0) }
}
getSubview(view: self)
return all
}
}
您可以将其称为
let allSubviews = view.allSubViewsOf(type: UIView.self)
let allLabels = view.allSubViewsOf(type: UILabel.self)
答案 2 :(得分:14)
要以递归方式执行此操作(即获取所有子视图的视图),您可以使用此通用函数:
private func getSubviewsOf<T : UIView>(view:UIView) -> [T] {
var subviews = [T]()
for subview in view.subviews {
subviews += getSubviewsOf(view: subview) as [T]
if let subview = subview as? T {
subviews.append(subview)
}
}
return subviews
}
要获取视图层次结构中的所有UILabel,只需执行以下操作:
let allLabels : [UILabel] = getSubviewsOf(view: theView)
答案 3 :(得分:11)
我现在无法测试它,但这应该适用于Swift 2:
view.subviews.flatMap{ $0 as? YourView }
返回YourView
这是一个经过测试的典型示例,用于计算:
countDots = allDots!.view.subviews.flatMap{$0 as? Dot}.count
答案 4 :(得分:5)
如果您想更新/访问这些特定的子视图,请使用此
<!DOCTYPE HTML>
<html>
<head>
<style>
.tooltip {
position: relative;
display: inline-block;
top: 200px;
}
.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: #555;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px 0;
position: absolute;
z-index: 1;
bottom: 125%;
left: 50%;
margin-left: -60px;
opacity: 0;
transition: opacity 1s;
}
.tooltip .tooltiptext::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: #555 transparent transparent transparent;
}
.tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
}
</style>
</head>
<body bgcolor="#008080">
<body style="text-align:center">
<div class="tooltip">Genu of Corpus Callosum <span class="tooltiptext">Tooltip text </span>
</div>
<canvas id="myCanvas" width="900" height="800"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, 300, 200, 400, 400);
//doen frontal 1
context.beginPath();
context.moveTo(150, 250);
context.lineTo(450, 250);
context.stroke();
//Done
context.strokeStyle = "white";
context.beginPath();
context.moveTo(150, 470);
context.lineTo(450, 480);
context.stroke();
//done
context.strokeStyle = "white";
context.beginPath();
context.moveTo(150, 380);
context.lineTo(420, 360);
context.stroke();
//4done
context.strokeStyle = "white";
context.beginPath();
context.moveTo(80, 530);
context.lineTo(450, 550);
context.stroke();
//3do
context.strokeStyle = "white";
context.beginPath();
context.moveTo(80, 420);
context.lineTo(380, 400);
context.stroke();
//done frontal horn
context.strokeStyle = "white";
context.beginPath();
context.moveTo(800, 300);
context.lineTo(480, 350);
context.stroke();
//gray mattr
context.strokeStyle = "white";
context.beginPath();
context.moveTo(750, 250);
context.lineTo(560, 300);
context.stroke();
//septum
context.strokeStyle = "white";
context.beginPath();
context.moveTo(850, 350);
context.lineTo(450, 380);
context.stroke();
//putamen
context.strokeStyle = "white";
context.beginPath();
context.moveTo(850, 400);
context.lineTo(500, 400);
context.stroke();
//thalamus
context.strokeStyle = "white";
context.beginPath();
context.moveTo(850, 450);
context.lineTo(460, 430);
context.stroke();
//choroid
context.strokeStyle = "white";
context.beginPath();
context.moveTo(850, 500);
context.lineTo(460, 450);
context.stroke();
//occipital
context.strokeStyle = "white";
context.beginPath();
context.moveTo(850, 550)
context.lineTo(520, 520);
context.stroke();
context.strokeStyle = "white";
context.beginPath();
context.moveTo(850, 600)
context.lineTo(460, 660);
context.stroke();
};
imageObj.src = 'in.jpg';
</script>
</html>
答案 5 :(得分:3)
func allSubViews(views: [UIView]) {
for view in views {
if let tf = view as? UITextField {
// Do Something
}
self.allSubViews(views: view.subviews)
}
}
self.allSubViews(views: self.view.subviews)
答案 6 :(得分:2)
这里的许多答案都是不必要的冗长或笼统的。以下是获取 any 所需类的,处于任意深度的视图的所有子视图的方法:
extension UIView {
func subviews<T:UIView>(ofType WhatType:T.Type) -> [T] {
var result = self.subviews.compactMap {$0 as? T}
for sub in self.subviews {
result.append(contentsOf: sub.subviews(ofType:WhatType))
}
return result
}
}
使用方法:
let arr = myView.subviews(ofType: MyButtonClass.self)
答案 7 :(得分:1)
对于这种情况,我认为我们可以使用Swift的first.where
语法,这比filter.count
,filter.isEmpty
更有效。
因为当我们使用filter
时,它会创建一个底层数组,因此无效,想象我们有一个大集合。
因此,只需检查视图的subViews
集合是否包含特定类别,我们就可以使用此
let containsBannerViewKind = view.subviews.first(where: { $0 is BannerView }) != nil
相当于:在此视图的子视图集合中找到我与BannerView类的第一个匹配项。因此,如果这是真的,我们可以执行进一步的逻辑。
参考:https://github.com/realm/SwiftLint/blob/master/Rules.md#first-where
答案 8 :(得分:1)
从Swift 4.1开始,您可以使用新的compactMap(现在已不再使用flatMap):https://developer.apple.com/documentation/swift/sequence/2950916-compactmap (请参阅示例)
您可以使用:
let buttons:[UIButton] = stackView.subviews.compactMap{ $0 as? UIButton }
您可以使用map对所有按钮执行操作:
let _ = stackView.subviews.compactMap{ $0 as? UIButton }.map { $0.isSelected = false }
答案 9 :(得分:0)
UIView有一个名为subViews
的属性,你可以看到API。
答案 10 :(得分:0)
让我发布我对此的变化),但是,找到T的第一个
extension UIView {
func firstSubView<T: UIView>(ofType type: T.Type) -> T? {
var resultView: T?
for view in subviews {
if let view = view as? T {
resultView = view
break
}
else {
if let foundView = view.firstSubView(ofType: T.self) {
resultView = foundView
break
}
}
}
return resultView
}
}
答案 11 :(得分:0)
我已经遍历了以上所有答案,它们涵盖了视图当前显示在窗口中的情况,但是没有提供视图控制器中未在窗口中显示的视图。
基于@matt的答案,我编写了以下函数,该函数以递归方式遍历所有视图,包括非可视视图控制器,子视图控制器,导航控制器视图控制器,并使用下一个响应程序
(注意:可以进行最终改进,因为它在递归函数的基础上增加了更多复杂性。请将其视为概念证明)
/// Returns the array of subviews in the view hierarchy which match the provided type, including any hidden
/// - Parameter type: the type filter
/// - Returns: the resulting array of elements matching the given type
func allSubviews<T:UIView>(of type:T.Type) -> [T] {
var result = self.subviews.compactMap({$0 as? T})
var subviews = self.subviews
// *********** Start looking for non-visible view into view controllers ***********
// Inspect also the non visible views on the same level
var notVisibleViews = [UIView]()
subviews.forEach { (v) in
if let vc = v.next as? UIViewController {
let childVCViews = vc.children.filter({$0.isViewLoaded && $0.view.window == nil }).compactMap({$0.view})
notVisibleViews.append(contentsOf: childVCViews)
}
if let vc = v.next as? UINavigationController {
let nvNavVC = vc.viewControllers.filter({$0.isViewLoaded && $0.view.window == nil })
let navVCViews = nvNavVC.compactMap({$0.view})
notVisibleViews.append(contentsOf: navVCViews)
// detect child vc in not visible vc in the nav controller
let childInNvNavVC = nvNavVC.compactMap({$0.children}).reduce([],+).compactMap({$0.view})
notVisibleViews.append(contentsOf: childInNvNavVC)
}
if let vc = v.next as? UITabBarController {
let tabViewControllers = vc.viewControllers?.filter({$0.isViewLoaded && $0.view.window == nil }) ?? [UIViewController]()
// detect navigation controller in the hidden tab bar view controllers
let vc1 = tabViewControllers.compactMap({$0 as? UINavigationController})
vc1.forEach { (vc) in
let nvNavVC = vc.viewControllers.filter({$0.isViewLoaded && $0.view.window == nil })
let navVCViews = nvNavVC.compactMap({$0.view})
notVisibleViews.append(contentsOf: navVCViews)
// detect child vc in not visible vc in the nav controller
let childInNvNavVC = nvNavVC.compactMap({$0.children}).reduce([],+).compactMap({$0.view})
notVisibleViews.append(contentsOf: childInNvNavVC)
}
// ad non-navigation controller in the hidden tab bar view controllers
let tabVCViews = tabViewControllers.compactMap({($0 as? UINavigationController) == nil ? $0.view : nil})
notVisibleViews.append(contentsOf: tabVCViews)
}
}
subviews.append(contentsOf: notVisibleViews.removingDuplicates())
// *********** End looking for non-visible view into view controllers ***********
subviews.forEach({result.append(contentsOf: $0.allSubviews(of: type))})
return result.removingDuplicates()
}
extension Array where Element: Hashable {
func removingDuplicates() -> [Element] {
var dict = [Element: Bool]()
return filter { dict.updateValue(true, forKey: $0) == nil }
}
}
样品用量:
let allButtons = keyWindow.allSubviews(of: UIButton.self)
注意:如果当前显示的是模式视图控制器,则上述脚本找不到presentingViewController
中包含的视图。 (可以对此进行扩展,但是我找不到一种优雅的方法来实现它,因为此代码本身已经不是很优雅了:/)
这种需求可能并不常见,但也许可以帮助某个人:)
答案 12 :(得分:0)
斯威夫特 5
func findViewInside<T>(views: [UIView]?, findView: [T] = [], findType: T.Type = T.self) -> [T] {
var findView = findView
let views = views ?? []
guard views.count > .zero else { return findView }
let firstView = views[0]
var loopViews = views.dropFirst()
if let typeView = firstView as? T {
findView = findView + [typeView]
return findViewInside(views: Array(loopViews), findView: findView)
} else if firstView.subviews.count > .zero {
firstView.subviews.forEach { loopViews.append($0) }
return findViewInside(views: Array(loopViews), findView: findView)
} else {
return findViewInside(views: Array(loopViews), findView: findView)
}
}
使用方法:
findViewInside(views: ([View] or Views), findType: (YourType).self)