这是我想要的输出。我仍然是新的flutter,所以谁可以让我知道,如果已经有一个小部件,这种开关或我应该如何做一个??此外,我希望数据显示在这个按钮下面的变化,如果我选择其他按钮,但我猜这是显而易见的。先谢了。
e5nszbig1#
您可以使用TabBar小部件来实现这一点,我添加了一个完整的示例来演示如何使用TabBar小部件来创建它:
TabBar
class StackOver extends StatefulWidget { @override _StackOverState createState() => _StackOverState();}class _StackOverState extends State<StackOver> with SingleTickerProviderStateMixin { TabController _tabController; @override void initState() { _tabController = TabController(length: 2, vsync: this); super.initState(); } @override void dispose() { super.dispose(); _tabController.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text( 'Tab bar', ), ), body: Padding( padding: const EdgeInsets.all(8.0), child: Column( children: [ // give the tab bar a height [can change hheight to preferred height] Container( height: 45, decoration: BoxDecoration( color: Colors.grey[300], borderRadius: BorderRadius.circular( 25.0, ), ), child: TabBar( controller: _tabController, // give the indicator a decoration (color and border radius) indicator: BoxDecoration( borderRadius: BorderRadius.circular( 25.0, ), color: Colors.green, ), labelColor: Colors.white, unselectedLabelColor: Colors.black, tabs: [ // first tab [you can add an icon using the icon property] Tab( text: 'Place Bid', ), // second tab [you can add an icon using the icon property] Tab( text: 'Buy Now', ), ], ), ), // tab bar view here Expanded( child: TabBarView( controller: _tabController, children: [ // first tab bar view widget Center( child: Text( 'Place Bid', style: TextStyle( fontSize: 25, fontWeight: FontWeight.w600, ), ), ), // second tab bar view widget Center( child: Text( 'Buy Now', style: TextStyle( fontSize: 25, fontWeight: FontWeight.w600, ), ), ), ], ), ), ], ), ), ); }}
class StackOver extends StatefulWidget {
@override
_StackOverState createState() => _StackOverState();
}
class _StackOverState extends State<StackOver>
with SingleTickerProviderStateMixin {
TabController _tabController;
void initState() {
_tabController = TabController(length: 2, vsync: this);
super.initState();
void dispose() {
super.dispose();
_tabController.dispose();
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Tab bar',
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
// give the tab bar a height [can change hheight to preferred height]
Container(
height: 45,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(
25.0,
child: TabBar(
controller: _tabController,
// give the indicator a decoration (color and border radius)
indicator: BoxDecoration(
color: Colors.green,
labelColor: Colors.white,
unselectedLabelColor: Colors.black,
tabs: [
// first tab [you can add an icon using the icon property]
Tab(
text: 'Place Bid',
// second tab [you can add an icon using the icon property]
text: 'Buy Now',
],
// tab bar view here
Expanded(
child: TabBarView(
// first tab bar view widget
Center(
child: Text(
'Place Bid',
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.w600,
// second tab bar view widget
'Buy Now',
);
atmip9wb2#
试试这个,你必须change一些colour和font:-
change
colour
font
import 'package:flutter/material.dart';typedef SwitchOnChange = Function(int);class CustomSwitch extends StatefulWidget { SwitchOnChange onChange; CustomSwitch({this.onChange}); @override State<StatefulWidget> createState() { return CustomSwitchState(); }}class CustomSwitchState extends State<CustomSwitch> with TickerProviderStateMixin { AnimationController controller; Animation animation; GlobalKey key = GlobalKey(); @override void initState() { Future.delayed(Duration(milliseconds: 100)).then((v) { controller = AnimationController( vsync: this, duration: Duration(milliseconds: 300)); tabWidth = key.currentContext.size.width / 2; // var width = (media.size.width - (2 * media.padding.left)) / 2; animation = Tween<double>(begin: 0, end: tabWidth).animate(controller); setState(() {}); controller.addListener(() { setState(() {}); }); }); super.initState(); } var selectedValue = 0; double tabWidth = 0; @override Widget build(BuildContext context) { return GestureDetector( onTap: () { selectedValue == 0 ? this.controller.forward() : controller.reverse(); selectedValue = selectedValue == 0 ? 1 : 0; }, child: Container( key: key, height: 44, decoration: BoxDecoration( color: Colors.grey, borderRadius: BorderRadius.circular(22)), child: Stack( children: <Widget>[ Row( children: <Widget>[ Transform.translate( offset: Offset(animation?.value ?? 0, 0), child: Container( height: 44, width: tabWidth, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(22), boxShadow: [ BoxShadow(color: Colors.grey, blurRadius: 3), ]), ), ), ], ), Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Container( width: tabWidth, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Icon(Icons.directions_walk), SizedBox(width: 5), Text("Place Bid") ], ), ), Container( width: tabWidth, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Icon(Icons.directions_walk), SizedBox(width: 5), Text("Buy now") ], ), ) ], ), ), ], ), ), ); }}
import 'package:flutter/material.dart';
typedef SwitchOnChange = Function(int);
class CustomSwitch extends StatefulWidget {
SwitchOnChange onChange;
CustomSwitch({this.onChange});
State<StatefulWidget> createState() {
return CustomSwitchState();
class CustomSwitchState extends State<CustomSwitch>
with TickerProviderStateMixin {
AnimationController controller;
Animation animation;
GlobalKey key = GlobalKey();
Future.delayed(Duration(milliseconds: 100)).then((v) {
controller = AnimationController(
vsync: this, duration: Duration(milliseconds: 300));
tabWidth = key.currentContext.size.width / 2;
// var width = (media.size.width - (2 * media.padding.left)) / 2;
animation = Tween<double>(begin: 0, end: tabWidth).animate(controller);
setState(() {});
controller.addListener(() {
});
var selectedValue = 0;
double tabWidth = 0;
return GestureDetector(
onTap: () {
selectedValue == 0 ? this.controller.forward() : controller.reverse();
selectedValue = selectedValue == 0 ? 1 : 0;
},
child: Container(
key: key,
height: 44,
color: Colors.grey, borderRadius: BorderRadius.circular(22)),
child: Stack(
children: <Widget>[
Row(
Transform.translate(
offset: Offset(animation?.value ?? 0, 0),
width: tabWidth,
color: Colors.white,
borderRadius: BorderRadius.circular(22),
boxShadow: [
BoxShadow(color: Colors.grey, blurRadius: 3),
]),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
Icon(Icons.directions_walk),
SizedBox(width: 5),
Text("Place Bid")
Text("Buy now")
)
wsewodh23#
您也可以使用PageView小工具。
const double borderRadius = 25.0;class CustomSwitchState extends StatefulWidget { @override _CustomSwitchStateState createState() => _CustomSwitchStateState();}class _CustomSwitchStateState extends State<CustomSwitchState> with SingleTickerProviderStateMixin { PageController _pageController; int activePageIndex = 0; @override void dispose() { _pageController.dispose(); super.dispose(); } @override void initState() { super.initState(); _pageController = PageController(); } @override Widget build(BuildContext context) { return Scaffold( body: SingleChildScrollView( physics: const ClampingScrollPhysics(), child: GestureDetector( onTap: () { FocusScope.of(context).requestFocus(FocusNode()); }, child: Container( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, child: Column( mainAxisSize: MainAxisSize.max, children: <Widget>[ Padding( padding: const EdgeInsets.only(top: 20.0), child: _menuBar(context), ), Expanded( flex: 2, child: PageView( controller: _pageController, physics: const ClampingScrollPhysics(), onPageChanged: (int i) { FocusScope.of(context).requestFocus(FocusNode()); setState(() { activePageIndex = i; }); }, children: <Widget>[ ConstrainedBox( constraints: const BoxConstraints.expand(), child: Center(child: Text("Place Bid"),), ), ConstrainedBox( constraints: const BoxConstraints.expand(), child: Center(child: Text("Buy Now"),), ), ], ), ), ], ), ), ), )); } Widget _menuBar(BuildContext context) { return Container( width: 300.0, height: 50.0, decoration: const BoxDecoration( color: Color(0XFFE0E0E0), borderRadius: BorderRadius.all(Radius.circular(borderRadius)), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ Expanded( child: InkWell( borderRadius: BorderRadius.all(Radius.circular(borderRadius)), onTap: _onPlaceBidButtonPress, child: Container( width: MediaQuery.of(context).size.width, padding: EdgeInsets.symmetric(vertical: 15), alignment: Alignment.center, decoration: (activePageIndex == 0) ? const BoxDecoration( color: Colors.green, borderRadius: BorderRadius.all(Radius.circular(borderRadius)), ) : null, child: Text( "Place Bid", style: (activePageIndex == 0) ? TextStyle(color: Colors.white) : TextStyle(color: Colors.black), ), ), ), ), Expanded( child: InkWell( borderRadius: BorderRadius.all(Radius.circular(borderRadius)), onTap: _onBuyNowButtonPress, child: Container( width: MediaQuery.of(context).size.width, padding: EdgeInsets.symmetric(vertical: 15), alignment: Alignment.center, decoration: (activePageIndex == 1) ? const BoxDecoration( color: Colors.green, borderRadius: BorderRadius.all(Radius.circular(borderRadius)), ) : null, child: Text( "Buy Now", style: (activePageIndex == 1) ? TextStyle(color: Colors.white, fontWeight: FontWeight.bold) : TextStyle(color: Colors.black, fontWeight: FontWeight.bold), ), ), ), ), ], ), ); } void _onPlaceBidButtonPress() { _pageController.animateToPage(0, duration: const Duration(milliseconds: 500), curve: Curves.decelerate); } void _onBuyNowButtonPress() { _pageController.animateToPage(1, duration: const Duration(milliseconds: 500), curve: Curves.decelerate); }}
const double borderRadius = 25.0;
class CustomSwitchState extends StatefulWidget {
_CustomSwitchStateState createState() => _CustomSwitchStateState();
class _CustomSwitchStateState extends State<CustomSwitchState> with SingleTickerProviderStateMixin {
PageController _pageController;
int activePageIndex = 0;
_pageController.dispose();
_pageController = PageController();
body: SingleChildScrollView(
physics: const ClampingScrollPhysics(),
child: GestureDetector(
FocusScope.of(context).requestFocus(FocusNode());
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
mainAxisSize: MainAxisSize.max,
Padding(
padding: const EdgeInsets.only(top: 20.0),
child: _menuBar(context),
flex: 2,
child: PageView(
controller: _pageController,
onPageChanged: (int i) {
setState(() {
activePageIndex = i;
ConstrainedBox(
constraints: const BoxConstraints.expand(),
child: Center(child: Text("Place Bid"),),
child: Center(child: Text("Buy Now"),),
));
Widget _menuBar(BuildContext context) {
return Container(
width: 300.0,
height: 50.0,
decoration: const BoxDecoration(
color: Color(0XFFE0E0E0),
borderRadius: BorderRadius.all(Radius.circular(borderRadius)),
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
child: InkWell(
onTap: _onPlaceBidButtonPress,
padding: EdgeInsets.symmetric(vertical: 15),
alignment: Alignment.center,
decoration: (activePageIndex == 0) ? const BoxDecoration(
) : null,
"Place Bid",
style: (activePageIndex == 0) ? TextStyle(color: Colors.white) : TextStyle(color: Colors.black),
onTap: _onBuyNowButtonPress,
decoration: (activePageIndex == 1) ? const BoxDecoration(
"Buy Now",
style: (activePageIndex == 1) ? TextStyle(color: Colors.white, fontWeight: FontWeight.bold) : TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
void _onPlaceBidButtonPress() {
_pageController.animateToPage(0,
duration: const Duration(milliseconds: 500), curve: Curves.decelerate);
void _onBuyNowButtonPress() {
_pageController.animateToPage(1,
输出
pod7payv4#
输出:
import 'package:flutter/material.dart';import 'package:icons_helper/icons_helper.dart';class DetailScreen extends StatefulWidget { var body; String title = ""; DetailScreen(this.body, this.title); @override _MainPageState createState() => _MainPageState();}class _MainPageState extends State<DetailScreen> with TickerProviderStateMixin { late int _startingTabCount; List<Tab> _tabs = <Tab>[]; List<Widget> _generalWidgets = <Widget>[]; late TabController _tabController; @override void initState() { _startingTabCount = widget.body["related_modules"].length; _tabs = getTabs(_startingTabCount); _tabController = getTabController(); super.initState(); } @override void dispose() { _tabController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), bottom: TabBar( isScrollable: true, tabs: _tabs, controller: _tabController, ), flexibleSpace: Container( decoration: BoxDecoration( gradient: LinearGradient( colors: [ Colors.grey, Colors.blue, ], stops: [0.3, 1.0], ), ), ), leading: IconButton( icon: Icon(Icons.arrow_back_ios), color: Colors.white, onPressed: () { Navigator.of(context, rootNavigator: true).pop(context); }, ), actions: <Widget>[ IconButton( icon: Icon(Icons.skip_previous), color: Colors.white, onPressed: () { goToPreviousPage(); }, ), Container( margin: EdgeInsets.only(right: 15), child: IconButton( icon: Icon(Icons.skip_next), color: Colors.white, onPressed: () { goToNextPage(); }, ), ) ], ), body: Column( children: <Widget>[ Expanded( child: TabBarView( physics: NeverScrollableScrollPhysics(), controller: _tabController, children: getWidgets(), ), ), ], ), ); } TabController getTabController() { return TabController(length: _tabs.length, vsync: this) ..addListener(_updatePage); } Tab getTab(int widgetNumber) { return Tab( icon: Column( children: [ if (widget.body["related_modules"][widgetNumber]["icon"].toString() == "fa-comments-o") ...[ Icon( Icons.comment_outlined, ), ] else if (widget.body["related_modules"][widgetNumber]["icon"] .toString() == "fa-map-marker") ...[ Icon( Icons.location_on_rounded, ), ] else if (widget.body["related_modules"][widgetNumber]["icon"] .toString() == "fa-address-card") ...[ Icon( Icons.contact_page_sharp, ), ] else ...[ Icon( getIconUsingPrefix( name: widget.body["related_modules"][widgetNumber]["icon"] .toString() .substring(3), ), ) ] ], ), text: widget.body["related_modules"][widgetNumber]["label"].toString(), ); } Widget getWidget(int widgetNumber) { return Center( child: Text("Widget nr: $widgetNumber"), ); } List<Tab> getTabs(int count) { _tabs.clear(); for (int i = 0; i < count; i++) { _tabs.add(getTab(i)); } return _tabs; } List<Widget> getWidgets() { _generalWidgets.clear(); for (int i = 0; i < _tabs.length; i++) { _generalWidgets.add(getWidget(i)); } return _generalWidgets; } void _updatePage() { setState(() {}); } //Tab helpers bool isFirstPage() { return _tabController.index == 0; } bool isLastPage() { return _tabController.index == _tabController.length - 1; } void goToPreviousPage() { _tabController.animateTo(_tabController.index - 1); } void goToNextPage() { isLastPage() ? showDialog( context: context, builder: (context) => AlertDialog( title: Text("End reached"), content: Text("This is the last page."))) : _tabController.animateTo(_tabController.index + 1); }}
import 'package:icons_helper/icons_helper.dart';
class DetailScreen extends StatefulWidget {
var body;
String title = "";
DetailScreen(this.body, this.title);
_MainPageState createState() => _MainPageState();
class _MainPageState extends State<DetailScreen> with TickerProviderStateMixin {
late int _startingTabCount;
List<Tab> _tabs = <Tab>[];
List<Widget> _generalWidgets = <Widget>[];
late TabController _tabController;
_startingTabCount = widget.body["related_modules"].length;
_tabs = getTabs(_startingTabCount);
_tabController = getTabController();
title: Text(widget.title),
bottom: TabBar(
isScrollable: true,
tabs: _tabs,
flexibleSpace: Container(
gradient: LinearGradient(
colors: [
Colors.grey,
Colors.blue,
stops: [0.3, 1.0],
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () {
Navigator.of(context, rootNavigator: true).pop(context);
actions: <Widget>[
IconButton(
icon: Icon(Icons.skip_previous),
goToPreviousPage();
margin: EdgeInsets.only(right: 15),
child: IconButton(
icon: Icon(Icons.skip_next),
goToNextPage();
body: Column(
physics: NeverScrollableScrollPhysics(),
children: getWidgets(),
TabController getTabController() {
return TabController(length: _tabs.length, vsync: this)
..addListener(_updatePage);
Tab getTab(int widgetNumber) {
return Tab(
icon: Column(
if (widget.body["related_modules"][widgetNumber]["icon"].toString() ==
"fa-comments-o") ...[
Icon(
Icons.comment_outlined,
] else if (widget.body["related_modules"][widgetNumber]["icon"]
.toString() ==
"fa-map-marker") ...[
Icons.location_on_rounded,
"fa-address-card") ...[
Icons.contact_page_sharp,
] else ...[
getIconUsingPrefix(
name: widget.body["related_modules"][widgetNumber]["icon"]
.toString()
.substring(3),
]
text: widget.body["related_modules"][widgetNumber]["label"].toString(),
Widget getWidget(int widgetNumber) {
return Center(
child: Text("Widget nr: $widgetNumber"),
List<Tab> getTabs(int count) {
_tabs.clear();
for (int i = 0; i < count; i++) {
_tabs.add(getTab(i));
return _tabs;
List<Widget> getWidgets() {
_generalWidgets.clear();
for (int i = 0; i < _tabs.length; i++) {
_generalWidgets.add(getWidget(i));
return _generalWidgets;
void _updatePage() {
//Tab helpers
bool isFirstPage() {
return _tabController.index == 0;
bool isLastPage() {
return _tabController.index == _tabController.length - 1;
void goToPreviousPage() {
_tabController.animateTo(_tabController.index - 1);
void goToNextPage() {
isLastPage()
? showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text("End reached"),
content: Text("This is the last page.")))
: _tabController.animateTo(_tabController.index + 1);
9jyewag05#
以下是我的变通方法,我认为这是最好的方法。
import 'package:flutter/material.dart';class SettingsScreen extends StatelessWidget { const SettingsScreen({ super.key, }); @override Widget build(BuildContext context) { return DefaultTabController( length: 2, child: Scaffold( appBar: AppBar( title: const Text('Settings'), bottom: PreferredSize( preferredSize: Size.fromHeight(AppBar().preferredSize.height), child: Container( height: 50, padding: const EdgeInsets.symmetric( horizontal: 20, vertical: 5, ), child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular( 10, ), color: Colors.grey[200], ), child: TabBar( labelColor: Colors.white, unselectedLabelColor: Colors.black, indicator: BoxDecoration( borderRadius: BorderRadius.circular( 10, ), color: Colors.pink, ), tabs: const [ Tab( text: 'Basic', ), Tab( text: 'Advanced', ) ], ), ), ), ), ), body: const TabBarView( children: [ Center( child: Text( 'Basic Settings', style: TextStyle( fontSize: 30, ), ), ), Center( child: Text( 'Advanced Settings', style: TextStyle( fontSize: 30, ), ), ), ], ), ), ); }}
class SettingsScreen extends StatelessWidget {
const SettingsScreen({
super.key,
return DefaultTabController(
length: 2,
child: Scaffold(
title: const Text('Settings'),
bottom: PreferredSize(
preferredSize: Size.fromHeight(AppBar().preferredSize.height),
height: 50,
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 5,
10,
color: Colors.grey[200],
color: Colors.pink,
tabs: const [
text: 'Basic',
text: 'Advanced',
body: const TabBarView(
'Basic Settings',
fontSize: 30,
'Advanced Settings',
5条答案
按热度按时间e5nszbig1#
您可以使用
TabBar
小部件来实现这一点,我添加了一个完整的示例来演示如何使用TabBar
小部件来创建它:atmip9wb2#
试试这个,你必须
change
一些colour
和font
:-wsewodh23#
您也可以使用PageView小工具。
输出

pod7payv4#
输出:
9jyewag05#
以下是我的变通方法,我认为这是最好的方法。