Tüm alt görünümleri bir UIViewController
. Denedim self.view.subviews
, ancak tüm alt görünümler listelenmedi, örneğin içindeki alt UITableViewCell
görünümler bulunamadı. Herhangi bir fikir?
Tüm alt görünümleri bir UIViewController
. Denedim self.view.subviews
, ancak tüm alt görünümler listelenmedi, örneğin içindeki alt UITableViewCell
görünümler bulunamadı. Herhangi bir fikir?
Yanıtlar:
Alt görünümleri yinelemeli olarak yinelemeniz gerekir.
- (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 tarafından yorumlandığı gibi, yukarıdaki COUNT KONTROL HATTI'nı atlayabilirsiniz.
recursiveDescription
Buradaysanız , LÜTFEN @natbro - stackoverflow.com/a/8962824/429521
Görünüm hiyerarşisini dökmenin xcode / gdb yerleşik yolu kullanışlıdır - http://developer.apple.com/library/ios/#technotes/tn2239/_index.html uyarınca recursiveDescription
Yararlı bulabileceğiniz daha eksiksiz bir görünüm hiyerarşisi sağlar:
> 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]
kodunu kodumun neresine veya başka bir yere koyacağım .
Özyinelemeli olarak yazdırmanız gerekir, bu yöntem aynı zamanda görünümün derinliğine göre sekmeler de oluşturur.
-(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];
}
}
İşte hızlı versiyon
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)
}
}
Partiye biraz geç kaldım, ancak biraz daha genel bir çözüm:
@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
Tek istediğiniz bir dizi UIView
diziyse, bu tek satırlık bir çözümdür ( Swift 4+ ):
extension UIView {
var allSubviews: [UIView] {
return self.subviews.reduce([UIView]()) { $0 + [$1] + $1.allSubviews }
}
}
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)")
Benim açımdan, UIView kategorisi veya uzantısı diğerlerinden çok daha iyi ve özyinelemeli, tüm alt görünümleri elde etmenin kilit noktasıdır.
daha fazla bilgi edin:
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
misal
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
}
}
misal
let views = viewController.view.recurrenceAllSubviews()
doğrudan, tüm alt görünümleri almak için sıra işlevini kullanın
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 }
Bir UITableViewCell'deki alt görüntülemelerin yazdırılmamasının nedeni, üst düzeydeki tüm alt görüntülerin çıktısını almanız gerekmesidir. Hücrenin alt görünümleri, görünümünüzün doğrudan alt görünümleri değildir.
UITableViewCell'in alt görünümlerini elde etmek için isKindOfClass:
, yazdırma döngünüzde hangi alt görünümlerin bir UITableViewCell'e ait olduğunu (kullanarak ) belirlemeniz ve ardından alt görünümleri arasında döngü oluşturmanız gerekir.
Düzenleme: Easy UIView Hata Ayıklama hakkındaki bu blog gönderisi potansiyel olarak yardımcı olabilir
Daha önce gönderilen cevaplardan esinlenen bir görünüm denetleyicisinin sahip olduğu tüm görüşleri listelemek için bir kategori yazdım.
@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
Bir görünüm denetleyicisi tarafından tutulan tüm görünümleri listelemek için NSLog("%@",[self listOfSubviews])
, bu yalnızca self
görünüm denetleyicisinin kendisi anlamına gelir. Etkili çıkmasa da.
Artı, NSLog(@"\n%@", [(id)self.view performSelector:@selector(recursiveDescription)]);
aynı şeyi yapmak için kullanabilirsiniz ve bence uygulamamdan daha verimli.
Basit Swift örneği:
var arrOfSub = self.view.subviews
print("Number of Subviews: \(arrOfSub.count)")
for item in arrOfSub {
print(item)
}
Süslü bir dizi numarası deneyebilirsiniz, örneğin:
[self.view.subviews makeObjectsPerformSelector: @selector(printAllChildrenOfView)];
Sadece bir satır kod. Elbette, yönteminizi printAllChildrenOfView
herhangi bir parametre almamak veya yeni bir yöntem yapmak için ayarlamanız gerekebilir .
Swift 2.0 uyumlu
Burada, genel bir görünümün tüm alt görünümlerini elde etmek için yinelemeli bir yöntem:
extension UIView {
func subviewsList() -> [UIView] {
var subviews = self.subviews
if subviews.count == 0 {
return subviews + []
}
for v in subviews {
subviews += v.listSubviewsOfView()
}
return subviews
}
}
Böylece her yeri şu şekilde arayabilirsiniz:
let view = FooController.view
let subviews = view.subviewsList()
Bu, bu cevabın yeniden yazılması :
Önce, tüm alt görünümlerini yazdırmayı düşündüğünüz nesnenin işaretçisini / referansını almalısınız. Bazen alt görünümünden erişerek o nesneyi bulmayı daha kolay bulabilirsiniz. Beğen po someSubview.superview
. Bu size şöyle bir şey verecektir:
Optional<UIView>
▿ some : <FacebookApp.WhatsNewView: 0x7f91747c71f0; frame = (30 50; 354 636); clipsToBounds = YES; layer = <CALayer: 0x6100002370e0>>
superview
0x7f91747c71f0
süpervizörün işaretçisidir.SuperView'ı yazdırmak için kesme noktaları kullanmanız gerekir.
Şimdi bu adımı yapmak için sadece 'hata ayıklama hiyerarşisini görüntüle' üzerine tıklayabilirsiniz. Kesme noktalarına gerek yok
O zaman kolayca yapabilirsin:
po [0x7f91747c71f0 recursiveDescription]
bu benim için şöyle bir şey döndürdü:
<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>>
tahmin etmiş olabileceğiniz gibi, süpervizörümün 4 alt görünümü var:
Bu benim için oldukça yeni, ancak görüşlerimin çerçevelerinde (ve metin ve tür) hata ayıklamama yardımcı oldu. Alt görünümlerimden biri ekranda görünmüyordu, bu yüzden recursiveDescription'ı kullandım ve subView'larımdan birinin genişliğinin ... olduğunu fark ettim 0
... bu yüzden kısıtlamalarını düzelttim ve alt görünüm görünüyordu.
Alternatif olarak, bir UIView Uzantısından tüm alt görünümlerin (ve iç içe geçmiş alt görünümlerin) bir dizisini döndürmek isterseniz:
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 sürümü:
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);
}
}
Alternatif olarak, kullandığım belirli bir türün tüm alt görünümlerini bulmak isterseniz:
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
Güzel bir ağaç biçiminde yazdırmak için dizini geçen işlevi çağırarak bir kategoride yaptım . Bu, James Webster tarafından gönderilen cevabın bir başka seçeneğidir .
#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++];
}
}
}
Umut ediyorum bu yardım eder :)
- (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, görünümlerin mirasını korur. uitableviewcell'in alt görünümlerini almak için aşağıdaki gibi bir şey yapmanız gerekir.
for (UIView *subView in self.view.subviews) {
if ([subView isKindOfClass:[UITableView class]]) {
for (UIView *tableSubview in subView.subviews) {
.......
}
}
}