#android #ios #dart #flutter #flutter-animation
#Android #iOS #dart #флаттер #флаттер-анимация
Вопрос:
Итак, у меня есть страница входа в систему с двумя текстовыми полями, а затем RaisedButton для входа в систему в самом низу. Когда я нажимаю на поле электронной почты и появляется клавиатура, я бы хотел, чтобы SingleChildScrollView (родительский элемент всего на странице) прокручивался до maxScrollExtent .
Вещи, которые я пробовал, которые не сработали:
- Используя возможности Scaffold делать это автоматически (Scaffold является родительским виджетом всего в приложении)
- Используя этот учебник, в котором создается вспомогательный виджет. Также используется WidgetBindingsObserver, но учебник в целом не сработал для меня. Интересно, однако, может ли WidgetBindingsObserver быть полезным.
Что почти работает:
- Прикрепление focusNode к текстовой форме, затем прикрепление слушателя в initState(), который будет анимироваться для maxScrollExtent, когда он имеет фокус.
Почти, вот что я имею в виду (извините за изменение цвета GIF):
Как вы можете видеть, это не работает при первом фокусировании, поэтому мне нужно нажать поле пароля, а затем повторно ввести поле электронной почты, чтобы оно анимировалось. Я попытался добавить задержку (даже до 500 мс), чтобы окно просмотра успело полностью изменить размер, прежде чем делать это, но это тоже не сработало.
Если вы узнаете эту тему входа в систему, это потому, что я адаптировал ее отсюда. Файл довольно длинный, но вот соответствующие биты:
@override
void initState() {
super.initState();
scrollController = ScrollController();
focusNode = FocusNode();
focusNode.addListener(() {
if (focusNode.hasFocus) {
scrollController.animateTo(scrollController.position.maxScrollExtent,
duration: Duration(milliseconds: 500), curve: Curves.ease);
}
});
_emailFieldController = TextEditingController();
_passFieldController = TextEditingController();
_emailFieldController.addListener(() {
_emailText = _emailFieldController.text;
});
_passFieldController.addListener(() {
_passText = _passFieldController.text;
});
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
controller: scrollController,
child: Container(
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
color: Colors.white,
image: DecorationImage(
colorFilter: ColorFilter.mode(
Colors.black.withOpacity(0.05), BlendMode.dstATop),
image: AssetImage('assets/images/mountains.jpg'),
fit: BoxFit.cover,
),
),
child: new Column(
children: <Widget>[
// this is where all other widgets in the file are
Container(
width: MediaQuery.of(context).size.width,
margin: const EdgeInsets.only(left: 40.0, right: 40.0, top: 10.0),
alignment: Alignment.center,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.deepPurple,
width: 0.5,
style: BorderStyle.solid),
),
),
padding: const EdgeInsets.only(left: 0.0, right: 10.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: TextField(
controller: _emailFieldController,
keyboardType: TextInputType.emailAddress,
focusNode: focusNode,
obscureText: false,
textAlign: TextAlign.left,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'coolname@bestemail.com',
hintStyle: TextStyle(color: Colors.grey),
),
),
),
],
),
),
Любые рекомендации будут с благодарностью. Спасибо!
Ответ №1:
Используйте addPostFrameCallback
для прослушивания после создания виджета.
_onLayoutDone(_){
FocusScope.of(context).requestFocus(focusNode);
}
@override
void initState() {
//... your stuff
WidgetsBinding.instance.addPostFrameCallback(_onLayoutDone);
super.initState();
}
Обновить
Я вижу ошибку, при первом использовании scrollController.position.maxScrollExtent
значение равно 0, после нажатия на текстовое поле пароля и изменения фокуса на email
, теперь maxScrollExtent
оно другое, потому что клавиатура открыта.
Если вы хотите, чтобы это работало, выполните логику для вычисления пробела и задайте значение напрямую.
Если вы используете
scrollController.animateTo(180.0,
duration: Duration(milliseconds: 500), curve: Curves.ease);
Это должно сработать.
Комментарии:
1. Пробовал это, как описано, и с focusNode.addListener() внутри него, но, к сожалению, никаких изменений.
2. не используйте focusNode.addListener() внутри _onLayoutDone , просто вызывайте непосредственно ScrollController.animateTo …
3. или просто вызовите: FocusScope.of(context).requestFocus(focusNode); внутри _onLayoutDone
4. было бы здорово, если бы вы могли поделиться частью своего кода, чтобы я мог протестировать самостоятельно
5. Нет проблем. Вот ссылка на файл в репозитории . Вся моя текущая работа находится в ветке разработки. Спасибо за вашу помощь!