- Оригинальный адрес:Flutter Deep Dive: Gestures
- Оригинальный автор:Nash
- Перевод с:Программа перевода самородков
- Постоянная ссылка на эту статью:GitHub.com/rare earth/gold-no…
- Переводчик:MeFelixWang
- Корректор:HaoChuan9421
Flutter предоставляет несколько отличных готовых компонентов для обработки сенсорных событий, таких какin InkWell
иInkResponse
. Оберните свои компоненты этими компонентами, и они будут реагировать на события касания. Среди прочего, он добавит всплески в стиле Material к вашим компонентам. Например, при расширении за пределы компонентаInkResponse
При желании управляйте формой и обрезанием всплеска. интересноInkWell
иInkResponse
не будет выполнять никакого рендеринга, но обновит родительскийMaterialкомпоненты. Типичный пример — фотографии. Если вы используетеinkEll
Оберните изображение, и вы заметите, что рябь не видна. Это потому, что он рисуется за изображением на материале. хочу сделатьInk
Эффект всплеска виден и может использоваться сInk.Image
Оберните картинку. Хотя это полезно для большинства задач, если вы хотите зафиксировать больше событий, например, когда пользователь перетаскивает экран, вы должны использоватьGestureDetector
.
Так что же такое детектор жестов? Как это работает?
Проще говоря, детектор жестов — это компонент без состояния, параметры которого в его конструкторе могут использоваться для различных событий касания. Стоит отметить, что вы не можете использовать обаPan
иScale
,так какScale
даPan
надмножество .GestureDetector
чисто для обнаружения жестов, поэтому никакого визуального ответа не дается (нетMaterial Inkраспространять).
Ниже представлена таблица, показывающаяGestureDetector
Различные предоставленные обратные вызовы и их соответствующие краткие описания:
свойство/обратный вызов | описывать |
---|---|
onTapDown |
Срабатывает каждый раз, когда пользователь касается экранаOnTapDown . |
onTapUp |
Когда пользователь перестает касаться экрана,onTapUp называется. |
onTap |
При кратковременном касании экранаonTap срабатывает. |
onTapCancel |
Когда пользователь касается экрана, не закончивTap , это событие будет запущено. |
onDoubleTap |
Вызывается при двойном касании экрана в быстрой последовательностиonDoubleTap . |
onLongPress |
Пользователь касается экрана больше, чем500 мсчас,onLongPress срабатывает. |
onVerticalDragDown |
Когда указатель соприкасается с экраном и начинает двигаться вертикально,onVerticalDown называется. |
onVerticalDragStart |
когда указательНачинатьВызывается при движении в вертикальном направленииonVerticalDragStart . |
onVerticalDragUpdate |
Этот метод вызывается каждый раз при изменении положения указателя на экране. |
onVerticalDragEnd |
Когда пользователь перестает двигаться, перетаскивание считается завершенным и вызывается это событие. |
onVerticalDragCancel |
Вызывается, когда пользователь внезапно прекращает перетаскивание. |
onHorizontalDragDown |
Вызывается, когда пользователь/указатель вступает в контакт с экраном и начинает двигаться горизонтально. |
onHorizontalDragStart |
Пользователь/указатель коснулся экрана иНачинатьДвигайтесь горизонтально. |
onHorizontalDragUpdate |
Вызывается каждый раз, когда положение указателя по горизонтали/оси x изменяется. |
onHorizontalDragEnd |
Это событие вызывается, когда заканчивается горизонтальное перетаскивание. |
onHorizontalDragCancel |
Когда указатель не срабатывает успешноonHorizontalDragDown когда звонили. |
onPanDown |
Вызывается, когда указатель касается экрана. |
onPanStart |
Когда событие указателя начинает двигаться,onPanStart курок. |
onPanUpdate |
Каждый раз, когда указатель меняет положение, вызовитеonPanUpdate . |
onPanEnd |
Это событие вызывается, когда панорамирование завершено. |
onScaleStart |
Это событие вызывается, когда указатель касается экрана и устанавливает фокус на 1.0. |
onScaleUpdate |
Указатель, касающийся экрана, указывает на новый фокус. |
onScaleEnd |
Вызывается, когда указатель больше не соприкасается с экраном, указывая на завершение жеста. |
GestureDetector
Какие жесты пытаться распознать, определяются на основе того, какой обратный вызов не является нулевым. Это полезно, потому что если вам нужно отключить жест, вам нужно передатьnull.
Давайте начнем с **onTap**
Жесты в качестве примера определяют, как обращаться с **GestureDetector**
.
Во-первых, мы используемonTap
Обратный вызов создает GestureDetector, поскольку он не равен нулю, когда происходит событие касания.GestureDetector
будет использовать наш обратный вызов. существуетGestureDetector
Внутри создаетGesture Factory.Gesture Recognizer
Проводится большая работа, чтобы определить, какой жест обрабатывается. Этот процесс предназначен дляGestureDetector
То же самое для всех предоставленных обратных вызовов.GestureFactories
затем будет переданоRawGestureDetector
.
RawGestureDetector
Придется проделать большую работу по обнаружению жестов. этокомпоненты с состоянием, синхронизирует все жесты при изменении состояния, обрабатывает распознаватели, получает все событиясобытия указателяи отправьте его зарегистрированному распознавателю. тогда они будутЖест АренаСхватка между самцами и самками.
RawGestureDetectorbuild
Метод сборки состоит из базового класса для прослушивания событий указателя.Listener
сочинение. Это ваш предпочтительный класс, если вы хотите использовать необработанные входные данные с платформы, такие как события вверх, вниз или отмена.Listener
не дает вам никаких жестов, только основныеonPointerDown
,onPointerUp
,onPointerMove
иonPointerCancel
событие. Все должно обрабатываться вручную, в том числеЖест Аренасообщить о себе. Если вы этого не сделаете, вы не получите автоматическую отмену и не сможете участвовать во взаимодействиях, которые там происходят. Этосторона компонентанижний слой.
Listener
ЯвляетсяSingleChildRenderObjectWidget
, унаследовано отRenderProxyBoxWithHitTestBehavior
типRenderPointerListener
составной, что означает, что он имитирует свойства своих подклассов, позволяя при этом настраиватьHitTestBehavior
. Если вы хотите узнать больше о блоках рендеринга и о том, как они работают, прочитайтеNorbert Kozsirнаписал эту статью.
HitTestBehaviour
Есть три варианта,deferToChild
,opaque
иtranslucent
. это изGestureDetector
, и там можно настроить.DeferToChild
Передавать события вниз по дереву компонентов, что такжеПоведение по умолчанию.Opaque
предотвратит получение фоновыми компонентами событий, в то время какTranslucent
Это позволяет фоновым компонентам получать события.
Так что, если вы хотите, чтобы и родительский, и дочерний компоненты получали события указателя?
Давайте представим на мгновение, что у вас есть вложенный список, и вы хотите просмотреть их все одновременно. Для этого вам нужно, чтобы и родительский, и дочерний компоненты получали указатели. Вы настраиваете поведение теста попадания, чтобы оно было полупрозрачным, убедитесь, что оба компонента получают событие, но все идет не так, как планировалось... почему?
Ответ на поставленный выше вопросGestureArena
.
GestureArena
используется дляЖест Значение. Все идентификаторы бьются здесь и рассылаются. В любой точке экрана может быть несколько распознавателей жестов. Арена учитывает, как долго пользователь касается экрана, наклон и направление перетаскивания, чтобы определить победителя.
И родительский, и дочерний списки отправят своих распознавателей на арену, но (на момент написания этой статьи) победит только один, и это всегда будет дочерний список.
Исправление заключается в использованииGestureFactory
при использованииRawGestureDetector
изменить производительность арены.
В качестве примера создадим простое приложение, состоящее из двух контейнеров. Цель состоит в том, чтобы и дочерний контейнер, и родительский контейнер получили жест.
использоватьRawGestureDetector
Заверните оба контейнера. Далее мы создадим собственный распознаватель жестов.AllowMultipleGestureRecognizer
.GestureRecognizer
Является базовым классом, от которого наследуются все остальные распознаватели. Он предоставляет базовый API для классов, чтобы они могли работать/взаимодействовать с распознавателями жестов. Примечательно,GestureRecognizer
Не заботьтесь о специфике самого распознавателя.
// 自定义手势识别器。
// 重写 rejectGesture()。当一个手势被拒绝时,将调用此函数。默认情况下,它会处理
// 识别器并进行清理。但是我们修改了它,它实际上是手动添加的,以代替识别器被处理。
// 结果是你将有两个识别器在竞技场中获胜。这是双赢。
class AllowMultipleGestureRecognizer extends TapGestureRecognizer {
@override
void rejectGesture(int pointer) {
acceptGesture(pointer);
}
}
В приведенном выше коде мы создаем класс, который наследуется отTapGestureRecognizer
пользовательский классAllowMultipleGestureRecognizer
. Это означает, что он может наследоватьTapGestureRecognizer
. В этом примере мы перепишемrejectGesture
, чтобы вместо обработки распознавателя он принимал его вручную.
Теперь мы будемGestureRecognizerFactoryWithHandlers
Пользовательский распознаватель жестов в переданномRawGestureDetector
.
Widget build(BuildContext context) {
return RawGestureDetector(
gestures: {
AllowMultipleGestureRecognizer: GestureRecognizerFactoryWithHandlers<
AllowMultipleGestureRecognizer>(
() => AllowMultipleGestureRecognizer(), //构造函数
(AllowMultipleGestureRecognizer instance) { //初始化器
instance.onTap = () => print('Episode 4 is best! (parent container) ');
},
)
},
Теперь мы будемGestureRecognizerFactoryWithHandlers
Пользовательский распознаватель жестов в переданномRawGestureDetector
. Фабричной функции требуются два свойства, конструктор и инициализатор, для создания и инициализации распознавателя жестов. Мы передаем эти параметры с помощью лямбда. Как упоминалось в приведенном выше коде, конструктор возвращаетAllowMultipleGestureRecognizer
новый экземпляр , а инициализатор получает свойства, которые прослушивают нажатия и выводят некоторый текст на консоль.instance
. Процесс будет повторяться для обоих контейнеров, с той лишь разницей, что будет напечатан текст.
Вот полный исходный код примера приложения:
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
//主函数。 Flutter 应用的入口
void main() {
runApp(
MaterialApp(
home: Scaffold(
body: DemoApp(),
),
),
);
}
// 简单的演示应用程序,由两个容器组成。目标是允许多个手势进入竞技场。
// 所有的东西都是通过 `RawGestureDetector` 和自定义 `GestureRecognizer` (继承自 `TapGestureRecognizer` )
// 将自定义 GestureRecognizer,`AllowMultipleGestureRecognizer` 添加到手势列表中,并创建一个 `AllowMultipleGestureRecognizer` 类型的 `GestureRecognizerFactoryWithHandlers`。
// 它用给定的回调创建一个手势识别器工厂函数,在这里是 `onTap`。
// 它监听 `onTap` 的一个实例,然后在被调用时向控制台打印文本。需要注意的是,`RawGestureDetector` 对于两个容器
// 是相同的。唯一的区别是打印的文本(用来标识组件)。
class DemoApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RawGestureDetector(
gestures: {
AllowMultipleGestureRecognizer: GestureRecognizerFactoryWithHandlers<
AllowMultipleGestureRecognizer>(
() => AllowMultipleGestureRecognizer(),
(AllowMultipleGestureRecognizer instance) {
instance.onTap = () => print('Episode 4 is best! (parent container) ');
},
)
},
behavior: HitTestBehavior.opaque,
//父容器
child: Container(
color: Colors.blueAccent,
child: Center(
//用 RawGestureDetector 将两个容器包裹起来
child: RawGestureDetector(
gestures: {
AllowMultipleGestureRecognizer:
GestureRecognizerFactoryWithHandlers<
AllowMultipleGestureRecognizer>(
() => AllowMultipleGestureRecognizer(), //构造函数
(AllowMultipleGestureRecognizer instance) { //初始化器
instance.onTap = () => print('Episode 8 is best! (nested container)');
},
)
},
//在第一个容器中创建嵌套容器。
child: Container(
color: Colors.yellowAccent,
width: 300.0,
height: 400.0,
),
),
),
),
);
}
}
// 自定义手势识别器。
// 重写 rejectGesture()。当一个手势被拒绝时,将调用此函数。默认情况下,它会处理
// 识别器并进行清理。但是我们修改了它,它实际上是手动添加的,以代替识别器被处理。
// 结果是你将有两个识别器在竞技场中获胜。这是双赢。
class AllowMultipleGestureRecognizer extends TapGestureRecognizer {
@override
void rejectGesture(int pointer) {
acceptGesture(pointer);
}
}
Итак, каков результат выполнения приведенного выше кода?
Когда вы касаетесь желтого контейнера, оба компонента получают событие касания, поэтому на консоль выводятся два оператора.
применение:
Вывод консоли:
Что происходит, когда вы выигрываете?
После того, как жест выигран, арена будет вclosed
иswept
государство. Это удалит неиспользуемые распознаватели и сбросит арену. Затем действие выполняется победным жестом.
вернуться к нашемуTapПример, после этого сопоставляется сonTap
Теперь функция будет выполнена.
Суммировать
Сегодня мы увидели, как фреймворк Flutter обрабатывает жесты. Сначала мы рассмотрели фантастические готовые компоненты, которые Flutter предоставляет для обработки нажатий и других сенсорных событий. Далее мы обсудилиGestureDetector
И экспериментировал с его внутренней работой. На примере мы увидели, как Flutter обрабатывает тап-жесты. мы прошли черезRawGestureDetector
Эта земля слушалаListener
голос, и к названномуGestureArena
Таинственный трибьют Flutter Fight Club.
Наконец, мы рассмотрели большую часть системы жестов во Flutter с точки зрения приложения. Вооружившись этими знаниями, вы теперь должны лучше понимать, как прикосновения к экрану приобретаются и обрабатываются за кулисами. Если у вас есть какие-либо вопросы или проблемы, пожалуйста, не стесняйтесь комментировать или черезTwitterverseСвяжитесь со мной.
такой жеОченьблагодарныйSimon Lightfoot(он же "Flutter Whisperer") внес свой вклад в эту статью ❤
Если вы обнаружите ошибки в переводе или в других областях, требующих доработки, добро пожаловать наПрограмма перевода самородковВы также можете получить соответствующие бонусные баллы за доработку перевода и PR. начало статьиПостоянная ссылка на эту статьюЭто ссылка MarkDown этой статьи на GitHub.
Программа перевода самородковэто сообщество, которое переводит высококачественные технические статьи из Интернета сНаггетсДелитесь статьями на английском языке на . Охват контентаAndroid,iOS,внешний интерфейс,задняя часть,блокчейн,продукт,дизайн,искусственный интеллектЕсли вы хотите видеть более качественные переводы, пожалуйста, продолжайте обращать вниманиеПрограмма перевода самородков,официальный Вейбо,Знай колонку.