ios - 自定义按钮view : detect touch down/up, 快速回退拖拽到UIScrollView

标签 ios swift

很抱歉,如果这个问题已经被问过/回答过。

我正在尝试创建一个 CustomButton (UIView) 来检测向下和向上触摸(以自定义背景颜色、文本颜色等的变化)。

我试过 touchesBegan 但它的 react 太慢了。

我已经尝试过 UILongPressGestureRecognizer 但它不会回退到在下面拖动 UIScrollView。我的意思是:在按钮上拖动时,它不会拖动 ScrollView 。

到目前为止,这是我的解决方案,使用 UILongPressGestureRecognizer,想法来自 here .

拜托,你能想到比我更好的解决方案吗?谢谢!

/** View that can be pressed like a button */

import UIKit

class ButtonView : UIView, UIGestureRecognizerDelegate {

    static let NoChange = { (btn:ButtonView) in }

    var enabled = true

    /* Called when the view goes to normal state (set desired appearance) */
    var onNormal = NoChange
    /* Called when the view goes to pressed state (set desired appearance) */
    var onPressed = NoChange
    /* Called when the view is released (perform desired action) */
    var action = {}


    override init(frame: CGRect)
    {
        super.init(frame: frame)

        let recognizer = UILongPressGestureRecognizer(target: self, action: #selector(touched))
        recognizer.delegate = self
        recognizer.minimumPressDuration = 0.0
        addGestureRecognizer(recognizer)
        userInteractionEnabled = true
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        onNormal(self)
    }

    func touched(sender: UILongPressGestureRecognizer)
    {
        guard enabled else { return }

        print("Current state: \(sender.state.rawValue)")

        if sender.state == .Began {
            onPressed(self)
        } else if sender.state == .Ended {
            onNormal(self)
            action()
        } else if sender.state == .Changed {
            onNormal(self)
            // This cancels recognizer when dragging
            // TODO: but doesn't drag scroll view
            sender.enabled = false
            sender.enabled = true
        }
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

用法:

    let button = ButtonView()
    // add some views to the ButtonView, e.g. add a label
    button.onNormal = { $0.backgroundColor = normalColor }
    button.onPressed = { $0.backgroundColor = pressedColor }
    button.action = { doSomethingWhenButtonIsClicked() }

最佳答案

UIControl 的另一种解决方案。 react 较慢但也不算太差,你可以在下面拖一个UIScrollView

/** 
 * View that can be pressed like a button.
 * 
 * Note that, since UIView has userInteractionEnabled = true by default,
 * you should disable it for UIView layers that you put insde this ButtonView.
 * Otherwise the ButtonView will not receive the touch events.
 */

// See: http://stackoverflow.com/q/40726283/custom-button-view

import UIKit

class ButtonView : UIControl {

    static let NoChange = { (btn:ButtonView) in }

    /* Called when the view goes to normal state (set desired appearance) */
    var onNormal = NoChange
    /* Called when the view goes to pressed state (set desired appearance) */
    var onPressed = NoChange
    /* Called when the view goes to disabled state, i.e. enabled = false (set desired appearance) */
    var onDisabled = NoChange
    /* Called when the view is released (perform desired action) */
    var action = {}


    override init(frame: CGRect)
    {
        super.init(frame: frame)

        self.addTarget(self, action: #selector(pressed), forControlEvents: .TouchDown)
        self.addTarget(self, action: #selector(clicked), forControlEvents: .TouchUpInside)
        self.addTarget(self, action: #selector(cancelled), forControlEvents: [.TouchCancel, .TouchDragExit, .TouchUpOutside])

        userInteractionEnabled = true // this is the default!
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        updateBaseStyle()
    }

    func pressed() {
        onPressed(self)
    }

    func clicked() {
        onNormal(self)
        action()
    }

    func cancelled() {
        onNormal(self)
    }

    override var enabled: Bool {
        willSet(e) {
            super.enabled = e
            updateBaseStyle()
        }
    }

    func updateBaseStyle() {
        if self.enabled {
            onNormal(self)
        } else {
            onDisabled(self)
        }
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

用法类似(我只是加了onDisable):

let button = ButtonView()
// add some views to the ButtonView, e.g. add a label
// note child views should have userInteractionEnabled = false
button.onNormal = { $0.backgroundColor = normalColor }
button.onPressed = { $0.backgroundColor = pressedColor }
button.onDisabled = { $0.backgroundColor = disabledColor }
button.action = { callToAction() }

关于ios - 自定义按钮view : detect touch down/up, 快速回退拖拽到UIScrollView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40726283/

相关文章:

iOS 调试与发布框架

ios - 我已导入 AVFoundation 并将音频添加到我的应用程序中,但如果应用程序进入后台模式,音频不会停止

ios - 我如何调用 'didselectitematindexpatch' 中的单元格类结果页面

ios - NSPredicate完全匹配

ios - 什么会导致 iOS 通用链接停止工作?

ios - 从解析错误中删除信息

ios - Xcode 8.3/Xcode 9.0 刷新配置文件设备

swift - PdfKit 注释突出显示并保存 IOS 11

ios - 如何使用 Storyboard为不同的 iPhone 屏幕尺寸设置不同的字体大小?

ios - 具有单一数据库和单一登录的多个 iOS 应用程序