为 UIButton isHighlighted 属性设置 Observable

Posted

技术标签:

【中文标题】为 UIButton isHighlighted 属性设置 Observable【英文标题】:Make Observable for UIButton isHighlighted property 【发布时间】:2018-02-02 22:18:26 【问题描述】:

我正在尝试为我的 UIButton 创建 isHighlighted Observable,以便在每次 UIButton 的 isHiglighted 发生更改时发送序列。我写过这样的东西

extension Reactive where Base: UIButton 

    var isHighlighted: Observable<Bool> 

        let property = self.base.rx.controlProperty(editingEvents: .allTouchEvents,
                                                    getter:  _ in self.base.isHighlighted ,
                                                    setter:  (_, _) in )
        return property
            .distinctUntilChanged()
            .asObservable()
    

问题是,它不适用于.touchUpInside。如果我将手指拖到 UIButton 外然后回来,它可以正常工作,但不适用于点击操作。我认为在.touchUpInside 之后它仍然会在很短的时间内突出显示。

【问题讨论】:

我希望找到专门解决此问题的 Apple 文档,但失败了。我找到了将按钮状态设置为highlighted - “例如,当用户点击带有标题的按钮时,该按钮将移动到突出显示状态。” - 但不是设置它的原因。 ..default?但它是有道理的(至少对我来说)直到其他东西收到“焦点”(使用 MSFT 术语)操作系统可能被设计为将“焦点”保持在按钮上。因此,移除高亮状态的“延迟”。 @dfd 您还有其他想法如何为 isHighlighted UIButton 属性创建 Observable 吗?没有子类化 UIButton 我不使用 [rx-swift],但你能否创建一个简单的扩展 UIButton 并覆盖 isHightlighted,在 didSet 中做你需要的事情。我刚试过这个,没有错误。 【参考方案1】:

感谢@iWheelBuy 我创建了没有 RxOptional 的代码,我部分基于您的回答,所以谢谢!这是工作代码:

extension Reactive where Base: UIButton 
    var isHighlighted: Observable<Bool> 
        let anyObservable = self.base.rx.methodInvoked(#selector(setter: self.base.isHighlighted))

        let boolObservable = anyObservable
            .flatMap  Observable.from(optional: $0.first as? Bool) 
            .startWith(self.base.isHighlighted)
            .distinctUntilChanged()
            .share()

        return boolObservable
    

【讨论】:

不错!我会选择 methodInvoked 作为默认实现,而不是 sentMessage。但这取决于你? 你说得对,应该在方法调用后调用谢谢!【参考方案2】:

我想我有一个解决办法。它可以简化,但我只是复制粘贴我拥有的完整解决方案。

public extension Reactive where Base: UIButton 

    public func isHighlighted() -> Observable<Bool> 
        let selector = #selector(setter: UIButton.isHighlighted)
        let value: ([Any]) -> Bool? =  $0.first(where:  $0 is Bool ) as? Bool 
        return base
            .observable(selector: selector, value: value)
            .filterNil()
            .startWith(base.isHighlighted)
            .distinctUntilChanged()
            .share(replay: 1, scope: .whileConnected)
    

另外,让它发挥作用。你需要RxOptional 和一些额外的代码:

public enum InvocationTime: Int 

    case afterMessageIsInvoked
    case beforeMessageIsInvoked

public extension NSObject 

    public func observable<T>(selector: Selector, value: @escaping ([Any]) -> T, when: InvocationTime = .afterMessageIsInvoked) -> Observable<T> 
        let observable: Observable<[Any]> = 
            switch when 
            case .afterMessageIsInvoked:
                return rx.methodInvoked(selector)
            case .beforeMessageIsInvoked:
                return rx.sentMessage(selector)
            
        ()
        return observable
            .map( value($0) )
            .share(replay: 1, scope: .whileConnected)
    

希望对你有帮助(^

【讨论】:

以上是关于为 UIButton isHighlighted 属性设置 Observable的主要内容,如果未能解决你的问题,请参考以下文章

如何在自定义 UIButton 中实现 .isHighlighted 动画?

单击时如何防止按钮动画

Swift中的Objective C Setter覆盖

通过在多个按钮上滑动手指来选择多个按钮

C# WPF - 组合框

将 PropertyChangedCallback 添加到基类的只读依赖属性