自定义对象的UIAppearance代理 [英] UIAppearance proxy for custom objects

查看:66
本文介绍了自定义对象的UIAppearance代理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义对象,它继承自NSObject。
这个对象执行一些事情,其中一个是创建带有一些UIKit对象的UIView(UILabel,UIButtons ecc ecc ...)。
这个对象有一些属性,如:textColor,font,backgroundColor ...,用于自定义包含的UIKit对象的外观。

I have a custom object, it inherits from NSObject. This object does "some things", one of it is creating an UIView with some UIKit objects (UILabel, UIButtons ecc ecc...). This object has some properties like: textColor, font, backgroundColor... that are used to customize the appearance of the contained UIKit objects.

我想要为这个对象的所有创建实例定制这个属性一次性,我看了UIAppearance协议。

I would like to customize this properties "one shot" for all created instances of this object, and I've looked at the UIAppearance protocol.

标准的UIKit对象已经符合UIAppearance协议,但我不想在所有UILabel或UIButtons上应用该样式。我想仅将样式应用于对象实例中包含的UILabel和UIButtons。
此外,我不能(我不想)使用appearanceWhenContainedIn:因为使用我的自定义对象的开发人员可能不知道其中包含什么类型的对象。

Standard UIKit objects already conforms to UIAppearance protocol, but I don't want to apply the style on ALL UILabels or UIButtons. I want to apply styles only to the UILabels and UIButtons contained inside my object instances. Moreover, I can't (and I don't want) use appearanceWhenContainedIn: because the developer using my custom object may not know what kind of objects are "contained" inside it.

所以,我正在研究如何使我的自定义对象符合UIAppearance协议。

So, I was looking at how to make my custom object conforms to UIAppearance protocol.

AFAIK它必须实现

AFAIK it must implement the

+ (id)appearance

方法。此方法应返回一个代理对象,您可以在其中发送所有自定义项。
但是,看一下UIKit对象的外观方法,我看到返回了一个私有对象。
类_UIAppearance的对象。

method. This method should return a proxy object where you can send all your customizations. But, looking at the appearance method of UIKit objects, I see that a private object is returned. An object of class _UIAppearance.

所以,似乎Apple没有给我一个标准的代理对象来定制我自己的,我必须创建如果从头开始。
是对还是我放松了?

So, it seems that Apple doesn't give me a standard proxy object for customizing my own, and I have to create if from scratch. Is it right or I'm loosing something?

谢谢

推荐答案

经过一些研究,我放弃使用标准的Apple对象。它暂时不存在。我已经创建了自己的代理,它非常简单(仅适用于外观:)。

After some reserach I "give up" about using a standard Apple object. It doesn't exists, for now. I've created my own proxy, it's quite simple (works only with "appearance:" by now).

让我们解释一下。
我想在NSObject子类上设置textColor的外观,我们称之为FLObject。
使FLObject符合UIAppearance协议并覆盖外观方法。
在这种方法中,你应该返回一个代理类(我创建的代理类):

Let's explain it. I want to set the appearance of "textColor" on a NSObject subclass, let's call it "FLObject". Make FLObject conforms to UIAppearance protocol and override the appearance method. In this method, you should return a proxy class (the one I created):

+ (id)appearance
{
    return [FLAppearance appearanceForClass:[self class]];
}

工作原理如何?
FLAppearance为appearanceForClass:方法传递的每个类创建一个自身的单个实例。
如果你为同一个类调用它两次,则会返回相同的实例。

How it works? FLAppearance creates a single instance of itself for each class passed by the appearanceForClass: method. If you call it two times for the same class, the same instance is returned.

然后,你可以这样做:

[[FLObject appearance] setTextColor:[UIColor redColor]]; 

FLAppearance覆盖forwardInvocation:方法,因此它接受所有发送的方法。
然后,它将所有调用放在一个数组中。
初始化FLObject时,只需调用

FLAppearance overrides the forwardInvocation: method, so it accepts all methods sent. Then, it puts all invocations in an array. When FLObject is initialized, a simple call to

[(FLAppearance *)[FLAppearance appearanceForClass:[self class]] startForwarding:self];

将开始发送调用并设置外观。
当然,这需要一些调整和错误检查,但我认为这是一个好的开始。

will start to send invocations and set the appearance. Sure, this needs some tuning and error checking, but I think it's a good start.

@interface FLAppearance ()

@property (strong, nonatomic) Class mainClass;
@property (strong, nonatomic) NSMutableArray *invocations;

@end

static NSMutableDictionary *dictionaryOfClasses = nil;

@implementation FLAppearance

// this method return the same object instance for each different class
+ (id) appearanceForClass:(Class)thisClass
{
    // create the dictionary if not exists
    // use a dispatch to avoid problems in case of concurrent calls
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (!dictionaryOfClasses)
            dictionaryOfClasses = [[NSMutableDictionary alloc]init];
    });



    if (![dictionaryOfClasses objectForKey:NSStringFromClass(thisClass)])
    {
        id thisAppearance = [[self alloc]initWithClass:thisClass];
        [dictionaryOfClasses setObject:thisAppearance forKey:NSStringFromClass(thisClass)];
        return thisAppearance;
    }
    else
        return [dictionaryOfClasses objectForKey:NSStringFromClass(thisClass)];
}

- (id)initWithClass:(Class)thisClass
{
    self = [self initPrivate];
    if (self) {
        self.mainClass = thisClass;
        self.invocations = [NSMutableArray array];
    }
    return self;
}

- (id)init
{
    [NSException exceptionWithName:@"InvalidOperation" reason:@"Cannot invoke init. Use appearanceForClass: method" userInfo:nil];
    return nil;
}

- (id)initPrivate
{
    if (self = [super init]) {

    }
    return self;
}

-(void)forwardInvocation:(NSInvocation *)anInvocation;
{
    // tell the invocation to retain arguments
    [anInvocation retainArguments];

    // add the invocation to the array
    [self.invocations addObject:anInvocation];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    return [self.mainClass instanceMethodSignatureForSelector:aSelector];
}

-(void)startForwarding:(id)sender
{
    for (NSInvocation *invocation in self.invocations) {
        [invocation setTarget:sender];
        [invocation invoke];
    }
}

这篇关于自定义对象的UIAppearance代理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆