UILongPressGestureRecognizer中断tableView滚动

时间:2017-11-29 15:58:13

标签: ios swift uilabel uitapgesturerecognizer

我创建了一个包含UILongPressGestureRecognizer的自定义Label类,我在TableViewController中的tableview单元格中调用它。长按手势识别器工作(属性sting中的两个可点击区域),但如果滚动手势在我的CustomLabel的UILongPressGestureRecognizer区域之一开始,则包含标签的tableView不再滚动(平移)。我已尝试"M24"以及下面的各种回复,但无济于事。任何建议将不胜感激。我花了一个星期来解决这个问题。我的代码如下。

这是CustomLabel类:

cancelsTouchesInView = false

这是cellClass:

class CustomLabel: UILabel {

    let layoutManager = NSLayoutManager()
    let textContainer = NSTextContainer(size: CGSize.zero)
    var textStorage = NSTextStorage() {
        didSet {
            textStorage.addLayoutManager(layoutManager)
        }
    }

    var onCharacterTapped: ((_ label: UILabel, _ characterIndex: Int, _ state: Bool) -> Void)?

    let tapGesture = UILongPressGestureRecognizer()

    override var attributedText: NSAttributedString? {
        didSet {
            if let attributedText = attributedText {

                if attributedText.string != textStorage.string {

                textStorage = NSTextStorage(attributedString: attributedText)

                DispatchQueue.main.async {

                    let characterDelay = TimeInterval(0.01 + Float(arc4random()) /  Float(UInt32.max)) / 100

                    for (index, char) in attributedText.string.characters.enumerated() {

                        DispatchQueue.main.asyncAfter(deadline: .now() + characterDelay * Double(index)) {
                            print("character ch is: \(char) at index: \(index)")
                            super.attributedText = attributedText.attributedSubstring(from: NSRange(location: 0, length: index+1))
                        }
                    }
                }
                }

            } else {
                textStorage = NSTextStorage()
            }
        }
    }

    override var lineBreakMode: NSLineBreakMode {
        didSet {
            textContainer.lineBreakMode = lineBreakMode
        }
    }

    override var numberOfLines: Int {
        didSet {
            textContainer.maximumNumberOfLines = numberOfLines
        }
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setUp()
    }

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

    func setUp() {
        isUserInteractionEnabled = true
        layoutManager.addTextContainer(textContainer)
        textContainer.lineFragmentPadding = 0
        textContainer.lineBreakMode = lineBreakMode
        textContainer.maximumNumberOfLines = numberOfLines
        tapGesture.addTarget(self, action: #selector(CustomLabel.labelTapped(_:)))
        tapGesture.minimumPressDuration = 0
        tapGesture.cancelsTouchesInView = false
        //tapGesture.delegate = self.superview
        addGestureRecognizer(tapGesture)
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        textContainer.size = bounds.size
    }

    func labelTapped(_ gesture: UILongPressGestureRecognizer) {

        let locationOfTouch = gesture.location(in: gesture.view)
        let textBoundingBox = layoutManager.usedRect(for: textContainer)
        let textContainerOffset = CGPoint(x: (bounds.width - textBoundingBox.width) / 2 - textBoundingBox.minX, y: (bounds.height - textBoundingBox.height) / 2 - textBoundingBox.minY)
        let locationOfTouchInTextContainer = CGPoint(x: locationOfTouch.x - textContainerOffset.x, y: locationOfTouch.y - textContainerOffset.y)
        let indexOfCharacter = layoutManager.characterIndex(for: locationOfTouchInTextContainer, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)

        if gesture.state == .began {

            onCharacterTapped?(self, indexOfCharacter, true)

        } else if gesture.state == .ended {

            onCharacterTapped?(self, indexOfCharacter, false)

        }

    }

}

以下是从创建CustomCells的TableViewControllerClass中选择的内容:

class friendTextCell: UITableViewCell {

    @IBOutlet weak var labelText: CustomLabel!

    override func awakeFromNib() {
        super.awakeFromNib()
        self.layoutIfNeeded()
    }

}

2 个答案:

答案 0 :(得分:1)

替换

tapGesture.minimumPressDuration = 0

使用

tapGesture.minimumPressDuration = 0.5

识别开始得太快,没有得到表格接触

答案 1 :(得分:0)

  

如果滚动手势在其中一个UILongPressGestureRecognizer中开始,则包含标签的tableView不再滚动(平移)

当您将UILongPressGestureRecognizer的最小按下持续时间设置为0并且它开始抓取滚动视图的嵌入式手势识别器时,会出现此问题。你可以通过使用更大的延迟解决它,如果你需要使用延迟的长按手势识别器,它应该如何。 首先会响应您的表格视图的didSelectRow at并在延迟您的选择器之后。 它对我有用,虽然我在声明识别器的选择器方法之前删除了tapGesture.cancelsTouchesInView = false并添加了属性@objc(如果你在swift 4中写,则需要)。

如果您想毫不拖延地使用UILongPressGestureRecognizer,请使用UITapGestureRecognizer。在这种情况下,表格视图将滚动,但如果您点击标签,则无法接收didSelectRow方法。 表和集合视图手势委托被设置为基础滚动视图,因此您无法在UIGestureRecognizerDelegate上使用UIViewController方法来实现此目的。 如果你希望在识别器触发时在View Controller中收到某种回调,你可以通过实现委托方法来回调。

创建实现CustomLabel函数的labelTapped委托。在您的选择器中调用该委托函数。让您的单元格符合该委托,并在单元格中重复该单元格以将函数抛出到UIViewController。您也可以使用闭包委托模式。

希望有所帮助。

<强>更新

因此,解决方案是让UILongPressGestureRecognizer的{​​{1}}为0,并将代理分配给它的单元格(在我的情况下为superview)。 在单元格中,您需要覆盖此方法:

minimumPressDuration

顺便说一下,您不需要让您的单元格符合gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { return gestureRecognizer == yourGesture || otherGestureRecognizer == yourGesture } 的要求