ios objective-c cocoa-touch uicontrol

ios - ¿Puedo usar valores personalizados de UIControlState para mi propio control?



objective-c cocoa-touch (4)

Basado en la respuesta de @Nick, he implementado una versión más simple. Esta subclase expone una propiedad BOOL outlined que es similar en función a selected , highlighted y enabled .

Hacer cosas como [customButtton setImage:[UIImage imageNamed:@"MyOutlinedButton.png"] forState:UIControlStateOutlined] hace que funcione [customButtton setImage:[UIImage imageNamed:@"MyOutlinedButton.png"] forState:UIControlStateOutlined] al actualizar la propiedad outlined .

Más de estas propiedades estatales + podrían agregarse si fuera necesario.

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

¿Hay una manera de establecer un estado personalizado, no uno de los valores UIControlState existentes, para un UIControl ?

En la enumeración UIControlSate , hay 16 bits que se pueden usar para estados de control personalizados:

UIControlStateApplication = 0x00FF0000, // additional flags available for application use

El problema es que la propiedad state UIControl es de solo lectura .

Quiero establecer diferentes imágenes de fondo en mi UIButton para estados personalizados.


Me gustaría ofrecer un ligero refinamiento a esta estrategia. Vea esta pregunta de :

La anulación es Resaltada sigue cambiando UIControlState: ¿por qué?

Resulta que la implementación del state de Apple es en realidad una propiedad computada basada en las otras propiedades, se isSelected , se isHighlighted , se isEnabled , etc.

Así que en realidad no hay necesidad de una máscara de bits de estado personalizada encima de UIControlState (bueno, no es que no haya necesidad, es solo que agrega complejidad donde no es necesario).

Si quisiera ser congruente con la implementación de Apple, solo tendría que anular la propiedad del estado y verificar sus estados personalizados en el gestor.

extension UIControlState { static let myState = UIControlState(rawValue: 1 << 16) } class MyControl: UIControl { override var state: UIControlState { var state = super.state if self.isMyCustomState { state.insert(UIControlState.myState) } return state } var isMyCustomState: Bool = false }

En realidad es una manera inteligente de ir; según el enlace anterior, si anula la propiedad y no cambia el estado, obtendrá resultados inconsistentes. Hacer que el estado sea siempre una propiedad calculada garantiza la coherencia entre las propiedades que representa el state .


Puede hacer uso de los estados personalizados en una subclase de UIControl.

  • Cree una variable llamada customState en la que administrará sus estados personalizados.
  • Si necesita establecer un estado, realice sus operaciones de bandera contra esta variable y llame a [self stateWasUpdated] .
  • Reemplace la propiedad state para devolver [super state] bitwise OR''d contra su customState
  • [self stateWasUpdated] enabled , selected y highlighted para que llamen [self stateWasUpdated] . Esto le permitirá responder a cualquier cambio en el estado, no solo a los cambios en customState
  • Implementar stateWasUpdated con lógica para responder a cambios en el estado

En el encabezado:

#define kUIControlStateCustomState (1 << 16) @interface MyControl : UIControl { UIControlState customState; }

En la implementación:

@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


Swift 3 versión de la respuesta de Nick:

extension UIControlState { static let myState = UIControlState(rawValue: 1 << 16) } class CustomControl: UIControl { private var _customState: UInt = 0 override var state: UIControlState { return UIControlState(rawValue: super.state.rawValue | self._customState) } var isMyCustomState: Bool { get { return self._customState & UIControlState.myState.rawValue == UIControlState.myState.rawValue } set { if newValue == true { self._customState |= UIControlState.myState.rawValue } else { self._customState &= ~UIControlState.myState.rawValue } } } }