ฉันต้องการแสดงรายการมุมมองย่อยทั้งหมดในไฟล์UIViewController
. ฉันลองself.view.subviews
แล้ว แต่มุมมองย่อยบางรายการไม่ปรากฏในรายการตัวอย่างเช่นUITableViewCell
ไม่พบมุมมองย่อยในรายการ ความคิดใด ๆ ?
ฉันต้องการแสดงรายการมุมมองย่อยทั้งหมดในไฟล์UIViewController
. ฉันลองself.view.subviews
แล้ว แต่มุมมองย่อยบางรายการไม่ปรากฏในรายการตัวอย่างเช่นUITableViewCell
ไม่พบมุมมองย่อยในรายการ ความคิดใด ๆ ?
คำตอบ:
คุณต้องวนซ้ำมุมมองย่อยซ้ำ
- (void)listSubviewsOfView:(UIView *)view {
// Get the subviews of the view
NSArray *subviews = [view subviews];
// Return if there are no subviews
if ([subviews count] == 0) return; // COUNT CHECK LINE
for (UIView *subview in subviews) {
// Do what you want to do with the subview
NSLog(@"%@", subview);
// List the subviews of subview
[self listSubviewsOfView:subview];
}
}
ตามความคิดเห็นของ @Greg Meletic คุณสามารถข้าม COUNT CHECK LINE ด้านบนได้
recursiveDescription
คำตอบที่ง่ายกว่ามากจาก @natbro - stackoverflow.com/a/8962824/429521
วิธีการในตัว xcode / gdb ในการถ่ายโอนข้อมูลลำดับชั้นมุมมองมีประโยชน์ - recursiveDescription ต่อhttp://developer.apple.com/library/ios/#technotes/tn2239/_index.html
แสดงลำดับชั้นมุมมองที่สมบูรณ์ยิ่งขึ้นซึ่งคุณอาจพบว่ามีประโยชน์:
> po [_myToolbar recursiveDescription]
<UIToolbarButton: 0xd866040; frame = (152 0; 15 44); opaque = NO; layer = <CALayer: 0xd864230>>
| <UISwappableImageView: 0xd8660f0; frame = (0 0; 0 0); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0xd86a160>>
[_myToolbar recursiveDescription]
ในรหัสของฉันหรือที่อื่น ๆ
โซลูชันการเรียกซ้ำที่หรูหราใน Swift:
extension UIView {
func subviewsRecursive() -> [UIView] {
return subviews + subviews.flatMap { $0.subviewsRecursive() }
}
}
คุณสามารถเรียก subviewsRecursive () บน UIView ใดก็ได้:
let allSubviews = self.view.subviewsRecursive()
คุณต้องพิมพ์ซ้ำวิธีนี้ยังแท็บตามความลึกของมุมมอง
-(void) printAllChildrenOfView:(UIView*) node depth:(int) d
{
//Tabs are just for formatting
NSString *tabs = @"";
for (int i = 0; i < d; i++)
{
tabs = [tabs stringByAppendingFormat:@"\t"];
}
NSLog(@"%@%@", tabs, node);
d++; //Increment the depth
for (UIView *child in node.subviews)
{
[self printAllChildrenOfView:child depth:d];
}
}
นี่คือเวอร์ชันที่รวดเร็ว
func listSubviewsOfView(view:UIView){
// Get the subviews of the view
var subviews = view.subviews
// Return if there are no subviews
if subviews.count == 0 {
return
}
for subview : AnyObject in subviews{
// Do what you want to do with the subview
println(subview)
// List the subviews of subview
listSubviewsOfView(subview as UIView)
}
}
ฉันไปงานปาร์ตี้ช้าไปหน่อย แต่วิธีแก้ปัญหาทั่วไปเล็กน้อย:
@implementation UIView (childViews)
- (NSArray*) allSubviews {
__block NSArray* allSubviews = [NSArray arrayWithObject:self];
[self.subviews enumerateObjectsUsingBlock:^( UIView* view, NSUInteger idx, BOOL*stop) {
allSubviews = [allSubviews arrayByAddingObjectsFromArray:[view allSubviews]];
}];
return allSubviews;
}
@end
หากสิ่งที่คุณต้องการคืออาร์เรย์ของUIView
s นี่คือโซลูชันซับเดียว ( Swift 4+ ):
extension UIView {
var allSubviews: [UIView] {
return self.subviews.reduce([UIView]()) { $0 + [$1] + $1.allSubviews }
}
}
ฉันใช้วิธีนี้:
NSLog(@"%@", [self.view subviews]);
ใน UIViewController
extension UIView {
private func subviews(parentView: UIView, level: Int = 0, printSubviews: Bool = false) -> [UIView] {
var result = [UIView]()
if level == 0 && printSubviews {
result.append(parentView)
print("\(parentView.viewInfo)")
}
for subview in parentView.subviews {
if printSubviews { print("\(String(repeating: "-", count: level))\(subview.viewInfo)") }
result.append(subview)
if subview.subviews.isEmpty { continue }
result += subviews(parentView: subview, level: level+1, printSubviews: printSubviews)
}
return result
}
private var viewInfo: String { return "\(classForCoder), frame: \(frame))" }
var allSubviews: [UIView] { return subviews(parentView: self) }
func printSubviews() { _ = subviews(parentView: self, printSubviews: true) }
}
view.printSubviews()
print("\(view.allSubviews.count)")
ในทางของฉันหมวดหมู่หรือส่วนขยายของ UIView ดีกว่าคนอื่นมากและการเรียกซ้ำเป็นจุดสำคัญในการรับมุมมองย่อยทั้งหมด
เรียนรู้เพิ่มเติม:
https://github.com/ZhipingYang/XYDebugView
@implementation UIView (Recurrence)
- (NSArray<UIView *> *)recurrenceAllSubviews
{
NSMutableArray <UIView *> *all = @[].mutableCopy;
void (^getSubViewsBlock)(UIView *current) = ^(UIView *current){
[all addObject:current];
for (UIView *sub in current.subviews) {
[all addObjectsFromArray:[sub recurrenceAllSubviews]];
}
};
getSubViewsBlock(self);
return [NSArray arrayWithArray:all];
}
@end
ตัวอย่าง
NSArray *views = [viewController.view recurrenceAllSubviews];
extension UIView {
func recurrenceAllSubviews() -> [UIView] {
var all = [UIView]()
func getSubview(view: UIView) {
all.append(view)
guard view.subviews.count>0 else { return }
view.subviews.forEach{ getSubview(view: $0) }
}
getSubview(view: self)
return all
}
}
ตัวอย่าง
let views = viewController.view.recurrenceAllSubviews()
โดยตรงใช้ฟังก์ชันลำดับเพื่อรับมุมมองย่อยทั้งหมด
let viewSequence = sequence(state: [viewController.view]) { (state: inout [UIView] ) -> [UIView]? in
guard state.count > 0 else { return nil }
defer {
state = state.map{ $0.subviews }.flatMap{ $0 }
}
return state
}
let views = viewSequence.flatMap{ $0 }
สาเหตุที่ไม่พิมพ์มุมมองย่อยใน UITableViewCell เนื่องจากคุณต้องส่งออกมุมมองย่อยทั้งหมดในระดับบนสุด มุมมองย่อยของเซลล์ไม่ใช่มุมมองย่อยโดยตรงของมุมมองของคุณ
ในการรับมุมมองย่อยของ UITableViewCell คุณต้องกำหนดว่ามุมมองย่อยใดที่เป็นของ UITableViewCell (ใช้isKindOfClass:
) ในลูปการพิมพ์ของคุณจากนั้นจึงวนผ่านมุมมองย่อย
แก้ไข: บล็อกโพสต์เกี่ยวกับEasy UIView Debuggingอาจช่วยได้
ฉันเขียนหมวดหมู่เพื่อแสดงรายการมุมมองทั้งหมดที่จัดขึ้นโดยผู้ควบคุมมุมมองซึ่งได้รับแรงบันดาลใจจากคำตอบที่โพสต์ไว้ก่อนหน้านี้
@interface UIView (ListSubviewHierarchy)
- (NSString *)listOfSubviews;
@end
@implementation UIView (ListSubviewHierarchy)
- (NSInteger)depth
{
NSInteger depth = 0;
if ([self superview]) {
deepth = [[self superview] depth] + 1;
}
return depth;
}
- (NSString *)listOfSubviews
{
NSString * indent = @"";
NSInteger depth = [self depth];
for (int counter = 0; counter < depth; counter ++) {
indent = [indent stringByAppendingString:@" "];
}
__block NSString * listOfSubviews = [NSString stringWithFormat:@"\n%@%@", indent, [self description];
if ([self.subviews count] > 0) {
[self.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
UIView * subview = obj;
listOfSubviews = [listOfSubviews stringByAppendingFormat:@"%@", [subview listOfSubviews]];
}];
}
return listOfSubviews;
}
@end
ในการแสดงรายการมุมมองทั้งหมดที่มีอยู่โดยตัวควบคุมมุมมองเพียงNSLog("%@",[self listOfSubviews])
ซึ่งself
หมายถึงตัวควบคุมมุมมองเอง แม้ว่าจะยังไม่เลิกใช้งานอย่างมีประสิทธิภาพ
นอกจากนี้คุณสามารถใช้NSLog(@"\n%@", [(id)self.view performSelector:@selector(recursiveDescription)]);
เพื่อทำสิ่งเดียวกันและฉันคิดว่ามันมีประสิทธิภาพมากกว่าการใช้งานของฉัน
ตัวอย่าง Swift ง่ายๆ:
var arrOfSub = self.view.subviews
print("Number of Subviews: \(arrOfSub.count)")
for item in arrOfSub {
print(item)
}
คุณสามารถลองใช้เคล็ดลับอาร์เรย์แฟนซีเช่น:
[self.view.subviews makeObjectsPerformSelector: @selector(printAllChildrenOfView)];
โค้ดเพียงบรรทัดเดียว แน่นอนคุณอาจต้องปรับเปลี่ยนวิธีการของคุณprintAllChildrenOfView
ไม่ให้ใช้พารามิเตอร์ใด ๆ หรือสร้างวิธีการใหม่
เข้ากันได้กับ Swift 2.0
นี่คือวิธีการเรียกซ้ำเพื่อรับมุมมองย่อยทั้งหมดของมุมมองทั่วไป:
extension UIView {
func subviewsList() -> [UIView] {
var subviews = self.subviews
if subviews.count == 0 {
return subviews + []
}
for v in subviews {
subviews += v.listSubviewsOfView()
}
return subviews
}
}
คุณจึงโทรหาได้ทุกที่ด้วยวิธีนี้:
let view = FooController.view
let subviews = view.subviewsList()
นี่เป็นการเขียนใหม่ของคำตอบนี้ :
ก่อนอื่นคุณต้องได้รับตัวชี้ / การอ้างอิงไปยังวัตถุที่คุณต้องการพิมพ์มุมมองย่อยทั้งหมด บางครั้งคุณอาจพบว่าการค้นหาวัตถุนั้นง่ายขึ้นโดยการเข้าถึงผ่านมุมมองย่อย ชอบpo someSubview.superview
. สิ่งนี้จะให้สิ่งต่างๆเช่น:
Optional<UIView>
▿ some : <FacebookApp.WhatsNewView: 0x7f91747c71f0; frame = (30 50; 354 636); clipsToBounds = YES; layer = <CALayer: 0x6100002370e0>>
superview
0x7f91747c71f0
เป็นตัวชี้ไปยังซูเปอร์วิวในการพิมพ์ superView คุณต้องใช้เบรกพอยต์
ในการทำขั้นตอนนี้คุณสามารถคลิกที่ 'ดูลำดับชั้นการแก้ไขข้อบกพร่อง' ไม่จำเป็นต้องมีจุดพัก
จากนั้นคุณสามารถทำได้อย่างง่ายดาย:
po [0x7f91747c71f0 recursiveDescription]
ซึ่งสำหรับฉันกลับมีบางอย่างเช่น:
<FacebookApp.WhatsNewView: 0x7f91747c71f0; frame = (30 50; 354 636); clipsToBounds = YES; layer = <CALayer: 0x6100002370e0>>
| <UIStackView: 0x7f91747c75f0; frame = (45 60; 264 93); layer = <CATransformLayer: 0x610000230ec0>>
| | <UIImageView: 0x7f916ef38c30; frame = (10.6667 0; 243 58); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x61000003b840>>
| | <UIStackView: 0x7f91747c8230; frame = (44.6667 58; 174.667 35); layer = <CATransformLayer: 0x6100006278c0>>
| | | <FacebookApp.CopyableUILabel: 0x7f91747a80b0; baseClass = UILabel; frame = (44 0; 86.6667 16); text = 'What's New'; gestureRecognizers = <NSArray: 0x610000c4a770>; layer = <_UILabelLayer: 0x610000085550>>
| | | <FacebookApp.CopyableUILabel: 0x7f916ef396a0; baseClass = UILabel; frame = (0 21; 174.667 14); text = 'Version 14.0.5c Oct 05, 2...'; gestureRecognizers = <NSArray: 0x610000c498a0>; layer = <_UILabelLayer: 0x610000087300>>
| <UITextView: 0x7f917015ce00; frame = (45 183; 264 403); text = ' • new Adding new feature...'; clipsToBounds = YES; gestureRecognizers = <NSArray: 0x6100000538f0>; layer = <CALayer: 0x61000042f000>; contentOffset: {0, 0}; contentSize: {264, 890}>
| | <<_UITextContainerView: 0x7f9170a13350; frame = (0 0; 264 890); layer = <_UITextTiledLayer: 0x6080002c0930>> minSize = {0, 0}, maxSize = {1.7976931348623157e+308, 1.7976931348623157e+308}, textContainer = <NSTextContainer: 0x610000117b20 size = (264.000000,340282346638528859811704183484516925440.000000); widthTracksTextView = YES; heightTracksTextView = NO>; exclusionPaths = 0x61000001bc30; lineBreakMode = 0>
| | | <_UITileLayer: 0x60800023f8a0> (layer)
| | | <_UITileLayer: 0x60800023f3c0> (layer)
| | | <_UITileLayer: 0x60800023f360> (layer)
| | | <_UITileLayer: 0x60800023eca0> (layer)
| | <UIImageView: 0x7f9170a7d370; frame = (-39 397.667; 36 2.33333); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x60800023f4c0>>
| | <UIImageView: 0x7f9170a7d560; frame = (258.667 -39; 2.33333 36); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x60800023f5e0>>
| <UIView: 0x7f916ef149c0; frame = (0 587; 354 0); layer = <CALayer: 0x6100006392a0>>
| <UIButton: 0x7f91747a8730; frame = (0 0; 0 0); clipsToBounds = YES; opaque = NO; layer = <CALayer: 0x610000639320>>
| | <UIButtonLabel: 0x7f916ef00a80; frame = (0 -5.66667; 0 16); text = 'See More Details'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x610000084d80>>
อย่างที่คุณต้องเดาว่าซูเปอร์วิวของฉันมี 4 มุมมองย่อย:
สิ่งนี้ค่อนข้างใหม่สำหรับฉัน แต่ได้ช่วยฉันแก้จุดบกพร่องเฟรมของมุมมอง (และข้อความและประเภท) หนึ่งในมุมมองย่อยของฉันไม่ปรากฏบนหน้าจอดังนั้นจึงใช้ recursiveDescription และฉันก็ตระหนักว่าความกว้างของหนึ่งในมุมมองย่อยของฉันคือ0
... ดังนั้นฉันจึงแก้ไขข้อ จำกัด และมุมมองย่อยก็ปรากฏขึ้น
หรือหากคุณต้องการส่งคืนอาร์เรย์ของมุมมองย่อยทั้งหมด (และมุมมองย่อยที่ซ้อนกัน) จากส่วนขยาย UIView:
func getAllSubviewsRecursively() -> [AnyObject] {
var allSubviews: [AnyObject] = []
for subview in self.subviews {
if let subview = subview as? UIView {
allSubviews.append(subview)
allSubviews = allSubviews + subview.getAllSubviewsRecursively()
}
}
return allSubviews
}
AC # Xamarin รุ่น:
void ListSubviewsOfView(UIView view)
{
var subviews = view.Subviews;
if (subviews.Length == 0) return;
foreach (var subView in subviews)
{
Console.WriteLine("Subview of type {0}", subView.GetType());
ListSubviewsOfView(subView);
}
}
หรือหากคุณต้องการค้นหามุมมองย่อยทั้งหมดของประเภทเฉพาะที่ฉันใช้:
List<T> FindViews<T>(UIView view)
{
List<T> allSubviews = new List<T>();
var subviews = view.Subviews.Where(x => x.GetType() == typeof(T)).ToList();
if (subviews.Count == 0) return allSubviews;
foreach (var subView in subviews)
{
allSubviews.AddRange(FindViews<T>(subView));
}
return allSubviews;
}
ฉันได้ทำในหมวดหมู่UIView
เพียงเรียกใช้ฟังก์ชันที่ส่งดัชนีเพื่อพิมพ์ด้วยรูปแบบต้นไม้ที่ดี นี่เป็นเพียงตัวเลือกของคำตอบโพสต์โดยอีกเจมส์เว็บสเตอร์
#pragma mark - Views Tree
- (void)printSubviewsTreeWithIndex:(NSInteger)index
{
if (!self)
{
return;
}
NSString *tabSpace = @"";
@autoreleasepool
{
for (NSInteger x = 0; x < index; x++)
{
tabSpace = [tabSpace stringByAppendingString:@"\t"];
}
}
NSLog(@"%@%@", tabSpace, self);
if (!self.subviews)
{
return;
}
@autoreleasepool
{
for (UIView *subView in self.subviews)
{
[subView printViewsTreeWithIndex:index++];
}
}
}
ฉันหวังว่ามันจะช่วย :)
- (NSString *)recusiveDescription:(UIView *)view
{
NSString *s = @"";
NSArray *subviews = [view subviews];
if ([subviews count] == 0) return @"no subviews";
for (UIView *subView in subviews) {
s = [NSString stringWithFormat:@"<%@; frame = (%f %f : %f %f) \n ",NSStringFromClass([subView class]), subView.frame.origin.x, subView.frame.origin.y ,subView.frame.size.width, subView.frame.size.height];
[self recusiveDescription:subView];
}
return s;
}
self.view.subviews รักษามรดกของมุมมองในการรับมุมมองย่อยของ uitableviewcell คุณต้องทำสิ่งต่อไปนี้
for (UIView *subView in self.view.subviews) {
if ([subView isKindOfClass:[UITableView class]]) {
for (UIView *tableSubview in subView.subviews) {
.......
}
}
}