Reputation: 53
I am trying to use CupertinoSegmentedControl
from the flutter Cupertino library in the AppBar
using the bottom attribute to achieve the following design (height = 32)
so I tried the following :
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 2,
backgroundColor: Colors.white,
centerTitle: true,
title: Text(this.widget.title, style: TextStyle(color: Colors.black)),
bottom: PreferredSize(
child: Padding(
padding: const EdgeInsets.only(top: 8, bottom: 12),
child: Row(
children: <Widget>[
SizedBox(width: 24),
Expanded(
child: CupertinoSegmentedControl(
children: this.widget.tabs,
groupValue: this._selectedTab,
onValueChanged: (value) {
this.setState(() => this._selectedTab = value);
this._tabController.animateTo(value);
}
),
),
SizedBox(width: 24)
],
),
),
preferredSize: Size(double.infinity, 48)
)
),
body: new TabBarView(
controller: this._tabController,
children: this.widget.views,
));
}
Upvotes: 5
Views: 10918
Reputation: 1964
Here is full example based on @shadowsheep 's answer but improve version.
my_cupertino_segmented_control.dart
class MyCupertinoSegmentedControl extends StatelessWidget {
final Map<int, Widget> children;
final int? groupValue;
final Function(int)? onValueChanged;
const MyCupertinoSegmentedControl(
{required this.children,
this.groupValue,
this.onValueChanged,
super.key});
@override
Widget build(BuildContext context) {
return PreferredSize(
preferredSize: const Size(double.infinity, 48),
child: Padding(
padding: const EdgeInsets.only(top: 8, bottom: 12),
child: Row(
children: <Widget>[
const SizedBox(width: 24),
Expanded(
child: CupertinoSegmentedControl<int>(
children: children,
groupValue: groupValue,
onValueChanged: (value) {
onValueChanged?.call(value);
}),
),
const SizedBox(width: 24)
],
),
));
}
}
It wrapped the annoying details to a simple widgets.
example.dart
import 'package:flutter/cupertino.dart';
import 'package:my_project/views/my_cupertino_segmented_control.dart';
class HomePageScaffold extends StatelessWidget {
const HomePageScaffold({super.key});
@override
Widget build(BuildContext context) {
return const CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('Segmented Control Example'),
),
child: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<StatefulWidget> createState() {
return HomePageState();
}
}
class HomePageState extends State<HomePage> {
Map<int, Widget> segmentedWidgets = {};
List<Widget> tabWidgets = [];
int selectedIndex = 0;
@override
void initState() {
super.initState();
_loadSegmentedWidgets();
_loadTabWidgets(); //Method to add the Children as user selected.
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Column(
children: <Widget>[
MyCupertinoSegmentedControl(
children: segmentedWidgets,
groupValue: selectedIndex,
onValueChanged: (value) {
setState(() {
selectedIndex = value;
});
}),
tabWidgets[selectedIndex],
],
),
);
}
void _loadSegmentedWidgets() {
for (int i = 0; i < 4; i++) {
segmentedWidgets[i] = Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Tab ${i + 1}"),
);
}
}
void _loadTabWidgets() {
for (int i = 0; i < 4; i++) {
tabWidgets.add(
Center(
child: Text("Detail ${i + 1}"),
),
);
}
}
}
It's initialize the CupertinoPageScaffold
and 4 tabs with tab details.
Here's preview
Upvotes: 0
Reputation: 954
just add Padding widget, or margin property to Container and wrap your Widgets in your "tabs" collection (in you case it is this.widget.tabs) with it
in my case
CupertinoSegmentedControl<int>(
children: segmentTextWidgets,
...
),
final Map<int, Widget> segmentTextWidgets = <int, Widget>{
0: Container(
margin: const EdgeInsets.symmetric(vertical: 16),
child: Text("Tab 1 title"),
),
1: Container(
margin: const EdgeInsets.symmetric(vertical: 16),
child: Text("Tab 2 title"),
),
};
Upvotes: 5
Reputation: 15002
Is something like that similar to the layout that you want? (Removing the green color of course ^_^)
Play around with the Container
and PreferredSize
heights to adjust the height to fit your needs.
Scaffold(
appBar: AppBar(
elevation: 2,
backgroundColor: Colors.white,
centerTitle: true,
title:
Text(this.widget.title, style: TextStyle(color: Colors.black)),
bottom: PreferredSize(
child: Row(
children: [
Expanded(
child: Container(
height: 48,
color: Colors.lightGreenAccent,
child: CupertinoSegmentedControl(
children: children,
groupValue: this._selectedTab,
onValueChanged: (value) {
this.setState(() => this._selectedTab = value);
}),
),
)
],
),
preferredSize: Size(double.infinity, 48))),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('hello')
]
)
)
);
UPDATE:
As kazimad pointed out, if you want to increase the segmented control height and not only add padding to it insiede the app bar, you can add a Padding
widget to your tabs, like that:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 2,
backgroundColor: Colors.white,
centerTitle: true,
title:
Text(this.widget.title, style: TextStyle(color: Colors.black)),
bottom: PreferredSize(
child: Padding(
padding: const EdgeInsets.only(top: 8, bottom: 12),
child: Row(
children: <Widget>[
SizedBox(width: 24),
Expanded(
child: CupertinoSegmentedControl(
children: const <int, Widget>{
0: Padding(
padding: EdgeInsets.all(8.0),
child: Text('Midnight')),
1: Padding(
padding: EdgeInsets.all(8.0),
child: Text('Viridian')),
2: Padding(
padding: EdgeInsets.all(8.0),
child: Text('Cerulean'))
},
groupValue: this._selectedTab,
onValueChanged: (value) {
// TODO: - fix it
}),
),
SizedBox(width: 24)
],
),
),
preferredSize: Size(double.infinity, 48))),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [Text('hello')])));
}
Upvotes: 6