When can I start using properties set using UIAppearance?
Asked Answered
E

5

10

I have some custom appearance properties in my view class (a descendant of UIView). I want to customize the view appearance according to these properties, but I can’t do that inside the initializer, since the values set using [[MyClass appearance] setFoo:…] aren’t in effect at that point:

@interface View : UIView
@property(strong) UIColor *someColor UI_APPEARANCE_SELECTOR;
@end

@implementation View
@synthesize someColor;

// Somewhere in other code before the initializer is called:
// [[View appearance] setSomeColor:[UIColor blackColor]];

- (id) initWithFrame: (CGRect) frame
{
    self = [super initWithFrame:frame];
    NSLog(@"%@", someColor); // nil
    return self;
}

@end

They are already set in layoutSubviews, but that’s not a good point to perform the view customizations, since some customizations may trigger layoutSubviews again, leading to an endless loop.

So, what’s a good point to perform the customizations? Or is there a way to trigger the code that applies the appearance values?

Elytron answered 24/5, 2012 at 12:21 Comment(2)
I think once the custom class has been allocated , the properties of member can always be accessed and changed as per requirement and then the object can be used with the modified information in the code.Doubletongued
Just to make sure, I am talking about the properties set through the appearance proxy (UIAppearance). These values are set somewhere later than in the initializer. If I set a breakpoint on the property setter, I can see that the values are applied from [CALayer layoutSublayers].Elytron
E
2

One possible workaround is to grab the value directly from the proxy:

- (id) initWithFrame: (CGRect) frame
{
    self = [super initWithFrame:frame];
    NSLog(@"%@", [[View appearance] someColor); // not nil
    return self;
}

Of course this kills the option to vary the appearance according to the view container and is generally ugly. Second option I found is to perform the customizations in the setter:

- (void) setSomeColor: (UIColor*) newColor
{
    someColor = newColor;
    // do whatever is needed
}

Still I’d rather have some hook that gets called after the appearance properties are set.

Elytron answered 24/5, 2012 at 14:33 Comment(1)
see my answer; the 'hook' is UIView didMoveToSuperview:, I believe.Sicard
G
1

Why not wait until

- (void)willMoveToSuperview:(UIView *)newSuperview {
    [super willMoveToSuperview:newSuperview];

    if (newSuperview) {
        ... code here ...
    }
}

if it's giving you trouble?

Gurango answered 24/5, 2012 at 12:46 Comment(1)
That was my next attempt, but the values are not set at that point either.Elytron
S
1

I believe UIAppearance properties are applied to a view when it is being added into a view hierarchy. So presumably you could access the set properties in UIView didMoveToSuperview.

Sicard answered 7/8, 2013 at 19:27 Comment(0)
M
1

Caveat: I am using Swift 2, so not sure about earlier versions of Swift / Objective-C. But I have found that didMoveToSuperview() will not work. The properties are available in layoutSubviews(), but that's not a great place to do anything like this (since it can be called more than once). The best place to access these properties in the lifeCycle of the view I have found is didMoveToWindow().

Manzanilla answered 17/12, 2015 at 16:33 Comment(0)
N
0

I would have thought that viewDidLoad would be best if it's a one-time thing. Otherwise, viewWillAppear.

EDIT:

If you want to do it in the view, and not it's controller then I would create a custom init for the view along the lines of:

-(id) initWithFrame:(CGRect) frame andAppearanceColor:(UIColor)theColor;

thereby passing the colour into the view at creation time.

Normally answered 24/5, 2012 at 13:23 Comment(4)
These are controller methods and I’d much rather handle it in the view. Besides, it’s quite probable that the values are not set yet during these calls.Elytron
Passing the color in the initializer is also not an option, since there are more appearance properties to set and the initializer is called in a place out of the controller’s… erm, control. One could say that the whole point of the appearance proxy API was to get rid of setting the values by hand all the time.Elytron
I see where you're coming from. Maybe you could create a method to set the appearance properties and call it in response to an NSNotification (sent when the appearance properties are specified)?Normally
At the time when the appearance properties are set through [[View appearance] setSomeColor:…], the instances of View don’t exist yet, so unfortunately that’s not an option either.Elytron

© 2022 - 2024 — McMap. All rights reserved.