1

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

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

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

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

2 回答 2

3

我制作了一个 UISegmentedControl 并在调试器中停止,然后recursiveDescription在其上调用该方法(recursiveDescription是一个私有方法,但它可以在iOS Debugging Magic中使用)。它显示 UISegmentedControl 中的标签实际上是UISegmentLabels,根据您将它们变为黑色的代码,它必须是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. 您可以检查 superview 是否属于 class 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
    

    只要您只迭代UILabels 的超级视图,就性能而言应该没问题,但请注意,手动处理您自己的解决方案会更快(我的方法更通用,因为它使用 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];
            }
        }
    }
    

#4 是我推荐的方法,因为我发现递归非常自然地适合 的树结构UIViews,并且因为我已经给了你它的代码:)

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

在此处输入图像描述

于 2013-10-02T06:04:49.900 回答
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
于 2013-10-04T14:01:54.880 回答