У меня есть UIPageViewController, где одна страница - это экран Настройки . На этом экране есть UISwitch для включения или выключения настройки.

Хотя я заметил, что многие люди нажимают UISwitch, чтобы переключать его, как и я, я заметил, что некоторые пользователи перемещают UISwitch, чтобы переключать его.

Попытка сдвинуть UISwitch может вызвать проблемы, когда он находится на UIViewController, который является частью UIPageViewController, поскольку сдвиг переключателя может начать сдвигать UIPageViewController, как если бы пользователь хотел изменить страницы.

Это поведение, которое кажется очень сломленным и непоследовательным. Кажется, что если пользователь касается переключателя, но колеблется перед скольжением, касания регистрируются UISwitch, и он работает так, как ожидает пользователь. Но если пользователь прикасается к UISwitch и сразу начинает скользить, вместо этого UIPageViewController получает прикосновения. Кажется, что между UISwitch прикосновением к получению прикосновений есть очень тонкая грань (порог колебания).

Как бы вы решили эту проблему?

Вот пример, который начинается с простых нажатий для переключения UISwitch, а затем показывает некоторые из различных способов попробовать скользить UISwitch, которые приводят к противоречивым результатам:

inconsistent-uiswitch-behavior


Возможные решения и проблемы

Один из способов решения этой проблемы - обнаружение касаний в любом месте Настройки UIViewController, и если касания начинаются где-то в кадре UISwitch, предотвратите {{ X2}} от скольжения.

Меня беспокоит то, что простое отключение скольжения для UIPageViewController не гарантирует, что касания будут переданы UISwitch. Это может означать, что пользователь может попытаться сдвинуть UISwitch, а UIPageViewController не будет скользить, но UISwitch также не будет реагировать на прикосновения, из-за чего он будет казаться сломанным и непоследовательным.

Чтобы начать исследовать это возможное решение, я попытался обнаружить прикосновения, переопределив метод touchesBegan следующим образом:

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

    print("touchesBegan")

    super.touchesBegan(touches,
                       with: event)
}

Я попытался обнаружить касания таким образом как на UIPageViewController, так и на UIViewController конкретной странице Настройки , но ни один из них не вызывается. Я также пытался установить view.isUserInteractionEnabled = true для видов и различные комбинации true или false для разных UIViewController, но все еще не могу обнаружить прикосновения.

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


ОБНОВЛЕНИЕ: РЕШЕНИЕ

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

В конечном счете, ответ Леона заставил меня пойти по пути к простому решению, которое работало с UIPanGestureRecognizer, которое очень похоже на то, что я пытался с UISwipeGestureRecognizer, основанным на ответе Карла, но в конечном итоге не сделало дают одинаковые результаты.

В итоге я создал подкласс UISwitch и добавил UIPanGestureRecognizer, который ничего не делает. Это заставляет его вести себя именно так, как я хочу: каждый раз, когда пользователь начинает сдвигать переключатель, UIPageViewController не панорамируется.

class NoPanSwitch: UISwitch {

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

        let recognizer = UIPanGestureRecognizer(target: self,
                                                action: nil)
        addGestureRecognizer(recognizer)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
2
gohnjanotis 16 Дек 2018 в 22:11

3 ответа

Лучший ответ

Контроллер просмотра страницы имеет свойство gestureRecognizers для распознавателей жестов, управляющих взаимодействиями на странице. Я бы попробовал добавить распознаватель панорамирования в UISwitch и добавить его в контроллер страницы. Эффект, который я ожидаю, состоит в том, что распознаватель жестов панорамирования контроллера страницы потребует, чтобы распознаватели жестов в массиве потерпели неудачу, прежде чем распознавать панорамирование страницы, чтобы прокрутка не происходила, когда вы щелкаете переключатель. Если это не сработает, вы можете поменять контроллер страницы на представление прокрутки с представлением стека или коллекции с вашими контроллерами внутри. Тогда у вас будет полный контроль над panGEstureRecognizer представлениями школы, чтобы добиться вышеуказанного поведения.

1
Leon Deriglazov 19 Дек 2018 в 12:26

Просто попробуйте это и посмотрите, работает ли он так, как вы хотите, или нет.

  1. Обнаружение касаний UISwitch, когда UISwitch touchBegan присваивают делегату и источнику данных UIPageViewController значение `nil.

  2. Вкл. touchesEnd установите снова, установите datasource и delegate для UIPageViewController.

Таким образом, вы сможете взаимодействовать с вашим UISwitch, как вы хотите.

0
Martin 18 Дек 2018 в 05:15

Можете ли вы подклассифицировать UIS-переключатели, которые вы используете? Это больше похоже на работу для этого класса, переопределяя gestRecognizerShouldBegin () для возврата NO для распознавателя жестов смахивания, движущегося горизонтально. В документации этого метода упоминается, что UISlider использует этот метод для той же цели; UISwitch, вероятно, должен сделать то же самое.

Другой вариант может заключаться в создании пользовательского UIGestureRecognizer, который с помощью делегата или методов UIGestureRecognizerSubclass заставляет любой другой UISwipeGestureRecognizer давать сбой, если он запускается через UISwitch, и сам по себе устанавливается с cancellsTouchesInView в false (и ничего не делает, когда он «завершается успешно»).

1
Carl Lindberg 18 Дек 2018 в 04:59