UITextView с Gesture Recognizer - условно прямое касание к родительскому виду - PullRequest
0 голосов
/ 28 сентября 2018

У меня есть UITextView, встроенный в UITableViewCell.

. При просмотре текста отключена прокрутка, и он увеличивается по высоте вместе с текстом.

Текстовое представление имеетссылка-подобный раздел текста, который приписывается другому цвету и подчеркнут, и у меня есть распознаватель жестов касания , прикрепленный к текстовому представлению, который определяет, нажал ли пользователь на часть текста «ссылки» илине (это выполняется с использованием текстовых представлений layoutManager и textContainerInset, чтобы определить, попадает ли касание в «ссылку» или нет. Это в основном пользовательская функция проверки попадания).


Я хочу, чтобы ячейка табличного представления принимала касание и становилась выбранной, когда пользователь "пропускает" часть ссылки текстового представления, , но не может понять, как это сделать.


Для текстового представления userInteractionEnabled установлено значение true.Однако это не блокирует прикосновения к достижению ячейки табличного представления, когда не подключен распознаватель жестов.

И наоборот, если я установил его на false, по какой-то причине выбор ячейки вообще прекращается, даже при касании за пределами границ текстового представления (но распознаватель жестов все еще работает ... ПОЧЕМУ? ).


What I 've Пробовал

Я пытался переопределить gestureRecognizer(_ :shouldReceive:), но даже когда я возвращаю false, ячейка табличного представления не выбирается ...

Я также пытался реализовать gestureRecognizerShouldBegin(_:), но и там, даже если я выполню тест на попадание и верну false, ячейка не получит сигнал.


Как я могу перенаправить пропущенные касания обратно в ячейку, чтобы выделить ее?

Ответы [ 2 ]

0 голосов
/ 02 октября 2018

После попытки Ответ свапнила Луктуке (насколько я понял, по крайней мере) безрезультатно, и все возможные комбинации:

  • Реализация методов UIGestureRecognizerDelegate,
  • Переопределение UITapGestureRecognizer,
  • Условный вызов ignore(_:for:) и т. Д.

(возможно, в своем отчаянии я упустил что-то очевидное,но кто знает ...)

... Я сдался и решил последовать предложению @danyapata в комментариях к моему вопросу и подклассу UITextView .

Частично на основе кода, найденного на этом посте Medium , я придумал этот UITextView подкласс:

import UIKit

/**
 Detects taps on subregions of its attributed text that correspond to custom,
 named attributes.

 - note: If no tap is detected, the behavior is equivalent to a text view with
 `isUserInteractionEnabled` set to `false` (i.e., touches "pass through"). The
 same behavior doesn't seem to be easily implemented using just stock
 `UITextView` and gesture recognizers (hence the need to subclass).
 */
class LinkTextView: UITextView {

    private var tapHandlersByName: [String: [(() -> Void)]] = [:]

    /**
     Adds a custom block to be executed wjhen a tap is detected on a subregion
     of the **attributed** text that contains the attribute named accordingly.
     */
    public func addTapHandler(_ handler: @escaping(() -> Void), forAttribute attributeName: String) {
        var handlers = tapHandlersByName[attributeName] ?? []
        handlers.append(handler)
        tapHandlersByName[attributeName] = handlers
    }

    // MARK: - Initialization

    override init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)
        commonSetup()
    }

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

    override func awakeFromNib() {
        super.awakeFromNib()
        commonSetup()
    }

    private func commonSetup() {
        self.delaysContentTouches = false
        self.isScrollEnabled = false
        self.isEditable = false
        self.isUserInteractionEnabled = true
    }

    // MARK: - UIView

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        guard let attributeName = self.attributeName(at: point), let handlers = tapHandlersByName[attributeName], handlers.count > 0 else {
            return nil // Ignore touch
        }
        return self // Claim touch
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesEnded(touches, with: event)

        // find attribute name
        guard let touch = touches.first, let attributeName = self.attributeName(at: touch.location(in: self)) else {
            return
        }

        // Execute all handlers for that attribute, once:
        tapHandlersByName[attributeName]?.forEach({ (handler) in
            handler()
        })
    }

    // MARK: - Internal Support

    private func attributeName(at point: CGPoint) -> String? {
        let location = CGPoint(
            x: point.x - self.textContainerInset.left,
            y: point.y - self.textContainerInset.top)

        let characterIndex = self.layoutManager.characterIndex(
            for: location,
            in: self.textContainer,
            fractionOfDistanceBetweenInsertionPoints: nil)

        guard characterIndex < self.textStorage.length else {
            return nil
        }

        let firstAttributeName = tapHandlersByName.allKeys.first { (attributeName) -> Bool in
            if self.textStorage.attribute(NSAttributedStringKey(rawValue: attributeName), at: characterIndex, effectiveRange: nil) != nil {
                return true
            }
            return false
        }
        return firstAttributeName
    }
}

Как обычно, я подождуза пару дней до принятия моего собственного ответа, на случай, если появится что-то лучшее ...

0 голосов
/ 28 сентября 2018

Сохраняйте все свои представления активными (т. Е. Взаимодействие с пользователем включено).

Перебирайте жесты текстового представления и отключайте те, которые вам не нужны.

Зацикливайте gestureRecognisers представления таблицы.массив и сделать их зависимыми от настраиваемого жеста касания текстового представления, используя requireGestureRecognizerToFail .

Если это статическое табличное представление, вы можете сделать это с учетом загрузки.Для динамического табличного представления сделайте это в willDisplayCell для ячейки текстового представления.

...