28

有没有办法为 a 设置自定义状态(不是现有UIControlState值之一) UIControl

UIControlSate枚举中,有 16 位可用于自定义控件状态:

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

问题是它UIControlstate属性是只读的。

我想UIButton为自定义状态设置不同的背景图像。

4

4 回答 4

36

您可以在 UIControl 的子类中使用自定义状态。

  • 创建一个名为的变量customState,您将在其中管理自定义状态。
  • 如果您需要设置状态,请针对此变量执行标志操作,然后调用[self stateWasUpdated].
  • 覆盖该state属性以[super state]按位或对您的customState
  • 覆盖enabled,selectedhighlightedsetter 以便他们调用[self stateWasUpdated]. 这将允许您响应状态的任何更改,而不仅仅是更改customState
  • 用逻辑实现stateWasUpdated以响应状态的变化

在标题中:

#define kUIControlStateCustomState (1 << 16)

@interface MyControl : UIControl {
    UIControlState customState;
}

在实施中:

@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
于 2011-01-18T14:25:52.093 回答
6

基于@Nick 的回答,我实现了一个更简单的版本。该子类公开了一个与、和BOOL outlined功能相似的属性。selectedhighlightedenabled

当你更新属性时,做一些事情[customButtton setImage:[UIImage imageNamed:@"MyOutlinedButton.png"] forState:UIControlStateOutlined]让它自动工作。outlined

如果需要,可以添加更多这些状态 + 属性。


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
于 2014-07-15T12:39:25.777 回答
3

我想对这个策略做一点改进。看到这个stackoverflow问题:

覆盖 isHighlighted 仍然会改变 UIControlState - 为什么?

事实证明,Apple 的state实现实际上是基于其他属性 、 、 等的计算isSelected属性。isHighlightedisEnabled

所以实际上不需要在 UIControlState 之上自定义状态位掩码(好吧,并不是没有必要,只是它在需要/不应该的地方增加了复杂性)。

如果您想与 Apple 的实现保持一致,您只需覆盖 state 属性并在 getter 中检查您的自定义状态。

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
 }

这实际上是一个聪明的方法。根据上面的链接,如果您覆盖该属性并且不更改状态,您将得到不一致的结果。使状态始终成为计算属性可确保state表示的属性之间的一致性。

于 2018-08-13T18:40:51.607 回答
2

尼克回答的 Swift 3 版本:

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
            }
        }
    }
}
于 2017-06-12T00:33:14.483 回答