【问题标题】:Can I use custom values of UIControlState for my own control?我可以将 UIControlState 的自定义值用于我自己的控件吗?
【发布时间】:2011-02-20 19:30:22
【问题描述】:

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

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

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

问题是UIControlstate 属性是只读的

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

【问题讨论】:

    标签: ios objective-c cocoa-touch uicontrol


    【解决方案1】:

    我想稍微改进一下这个策略。请参阅此 stackoverflow 问题:

    Overriding isHighlighted still changes UIControlState - why?

    事实证明,Apple 的 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 表示的属性之间的一致性。

    【讨论】:

    • 我认为将自己作为一个额外的位注入现有的state 位掩码是没有意义的。上面写着“脆弱”。导出一种完全不同的状态表达方式是一回事,但假设 Apple 自己的 state 的第 16 位是并且永远对你的 hack 是免费的是错误的。
    • 我同意,在一定程度上,所以我投了赞成票。但是,我认为说错有点过分了。我们都根据假设编写代码,我认为这很可能是可以的(或者至少以后很容易通过简单的位移进行更改)。 hack有效,它为我节省了很多悲伤。例如,当根据状态分配自定义颜色时,它可以让您免于创建巨大的 if/else 厄运金字塔。即if (isSelected &amp;&amp; isHighlighted) &amp;&amp; (!isEnabled || isMyCustomState)。我会很感激任何与管理这种情况的替代策略的链接。
    • 我会制作自己的选项集。我没有看到此页面上的任何策略这样做。
    【解决方案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
                }
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

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

      当您更新 outlined 属性时,执行 [customButtton setImage:[UIImage imageNamed:@"MyOutlinedButton.png"] forState:UIControlStateOutlined] 之类的操作会使其自动工作。

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


      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
      

      【讨论】:

        【解决方案4】:

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

        • 创建一个名为customState 的变量,您将在其中管理您的自定义状态。
        • 如果您需要设置状态,请对该变量执行标志操作,并调用[self stateWasUpdated]
        • 覆盖state 属性以返回[super state] 对您的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
        

        【讨论】:

        • UIControlState 枚举指定应用程序控件状态使用掩码 0x00FF0000。这意味着 1
        • 还要注意;如果您计划使用自定义状态来控制 UIButton 中的自定义资源,例如标题、背景图像、图像、titleShadow 或属性标题。更改自定义状态后,您必须调用 setNeedsLayout。否则按钮只会在再次点击后更新其外观。
        • 绝对不要使用 1
        • 另一个问题是一个很好的支持性解释:Whats the use of UIControlState “application” of UIButton?
        猜你喜欢
        • 2023-02-15
        • 1970-01-01
        • 2011-06-23
        • 2012-02-27
        • 2012-07-31
        • 2016-01-26
        • 2011-04-04
        • 2018-10-17
        • 2022-01-04
        相关资源
        最近更新 更多