#flutter #dart
Вопрос:
У меня есть 2 pages
(страница A и страница B), по которым вы можете перемещаться с и на через a bottom navigation bar
.
У меня есть специальная банка для использования, где:
Страница А : должно быть « keptAlive
» большую часть времени, только 1 сценарий, в котором он должен быть восстановлен
Страница Б: должно быть rebuilt
, каждый раз, когда мы переключаемся на нее.
У меня работают эти модели поведения, кроме одной, Dynamic
keepAlive
для страницы А.
Прежде всего, код:
Главная страница, на которой размещена навигация:
class Example extends StatefulWidget {
@override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
int _currentIndex = 0;
PageController? _pageController;
List<Widget> _pages = [];
@override
void initState() {
super.initState();
_currentIndex = 0;
_pages = [PageA(), PageB()];
_pageController = PageController(initialPage: _currentIndex);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('example')),
body: PageView(
controller: _pageController,
physics: NeverScrollableScrollPhysics(),
children: _pages,
),
bottomNavigationBar: AnimatedBottomNavigationBar.builder(
itemCount: _iconList.length,
activeIndex: _currentIndex,
onTap: (index) {
setState(() {
_currentIndex = index;
_pageController!.jumpToPage(index);
});
},
),
);
}
Теперь эта часть работает нормально, на странице B мне не нужно делать ничего особенного, так как по умолчанию при просмотре страниц каждый раз, когда я переключаюсь на эту страницу, она перестраивается.
Теперь, для страницы A, я хочу, чтобы большую часть времени она НЕ перестраивалась, если переходить со страницы B
И я достигаю этого с помощью: AutomaticKeepAliveClientMixin
и wantKeepAlive
:
Страница виджета:
class PageA extends StatefulWidget {
@override
_PageAState createState() => _PageAState();
}
class _PageAState extends State<PageA> with AutomaticKeepAliveClientMixin<PageA> {
bool shouldKeepAlive = true;
@override
void initState() {
super.initState();
}
@override
bool get wantKeepAlive => shouldKeepAlive;
@override
Widget build(BuildContext context) {
super.build(context);
/// .....
Так что это отлично работает, страница A не перестраивается, но у меня есть особый случай,
когда, если на странице A пользователь заполняет a textField
любым значением, а затем переключается на страницу B, я хочу, чтобы, если пользователь вернется на страницу A, теперь она была сброшена и перестроена!
Я пробовал разные подходы, но я не могу изменить значение wantKeepAlive
после того, как страница A была создана в первый раз. Я пробовал использовать updateKeepAlive()
, но это не помогает, так что у кого-нибудь есть идея, как я могу динамически настроить wantKeepAlive
страницу A, чтобы, если я перейду на страницу B при некоторых особых условиях, при возвращении на страницу A она могла быть сброшена, а могла и не быть сброшена.
Ответ №1:
Используя метод «updateKeepAlive» в классе «AutomaticKeepAliveClientMixin»,
вы можете изменить условие сохранения.
Если пользователь вводит текст в «Текстовое поле» на странице,
установите значение «shouldKeepAlive» в значение false и вызовите метод «updateKeepAlive», чтобы обновить параметр «Сохранить жизнь».
Я подтвердил, что все работает хорошо, отправив сообщение журнала в метод build (), чтобы подтвердить, когда вызывается build ().
——Модификация—-
Я точно не знаю, почему «updateKeepAlive» адаптируется после того, как фокус удален из виджета текстового поля.
Я изменил некоторый код, чтобы отключить фокус от текстового поля после исчезновения клавиатуры, используя кнопку «стрелка вниз» или «галочка».
По этой причине я использовал один пакет, чтобы проверить, отображается или скрывается клавиатура. https://pub.dev/packages/keyboard_visibility
import 'package:animated_bottom_navigation_bar/animated_bottom_navigation_bar.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:keyboard_visibility/keyboard_visibility.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Example(),
);
}
}
class Example extends StatefulWidget {
@override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
int _currentIndex = 0;
PageController _pageController;
List<Widget> _pages = [];
final iconList = <IconData>[
Icons.brightness_5,
Icons.brightness_4,
];
@override
void initState() {
super.initState();
_currentIndex = 0;
_pages = [PageA(), PageB()];
_pageController = PageController(initialPage: _currentIndex);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('example')),
body: PageView(
controller: _pageController,
physics: NeverScrollableScrollPhysics(),
children: _pages,
),
bottomNavigationBar: AnimatedBottomNavigationBar.builder(
itemCount: 2,
activeIndex: _currentIndex,
onTap: (index) {
setState(() {
_currentIndex = index;
_pageController.jumpToPage(index);
});
},
tabBuilder: (int index, bool isActive) {
final color = isActive ? Color(0XFFFFA400) : Colors.grey;
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
iconList[index],
size: 24,
color: color,
),
const SizedBox(height: 4),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Text(
"Page $index",
maxLines: 1,
style: TextStyle(color: color),
),
)
],
);
},
),
);
}
}
class PageA extends StatefulWidget {
@override
_PageAState createState() => _PageAState();
}
class _PageAState extends State<PageA>
with AutomaticKeepAliveClientMixin<PageA> {
bool shouldKeepAlive = true;
String input;
@override
void initState() {
super.initState();
KeyboardVisibilityNotification().addNewListener(
onChange: (bool visible) {
if (!visible) {
FocusManager.instance.primaryFocus.unfocus();
print('keyboard disappeared');
if (!shouldKeepAlive amp;amp; input.isEmpty) {
shouldKeepAlive = true;
updateKeepAlive();
} else if (shouldKeepAlive amp;amp; input.isNotEmpty) {
shouldKeepAlive = false;
updateKeepAlive();
}
}
},
);
}
@override
bool get wantKeepAlive => shouldKeepAlive;
@override
Widget build(BuildContext context) {
super.build(context);
print('PageA is builded');
return TextField(
onSubmitted: (String value) {
print('onSumitted: $value');
},
onChanged: (String value) {
input = value;
print('onChanged: $value');
},
);
}
}
class PageB extends StatefulWidget {
@override
_PageBState createState() => _PageBState();
}
class _PageBState extends State<PageB> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
print('PageB is builded');
return TextField();
}
}
Комментарии:
1. Это был мой первый подход после того, как я нашел метод «updateKeepAlive ()», но он не сработал, поэтому я разместил здесь, в основном у меня точно такой же код, у меня есть несколько отпечатков в методе «OnChanged» текстового поля, и значение ShouldKeepAlive обновляется правильно, но даже если значение «shouldKeepAlive» установлено в значение false, если я переключусь на страницу, когда я вернусь на страницу, я нахожусь в том же самом состоянии, в текстовом поле есть то, что я написал перед переключением страниц, и страница не сбрасывается…что-то не так отсутствует, похоже, что, когда я возвращаюсь назад, он не запускает повторное создание виджета PageA
2. и я просто запускаю ваш код, и действительно, если вы заполните текстовое поле на странице, а затем переключитесь на страницу, когда вернетесь на страницу, даже в вашем примере текстовое поле все еще имеет value…so это не сбросило страницу
3. @AJ989 Правда? Я много раз подтверждал, работает ли это так, как вы хотите.
4. @AJ989 Я прикрепил gif, который я тестировал, к контенту.
5. хорошо, я выяснил, почему это не работает на моей стороне, я закрывал клавиатуру с помощью «стрелки вниз» вместо того, чтобы нажимать «значок галочки», чтобы закрыть клавиатуру.. Это подводит меня к проблеме, как я могу убедиться, что даже если пользователь закрывает клавиатуру кнопкой «вниз» и переключает страницу, у меня такое же поведение? Спасибо за помощь