Is there a way to set a custom states -- not one of the existing UIControlState
values -- for a UIControl
?
In the UIControlSate
enum, there are 16 bits that can be used for custom control states:
UIControlStateApplication = 0x00FF0000, // additional flags available for application use
The problem is that UIControl
's state
property is readonly.
I want to set different background images to my UIButton
for custom states.
UIControlState() is an "empty" control state with some undocumented default value. It just so happens that both of these are backed with a raw value of 0 . So it seems that both represent the "normal" state. But it is bad practice to rely on this. The defaults could change.
Overview. A control can have more than one state at a time. Controls can be configured differently based on their state. For example, a UIButton object can be configured to display one image when it is in its normal state and a different image when it is highlighted.
You can make use of the custom states in a subclass of UIControl.
customState
in which you will manage your custom states. [self stateWasUpdated]
. state
property to return [super state]
bitwise OR'd against your customState
enabled
, selected
and highlighted
setters so that they call [self stateWasUpdated]
. This will allow you to respond to any changes in state, not just changes to customState
stateWasUpdated
with logic to respond to changes in stateIn the header:
#define kUIControlStateCustomState (1 << 16) @interface MyControl : UIControl { UIControlState customState; }
In the implementation:
@implementation MyControl -(void)setCustomState { customState |= kUIControlStateCustomState; [self stateWasUpdated]; } -(void)unsetCustomState { customState &= ~kUIControlStateCustomState; [self stateWasUpdated]; } - (UIControlState)state { return [super state] | customState; } - (void)setSelected:(BOOL)newSelected { [super setSelected:newSelected]; [self stateWasUpdated]; } - (void)setHighlighted:(BOOL)newHighlighted { [super setHighlighted:newHighlighted]; [self stateWasUpdated]; } - (void)setEnabled:(BOOL)newEnabled { [super setEnabled:newEnabled]; [self stateWasUpdated]; } - (void)stateWasUpdated { // Add your custom code here to respond to the change in state } @end
Based on @Nick answer I have implemented a simpler version. This subclass exposes a BOOL outlined
property that is similar in function to selected
, highlighted
and enabled
.
Doing things like [customButtton setImage:[UIImage imageNamed:@"MyOutlinedButton.png"] forState:UIControlStateOutlined]
makes it automagically work when you update the outlined
property.
More of these state + property could be added if needed.
UICustomButton.h
extern const UIControlState UIControlStateOutlined; @interface UICustomButton : UIButton @property (nonatomic) BOOL outlined; @end
UICustomButton.m
const UIControlState UIControlStateOutlined = (1 << 16); @interface OEButton () @property UIControlState customState; @end @implementation OEButton - (void)setOutlined:(BOOL)outlined { if (outlined) { self.customState |= UIControlStateOutlined; } else { self.customState &= ~UIControlStateOutlined; } [self stateWasUpdated]; } - (BOOL)outlined { return ( self.customState & UIControlStateOutlined ) == UIControlStateOutlined; } - (UIControlState)state { return [super state] | self.customState; } - (void)stateWasUpdated { [self setNeedsLayout]; } // These are only needed if you have additional code on -(void)stateWasUpdated // - (void)setSelected:(BOOL)newSelected // { // [super setSelected:newSelected]; // [self stateWasUpdated]; // } // // - (void)setHighlighted:(BOOL)newHighlighted // { // [super setHighlighted:newHighlighted]; // [self stateWasUpdated]; // } // // - (void)setEnabled:(BOOL)newEnabled // { // [super setEnabled:newEnabled]; // [self stateWasUpdated]; // } @end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With