Много раз флаттер должен иметь дело с фокусом ввода, давайте посмотрим, как использовать элемент управления сегодня.
Эту статью можно рассматривать как простое использование, и она не будет углубляться в исходный код, чтобы обсуждать, как прикрепить, в основном использование элементов управления серии Focus, и как многократно переходить между несколькими полями ввода.
Описание окружающей среды
- Эта статья в основном основана на версии 1.17.5 flutter sdk, другие версии должны быть похожими, но со временем многое может измениться, пожалуйста, продолжайте проверять, действительна ли она в будущем.
- Эта статья предназначена в основном для мобильных устройств.
- На момент написания этой статьи фокус Flutter Web был довольно запутанным, и он, кажется, отличается от мобильной версии, поэтому я пока пропущу его.
- Настольная версия была опробована только на macOS, других настольных движках, проверьте сами.
Связанные классы дартс
Во флаттере классы, связанные с фокусом, следующие:
-
FocusNode
: можно сказать, что это наиболее часто используемый, один из основных классов -
FocusManager
: Класс Singleton, эта штука обрабатывает ядро управления фокусом всего приложения флаттера, включая такие операции, как всплывающее окно программной клавиатуры с собственным взаимодействием. -
Focus
: виджет, используемый для «добавления» возможностей фокусировки к элементу управления, просто завершите его,InkWell
Способность таких элементов управления получать фокус зависит от этой вещи. -
FocusScope
: Виджет, подкласс Фокуса, все подвиджеты, обернутые этой вещью.FocusNode
будут автоматически зарегистрированы в нем и примут единое управление -
FocusScopeNode
: Эта штука сама по себе является подклассом FocusNode, но в основном используется дляFocusScope
б/у, расширенныйFocusNode
поведение -
FocusTraversalPolicy
,FocusTraversalGroup
: Эти две вещи являются стратегией узла фокуса, который используется для сортировки следующего фокуса. Эти две вещи не должны быть рассмотрены в этой статье. Если вам интересно, вы можете перейти к официальной документации. В настоящее время я думаю его не следует использовать.
FocusNode
Об этом много говорят, поэтому я не буду распространяться об этом, просто кратко расскажу о нескольких методах.
-
canRequestFocus
: запрашивать ли фокус -
context
: BuildContext виджета, фокус которого "прикреплен" -
hasFocus
: есть ли фокус -
unfocus
: отказаться от фокуса, если текущий узел имеет фокус и это вызывается, фокус будет передан, если в то же время появится программная клавиатура, программная клавиатура будет закрыта. -
requestFocus
: запросить фокус, после вызова этого метода он переместит фокус на текущий
Примечания: Есть много других методов, которые трудно использовать для обычных друзей и нормальных сценариев приложений. Они предоставляются в качестве программной структуры, но личные мнения не должны быть поняты, если вы знаете основные методы
FocusManager
Этот вариант осуществления является одной вещьюFocusManager.instance
Получать
Есть общий способ понять:FocusManager.instance.primaryFocus.unfocus();
, назови это, софт клава опустится
В основном в этой штуке есть приватные методы, и не так много их можно вызвать.
FocusHighlightMode Эта штука "режим" фокуса, соответствующий прикосновению и мышке и клавиатуре. Лично я не думаю, что он используется в нормальных условиях, достаточно прикосновения на мобильном терминале.
Focus
Эта штука вообще редко используется, в SDK есть кое-какие места, которые будут использоваться,Focus
Сам внутренний объект поддерживаетFocusNode
, например, кнопка может реагировать на фокус клавиатуры и вводить потому что внутри что-то есть
Этот класс не очень часто используется в проекте флаттера, но он является ключевым.
_FocusableActionDetectorState
: соответствуетFocusableActionDetector
состояние, этот класс используется дляCheckBox
, Radio
, Switch
FocusScope
Эта вещь редко встречается в документах. Здесь я кратко проанализирую ее. Можно также сказать, что это будет предметом дальнейшего использования. Когда я сталкиваюсь с полем ввода в реальной разработке, этот элемент управления является моим первым выбором.
Проще говоря, именно в этом субуправленииFocusNode
будет поддерживаться равномерно
Метод построения этой штуки может передавать некоторые параметры, и наиболее часто используемые из них — node, canRequestFocus и тому подобное.
Вот skipTraversal, этот параметр можно объяснить позже на примере
FocusScopeNode
вообще иFocusScope
использовать в паре
написать код
написание начального уровня
Ну а спереди все концептуально, многие мои друзья не хотят его видеть, да и не интересно
Например, есть такая сцена
В случае с приложением есть 4 поля ввода, и вы можете нажимать одно за другим, но если вы хотите получить хороший пользовательский опыт, разве вы не должны нажимать Enter до следующего шага, а затем отправить последний напрямую?
Смоделируйте, сколько людей пишут эту вещь
Хм, пересмотрите это, хм, это аккуратно, так что... что вы делаете, когда у вас есть 10?
Может, перепишем?
Хорошо, при условии, что у вас есть прочная основа, естественно писать так.
Передовой
Вышеупомянутое письмо очень быстрое, но не трепетное, мы можем изменить написание трепетания на это
import 'package:flutter/material.dart';
class Example3 extends StatefulWidget {
@override
_Example3State createState() => _Example3State();
}
class _Example3State extends State<Example3> {
FocusScopeNode node = FocusScopeNode();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: FocusScope(
node: node,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
for (var i = 0; i < 10; i++) buildTextField(),
],
),
),
),
);
}
TextField buildTextField() {
return TextField(
onEditingComplete: () {
if (node.focusedChild == node.children.last) {
print('submit');
} else {
node.nextFocus();
}
},
);
}
}
На этот раз дажеFocusNode
Вам не нужно писать его самостоятельно, просто используйте его непосредственно в Scope.
Как выглядит этот пример:
Это потому чтоTextField
даEditableText
упаковка
Затем в EditableText прикрепите его к контексту
Увидев это, вы обнаружили, что некоторые вещи на самом деле очень просты, а потом их усложняют?
Передовой
import 'package:flutter/material.dart';
class Example3 extends StatefulWidget {
@override
_Example3State createState() => _Example3State();
}
class _Example3State extends State<Example3> {
FocusScopeNode node = FocusScopeNode();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: FocusScope(
node: node,
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
for (var i = 0; i < 5; i++) buildTextField(),
Row(
children: <Widget>[
Expanded(
child: TextField(
onEditingComplete: onEdit,
),
),
RaisedButton(
onPressed: () {},
child: Text('假装获取验证码'),
),
],
),
for (var i = 0; i < 5; i++) buildTextField(),
],
),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
print(node.traversalChildren.length);
},
child: Icon(Icons.check),
),
);
}
TextField buildTextField() {
return TextField(
onEditingComplete: onEdit,
);
}
void onEdit() {
node.nextFocus();
}
}
Иногда рядом с этим видом есть кнопка, что является относительно распространенным способом, и тогда приведенный выше код внезапно не работает должным образом.
Тогда вам нужно изменить код
floatingActionButton: FloatingActionButton(
onPressed: () {
print(node.children.length); // 12
},
child: Icon(Icons.check),
),
Почему оно изменено на 12, разве там не только 11 полей ввода?
Именно об этом я и говорил в начале, у многих кнопок тоже есть фокус.
Итак, как пропустить эту кнопку при входе
RaisedButton(
onPressed: () {},
focusNode: FocusNode(skipTraversal: true),
child: Text('假装获取验证码'),
),
Да, все, вручную передать кнопку дляFocusNode
, затем пропустить работы
Полный код:
import 'package:flutter/material.dart';
class Example3 extends StatefulWidget {
@override
_Example3State createState() => _Example3State();
}
class _Example3State extends State<Example3> {
FocusScopeNode node = FocusScopeNode();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: FocusScope(
node: node,
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
for (var i = 0; i < 5; i++) buildTextField(),
Row(
children: <Widget>[
Expanded(
child: TextField(
onEditingComplete: onEdit,
),
),
RaisedButton(
onPressed: () {},
focusNode: FocusNode(skipTraversal: true),
child: Text('假装获取验证码'),
),
],
),
for (var i = 0; i < 5; i++) buildTextField(),
],
),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
print(node.traversalChildren.length);
},
child: Icon(Icons.check),
),
);
}
TextField buildTextField() {
return TextField(
onEditingComplete: onEdit,
);
}
void onEdit() {
node.nextFocus();
}
}
Итак, резюмируя шаги
- обернуть все поля ввода в одно
FocusScope
внутри, настройкиFocusScopeNode
. - Установите элемент управления, который имеет фокус, но не является полем ввода
FocusNode(skipTraversal: true)
- использовать
FocusScopeNode
изnextFocus
метод
постскриптум
На данный момент в этой статье ожидается, что продолжение этой серии будет глубоко проникать в исходный код.
над