Как я могу прокручивать все подпункты UIView, их подзонов и их подзонов?
Как я могу перебирать все подпункты UIView, а также их подзоны и их подпрограммы
Ответ 1
Использовать рекурсию:
// UIView+HierarchyLogging.h
@interface UIView (ViewHierarchyLogging)
- (void)logViewHierarchy;
@end
// UIView+HierarchyLogging.m
@implementation UIView (ViewHierarchyLogging)
- (void)logViewHierarchy
{
NSLog(@"%@", self);
for (UIView *subview in self.subviews)
{
[subview logViewHierarchy];
}
}
@end
// In your implementation
[myView logViewHierarchy];
Ответ 2
Ну вот мое решение, использующее рекурсию и оболочку (категорию/расширение) для класса UIView.
// UIView+viewRecursion.h
@interface UIView (viewRecursion)
- (NSMutableArray*) allSubViews;
@end
// UIView+viewRecursion.m
@implementation UIView (viewRecursion)
- (NSMutableArray*)allSubViews
{
NSMutableArray *arr=[[[NSMutableArray alloc] init] autorelease];
[arr addObject:self];
for (UIView *subview in self.subviews)
{
[arr addObjectsFromArray:(NSArray*)[subview allSubViews]];
}
return arr;
}
@end
Использование: теперь вам нужно перебирать все подпункты и манипулировать ими по мере необходимости.
//disable all text fields
for(UIView *v in [self.view allSubViews])
{
if([v isKindOfClass:[UITextField class]])
{
((UITextField*)v).enabled=NO;
}
}
Ответ 3
Просто нашел интересный способ сделать это через отладчик:
http://idevrecipes.com/2011/02/10/exploring-iphone-view-hierarchies/
ссылается на Apple Technote:
http://developer.apple.com/library/ios/#technotes/tn2010/tn2239.html#SECUIKIT
Просто убедитесь, что ваш отладчик приостановлен (либо установите точку прерывания, чтобы приостановить его вручную), и вы можете запросить recursiveDescription
.
Ответ 4
Я отмечаю все, когда он создается. Тогда легко найти любое под просмотр.
view = [aView viewWithTag:tag];
Ответ 5
Решение в Swift 3, которое дает все subviews
без включения самого представления:
extension UIView {
var allSubViews : [UIView] {
var array = [self.subviews].flatMap {$0}
array.forEach { array.append(contentsOf: $0.allSubViews) }
return array
}
}
Ответ 6
С помощью Оле Бегеманна. Я добавил несколько строк, чтобы включить в него концепцию блока.
UIView + HierarchyLogging.h
typedef void (^ViewActionBlock_t)(UIView *);
@interface UIView (UIView_HierarchyLogging)
- (void)logViewHierarchy: (ViewActionBlock_t)viewAction;
@end
UIView + HierarchyLogging.m
@implementation UIView (UIView_HierarchyLogging)
- (void)logViewHierarchy: (ViewActionBlock_t)viewAction {
//view action block - freedom to the caller
viewAction(self);
for (UIView *subview in self.subviews) {
[subview logViewHierarchy:viewAction];
}
}
@end
Использование категории иерархии в вашем ViewController. Теперь у вас есть свобода в том, что вам нужно делать.
void (^ViewActionBlock)(UIView *) = ^(UIView *view) {
if ([view isKindOfClass:[UIButton class]]) {
NSLog(@"%@", view);
}
};
[self.view logViewHierarchy: ViewActionBlock];
Ответ 7
Вот рекурсивный код: -
for (UIView *subViews in yourView.subviews) {
[self removSubviews:subViews];
}
-(void)removSubviews:(UIView *)subView
{
if (subView.subviews.count>0) {
for (UIView *subViews in subView.subviews) {
[self removSubviews:subViews];
}
}
else
{
NSLog(@"%i",subView.subviews.count);
[subView removeFromSuperview];
}
}
Ответ 8
Кстати, я сделал проект с открытым исходным кодом, чтобы помочь в решении такого рода задач. Это очень просто и использует Objective-C 2.0 блоки для выполнения кода во всех представлениях в иерархии.
https://github.com/egold/UIViewRecursion
Пример:
-(void)makeAllSubviewsGreen
{
[self.view runBlockOnAllSubviews:^(UIView *view) {
view.backgroundColor = [UIColor greenColor];
}];
}
Ответ 9
Не нужно создавать новую функцию. Просто делайте это при отладке с помощью Xcode.
Установите контрольную точку в контроллере представления и сделайте паузу приложения на этой точке останова.
Щелкните правой кнопкой мыши пустую область и нажмите "Добавить выражение..." в окне просмотра Xcode.
Введите эту строку:
(NSString*)[self->_view recursiveDescription]
Если значение слишком велико, щелкните его правой кнопкой мыши и выберите "Печать описания...". В окне консоли вы увидите все subviews self.view. Измените self → _ view на что-то еще, если вы не хотите видеть subviews self.view.
Готово! Нет gdb!
Ответ 10
Ниже приведен вариант ответа Ole Begemann, который добавляет отступы для иллюстрации иерархии:
// UIView+HierarchyLogging.h
@interface UIView (ViewHierarchyLogging)
- (void)logViewHierarchy:(NSString *)whiteSpaces;
@end
// UIView+HierarchyLogging.m
@implementation UIView (ViewHierarchyLogging)
- (void)logViewHierarchy:(NSString *)whiteSpaces {
if (whiteSpaces == nil) {
whiteSpaces = [NSString string];
}
NSLog(@"%@%@", whiteSpaces, self);
NSString *adjustedWhiteSpaces = [whiteSpaces stringByAppendingFormat:@" "];
for (UIView *subview in self.subviews) {
[subview logViewHierarchy:adjustedWhiteSpaces];
}
}
@end
Ответ 11
Вот пример с фактической функцией циклизации и разлома представления.
typedef void(^ViewBlock)(UIView* view, BOOL* stop);
@interface UIView (ViewExtensions)
-(void) loopViewHierarchy:(ViewBlock) block;
@end
@implementation UIView (ViewExtensions)
-(void) loopViewHierarchy:(ViewBlock) block {
BOOL stop = NO;
if (block) {
block(self, &stop);
}
if (!stop) {
for (UIView* subview in self.subviews) {
[subview loopViewHierarchy:block];
}
}
}
@end
Пример вызова:
[mainView loopViewHierarchy:^(UIView* view, BOOL* stop) {
if ([view isKindOfClass:[UIButton class]]) {
/// use the view
*stop = YES;
}
}];
Ответ 12
Код, отправленный в этом ответе, охватывает все окна и все представления и все их подпрограммы. Он использовался для сброса распечатки иерархии представлений в NSLog, но вы можете использовать ее в качестве основы для любого обхода иерархии представлений. Он использует рекурсивную функцию C, чтобы пересечь дерево представлений.
Ответ 13
Я написал категорию некоторое время назад для отладки некоторых видов.
IIRC, опубликованный код - тот, который работал. Если нет, он укажет вам в правильном направлении. Использовать на свой страх и риск и т.д.
Ответ 14
Здесь также отображается уровень иерархии
@implementation UIView (ViewHierarchyLogging)
- (void)logViewHierarchy:(int)level
{
NSLog(@"%d - %@", level, self);
for (UIView *subview in self.subviews)
{
[subview logViewHierarchy:(level+1)];
}
}
@end
Ответ 15
Желаю, чтобы я сначала нашел эту страницу, но если (по какой-то причине) вы хотите сделать это нерекурсивно, а не в категории, и с более строки кода
Ответ 16
Я думаю, что все ответы, использующие рекурсию (за исключением опции отладчика), используют категории. Если вам не нужна/нужна категория, вы можете просто использовать метод экземпляра. Например, если вам нужно получить массив всех меток в иерархии представлений, вы можете сделать это.
@interface MyViewController ()
@property (nonatomic, retain) NSMutableArray* labelsArray;
@end
@implementation MyViewController
- (void)recursiveFindLabelsInView:(UIView*)inView
{
for (UIView *view in inView.subviews)
{
if([view isKindOfClass:[UILabel class]])
[self.labelsArray addObject: view];
else
[self recursiveFindLabelsInView:view];
}
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.labelsArray = [[NSMutableArray alloc] init];
[self recursiveFindLabelsInView:self.view];
for (UILabel *lbl in self.labelsArray)
{
//Do something with labels
}
}
Ответ 17
В приведенном ниже методе создается один или несколько изменяемых массивов, а затем проходит через подвыборы входного представления. При этом он добавляет начальное подчинение, а затем запросы относительно того, есть ли какие-либо подзадачи этого подвью. Если это правда, он снова называет себя. Он делает это до тех пор, пока не будут добавлены все представления иерархии.
-(NSArray *)allSubs:(UIView *)view {
NSMutableArray * ma = [NSMutableArray new];
for (UIView * sub in view.subviews){
[ma addObject:sub];
if (sub.subviews){
[ma addObjectsFromArray:[self allSubs:sub]];
}
}
return ma;
}
Вызов с использованием:
NSArray * subviews = [self allSubs:someView];