我可以使用UIControlState的自定义值来控制自己吗?

时间:2010-05-18 09:40:29

标签: ios objective-c cocoa-touch uicontrol

有没有办法为UIControlState设置自定义状态 - 而不是现有的UIControl值之一?

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

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

问题是UIControl的{​​{1}}属性只读

我想为我的state设置不同的背景图片以用于自定义状态。

4 个答案:

答案 0 :(得分:36)

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

  • 创建一个名为customState的变量,您可以在其中管理自定义状态。
  • 如果需要设置状态,请对此变量执行标记操作,然后调用[self stateWasUpdated]
  • 覆盖state媒体资源,以[super state]
  • 的形式按位ORUD返回customState
  • 覆盖enabledselectedhighlighted设置者,以便他们致电[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

答案 1 :(得分:5)

根据@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

答案 2 :(得分:2)

斯威夫特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
            }
        }
    }
}

答案 3 :(得分:2)

我想对该策略进行一些细化。请参阅以下stackoverflow问题:

Overriding isHighlighted still changes UIControlState - why?

事实证明,苹果公司的state实现实际上是基于其他属性isSelectedisHighlightedisEnabled等的计算属性。

因此,实际上在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所表示的属性之间的一致性。