如何识别未嵌入控件的UILabel

时间:2013-10-01 13:59:43

标签: uilabel ios7

我在我的应用程序中添加了一个功能,用户可以在其中更改颜色方案,因此我需要更改屏幕上标签的颜色。我通过循环UIView来做到这一点,如果我找到一个标签,我会改变颜色。

这很好用,但我不想更改属于segmentedControls或出现在导航栏中的标签的颜色。

我的问题是,如何判断UILabel是否实际嵌入控件中,以便我可以跳过它?此代码对我不起作用:

      if([v isKindOfClass:[UILabel class]] && ![v.superview isKindOfClass:[UISegmentedControl class]] )
        {
            UILabel *label = (UILabel *)v;
            [label setTextColor:[UIColor blackColor]];
        }

2 个答案:

答案 0 :(得分:3)

我创建了一个UISegmentedControl并在调试器中停止,然后在其上调用recursiveDescription方法(recursiveDescription是一个私有方法,但它可以在iOS Debugging Magic中使用)。它揭示了UISegmentedControl中的标签实际上是UISegmentLabel s,根据你的代码将它们变为黑色必须是UILabel的子类。你的代码不起作用的原因是他们的直接超级视图显然是UISegment,一个用于实现UISegmentedControl的私有类。

<UISegmentedControl: 0x8e30130; frame = (99 114; 123 29); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x8e30250>>
   | <UISegment: 0x8e304a0; frame = (62 0; 61 29); opaque = NO; layer = <CALayer: 0x8e305f0>>
   |    | <UISegmentLabel: 0x8e309d0; frame = (7 6; 47 16); text = 'Second'; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8e30ae0>>
   |    | <UIImageView: 0x8e32510; frame = (61 0; 1 1); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; tag = -1030; layer = <CALayer: 0x8e325e0>>
   | <UISegment: 0x8e34bf0; frame = (0 0; 61 29); opaque = NO; layer = <CALayer: 0x8e34410>>
   |    | <UISegmentLabel: 0x8e34d30; frame = (17 6; 27 16); text = 'First'; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8e34e60>>
   |    | <UIImageView: 0x8e149e0; frame = (61 0; 1 1); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; tag = -1030; layer = <CALayer: 0x8e0ba60>>

您可以选择几条道路:

  1. 您可以检查属于UISegment类的超级视图,不建议这样做,因为它依赖于不稳定的私有API
  2. 如果视图属于类UISegmentLabel,则无法更改颜色,因为它依赖于不稳定的私有API而不推荐使用
  3. 您可以检查超级视图链的整个(或至少几个部分)。我有一个Cocoapod MTRecursiveKVC,它允许你编写代码来执行此操作:

    // Recursively gets the superview property until it is nil 
    NSArray *superviewChain = [view recursiveValueForKey:@"superview"]; 
    // Now iterate through the array, checking for a view being a UISegmentedControl
    

    只要你只是遍历UILabel的超级视图,你应该在性能方面做得很好,但请注意,手动输入你自己的解决方案会更快(我的方法更通用,因为它使用KVC,但是这会增加开销与纯方法调用的关系,并且一旦找到UISegmentedControl超级视图,你的内容也可能会突破循环。

  4. 推荐方法)您可以撤消循环方法。如果您从应用程序的UIWindow(或足够高的视图)开始,您可以超越层次结构,并且只有在没有UISegmentedControl时才进一步追求分支。如果它作为UIView上的类别实现,那么这就是它的样子(我实际上没有对此进行测试......)

    - (void)changeColorOfSubviews
    {
        if ([self isKindOfClass:[UILabel class]]) { /* change color */ }
    
        for (UIView *subview in self.subviews) {
            if (![subview isKindOfClass:[UISegmentedControl class]]) {
                [subview changeColorOfSubviews];
            }
        }
    }
    
  5. #4是我推荐的方法,因为我发现递归非常适合UIViews的树结构,因为我已经为你提供了代码:)

    这是一个说明方法编号4的图表,其中遵循黑色路径,红色路径是我们停止跟随分支的地方,灰色路径永远不会被评估(因为我们到达之前达到了红色):

    enter image description here

答案 1 :(得分:1)

为了完整性,这是我的最终代码。再次感谢MaxGabriel的回答。

新文件,Objective-C类别(UIView)

//  UIView+UIMods.m
//  ATB iPad
//
//  Created by A Smith on 10/4/13.
//
//

#import "UIView+UIMods.h"
#import "Colors.h"

    - (void)changeColorOfLabels:(int)hiContrast
{
    if ([self isKindOfClass:[UILabel class]]) {     // if we are currently in a UILabel view
        /* change color */
        UILabel *label = (UILabel *)self;
        NSString *ver = [UIDevice currentDevice].systemVersion;
        int majorVer = [ver integerValue];

        if( hiContrast ){

            if( ![label.superview isKindOfClass:[UIButton class]]  ){

                [label setTextColor:[UIColor blackColor]];
                [label setBackgroundColor:[UIColor whiteColor]];

            } else {

                if( majorVer >= 7 ){
                    [label setTextColor:[Colors iOS7ButtonColor]];
                }

            }

        } else {

            if(  ![label.superview isKindOfClass:[UIButton class]]  ){
                [label setTextColor:[UIColor whiteColor]];
                [label setBackgroundColor:[Colors darkBkgColor]];
            } else {
                if( majorVer >= 7 ){
                    [label setTextColor:[Colors iOS7ButtonColor]];
                }
            }

        }
    }

    for (UIView *subview in self.subviews) {

        if (![subview isKindOfClass:[UISegmentedControl class]] && ![subview.superview isKindOfClass:[UITextField class]]  ) {

            [subview changeColorOfLabels:hiContrast];       // only recurse down if it's the type of view we want to modify the label for
        }
    }
}

和.h文件:

@interface UIView (UIMods){

}

- (void)changeColorOfLabels:(int)hiContrast;

@end

就像这样,

UIView *aView = theView.view;
[aView changeColorOfLabels:globalHighContrast];

我看到一个很好的建议是将.h文件导入添加到.pch文件中,以便在任何地方都可以使用此添加内容,您不必在本地导入任何内容。

#ifdef __OBJC__
    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    #import "UIView+UIMods.h"
#endif