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 sucustomState
-
[self stateWasUpdated]
enabled
,selected
yhighlighted
para que llamen[self stateWasUpdated]
. Esto le permitirá responder a cualquier cambio en el estado, no solo a los cambios encustomState
- 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
}
}
}
}