手机上常见的导航模式是显示多个标签,里面有不同的页面。
在Flutter中,这可以通过TabBar部件以及TabController和TabBarView轻松实现。
但是在Flutter中,你如何以编程方式在这样的标签之间进行导航?
Flutter TabBar。按下按钮后的导航
让我们来弄清楚。👍
作为其中的一部分,我们将看到如何。
- 当一个按钮被按下时,更新所选的标签。
- 禁用用户在标签栏上的互动,这样我们就可以引导用户按顺序浏览多个标签。
Flutter TabBar的设置
让我们首先创建一个StatefulWidget ,其中有一个TabBar 和一个TabController 。
// Just a standard StatefulWidget
class JobApplicationFlow extends StatefulWidget {
const JobApplicationFlow({Key? key}) : super(key: key);
@override
_JobApplicationFlowState createState() => _JobApplicationFlowState();
}
// This is where the interesting stuff happens
class _JobApplicationFlowState extends State<JobApplicationFlow>
with SingleTickerProviderStateMixin {
// We need a TabController to control the selected tab programmatically
late final _tabController = TabController(length: 3, vsync: this);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Job Application'),
// Use TabBar to show the three tabs
bottom: TabBar(
controller: _tabController,
tabs: const <Widget>[
Tab(
icon: Icon(Icons.radio_button_on, color: Colors.white),
text: 'Experience',
),
Tab(
icon: Icon(Icons.check_box, color: Colors.white),
text: 'Skills',
),
Tab(
icon: Icon(Icons.send, color: Colors.white),
text: 'Submit',
),
],
),
),
);
}
}
然后,让我们添加一个TabBarView ,包含所有的视图(页面)。
Scaffold(
appBar: AppBar(...),
body: TabBarView(
controller: _tabController,
children: [
ExperiencePage(
onNext: () => _tabController.index = 1,
),
SkillsPage(
onNext: () => _tabController.index = 2,
),
SubmitPage(
onSubmit: () => showCupertinoDialog(...),
),
],
),
)
在上面的代码中,每个页面都是一个自定义的小部件,有一些内容和一个按钮,触发onNext 或onSubmit 回调。
我们可以使用每个回调来改变TabController 的索引。反过来,这也会更新当前的视图(页面)。
禁用用户在TabBar上的互动
这很有效,但是我们仍然可以通过点击标签来浏览它们,这并不总是可取的。
如果我们想 "强迫 "用户按顺序浏览页面,这并不理想。
Flutter TabBar:交互式导航
为了解决这个问题,我们可以创建一个ReadOnlyTabBar ,使用IgnorePointer ,忽略与标签的所有互动(正如StackOverflow的这个主题所提议的)。
// https://stackoverflow.com/a/57354375/436422
class ReadOnlyTabBar extends StatelessWidget implements PreferredSizeWidget {
final TabBar child;
const ReadOnlyTabBar({Key? key, required this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
return IgnorePointer(child: child);
}
@override
Size get preferredSize => child.preferredSize;
}
然后,我们可以用这个新的widget来包装TabBar 。
AppBar(
bottom: ReadOnlyTabBar(child:
TabBar(...),
),
)
我们还应该确保我们不能用交互式的拖动手势在标签之间进行切换。NeverScrollableScrollPhysics 可以帮助解决这个问题。
TabBarView(
// make sure we can't switch tabs with interactive drag gestures
physics: const NeverScrollableScrollPhysics(),
controller: _tabController,
children: [...],
)
就这样了!我们已经使用TabController,TabBar, 和TabBarView 来创建一个多步骤的用户旅程。
为了获得奖励,我们可以显示一个对话框,当我们按OK键时,将TabController 的索引重置为0。
SubmitPage(
onSubmit: () => showCupertinoDialog(
context: context,
builder: (_) {
return CupertinoAlertDialog(
title: const Text('Thank you'),
content: const Text('Your application was submitted.'),
actions: [
CupertinoDialogAction(
child: const Text('OK'),
onPressed: () {
// dismiss dialog
Navigator.of(context).pop();
_tabController.index = 0;
},
),
],
);
},
)
)
下面是最后的结果,再一次。
Flutter TabBar。按下按钮后的导航
结论
FlutterTabBar 和TabController 类为我们提供了方便的API,我们可以用它来在标签之间进行导航,无论是交互式还是编程式。
这使得它们成为将复杂的输入表单分解成更小的表单的理想选择,用户可以更容易地浏览。
你可以在DartPad上找到这个例子的完整源代码。
编码愉快!