Here's a screenshot of a simple flutter app:
Pushing the ++/-- buttons adds/removes a panel to/from a Container. The container is outlined with a blue shadow.
Now, as soon as the container grows too close to the bottom border, it's shadow gets clipped on the left and right border.
Do you have any ideas what causes the clipping and how to avoid it?
This is how the code looks:
import 'package:flutter/material.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: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
ScrollController _scrollController;
#override
void initState() {
_scrollController = ScrollController();
super.initState();
}
#override
void dispose() {
_scrollController.dispose();
super.dispose();
}
void _incrementCounter() {
setState(() {
_counter++;
});
}
void _decrementCounter() {
setState(() {
if (_counter > 0) {
_counter--;
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: EdgeInsets.all(20),
child: ListView(
controller: _scrollController,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
SizedBox(height: 30),
_getButtonPanel(),
SizedBox(height: 20),
Container(
padding: EdgeInsets.all(20),
child: _getChildren(_counter),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(20)),
boxShadow: [
BoxShadow(
color: Colors.blue,
offset: Offset(0, 0),
blurRadius: 10.0,
spreadRadius: 5.0,
)
],
),
),
SizedBox(height: 20),
],
),
],
),
),
);
}
Widget _getButtonPanel() {
return Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
OutlineButton(
onPressed: _decrementCounter,
child: Text('--'),
),
Spacer(),
OutlineButton(
onPressed: _incrementCounter,
child: Text('++'),
),
],
);
}
Widget _getChildren(int cnt) {
List<Widget> children = [];
for (int i = 0; i < cnt; i++) {
children.add(_getItem(1 + i));
}
return Column(
children: children,
);
}
Widget _getItem(int i) {
return Column(
children: <Widget>[
SizedBox(
height: 50,
),
Text('Child panel $i'),
SizedBox(
height: 50,
),
],
);
}
}
You should add margin to the container containing the list to prevent it from clipping.
Container(
padding: EdgeInsets.all(20),
margin: EdgeInsets.all(15), //Add margin
child: _getChildren(_counter),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(20)),
boxShadow: [
BoxShadow(
color: Colors.blue,
offset: Offset(0, 0),
blurRadius: 10.0,
spreadRadius: 5.0,
)
],
),
);
Related
I want to make a custom tab widget and set a list of this widgets to a tab bar. But tab bar can't take all space and some space will remain. I try to wrap it with PreferredSize but it doesn't work .
The tab bar (ScrollTabBar) :
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.black54,
blurRadius: 5.0,
offset: Offset(0.0, 0.75),
),
],
borderRadius: BorderRadius.circular(widget.borderRadiusT),
color: Colors.red,
),
height: widget.tabHeight,
child: PreferredSize(
preferredSize: Size.fromHeight(widget.tabHeight),
child: TabBar(
indicator: UnderlineTabIndicator(
borderSide: BorderSide(
color: widget.indicatorColor,
width: widget.indicatorWheight,
),
insets: EdgeInsets.symmetric(
horizontal: widget.horizontalPadding,
),
),
indicatorWeight: widget.indicatorWheight,
indicatorColor: widget.indicatorColor,
labelPadding: EdgeInsets.only(
bottom: 0,
right: widget.horizontalPadding,
left: widget.horizontalPadding,
),
labelColor: widget.activeTextColor,
unselectedLabelColor: widget.diactiveTextColor,
controller: widget.tabController,
tabs: widget.tabList,
isScrollable: true,
),
),
),
Expanded(
child: TabBarView(
controller: widget.tabController,
children: [
for (var builder in widget.screenList) builder.call(context)
],
),
),
],
),
);
}
tabList is list of FTabComp :
FTabComp(
String title,
Key key,
ScrollTabBar parent, {
bool haveDivider = true,
}) {
return Tab(
key: key,
child: Container(
color: Colors.blue,
width: parent.tabLength,
child: Stack(
clipBehavior: Clip.none,
children: [
Align(
alignment: Alignment.center,
child: Text(title),
),
haveDivider
? Positioned.fill(
left: parent.tabLength * - 1.5,
child: SizedBox(
height: double.maxFinite,
child: VerticalDivider(
color: parent.outerBackgroundColor,
thickness: parent.dviderWidth,
),
),
)
: Center()
,
],
),
),
);
}
Container are red . Tabs are blue , if you solve this , I will say thank you.
Image
To make the TabBar use the maximum width of the screen you should remove the isScrollable property or set it to false. This way the TabBar is going to fill the entire width of the screen and resize each tab accordingly. From the docs, each tab gets an equal share of the available space). Also, the tabLength should be removed as it doesn't make sense anymore.
Now, the position of VerticalDivider should be calculated. It should take into account the screen width, the width of the tab, and also the padding between tabs. And it should be places in a Stack with the TabBar to make it the same height as the TabBar itself.
The algorithm to calculate the tab width can be something like this:
double width = MediaQuery.of(context).size.width;
double tabLength = (width -
horizontalPadding * (tabCount + 1) -
horizontalPadding * (tabCount - 1)) /
tabCount;
Below are the screenshots of the final result. Take a look also on the live demo on DartPad (Wait a little to run):
Small
Medium
Large
Take a look at the changed code below:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
late TabController tabController;
late TabController tabController2;
#override
void initState() {
// TODO: implement initState
super.initState();
tabController = TabController(length: 4, vsync: this);
tabController2 = TabController(length: 3, vsync: this);
}
#override
Widget build(BuildContext context) {
double horizontalPadding = 8;
return Scaffold(
body: ScrollTabBar(
tabController: tabController,
horizontalPadding: horizontalPadding,
tabList: const [
FTabComp(
title: 'secKey',
key: ValueKey('tab1'),
),
FTabComp(
title: 'firstKey',
key: ValueKey('tab2'),
),
FTabComp(
title: 'otherKey',
key: ValueKey('tab3'),
),
FTabComp(
title: 'anotherKey',
key: ValueKey('tab4'),
),
],
screenList: [
(context) => const Text('Tab 1'),
(context) => const Text('Tab 2'),
(context) => const Text('Tab 3'),
(context) => const Text('Tab 4'),
],
),
);
}
}
class ScrollTabBar extends StatefulWidget {
final double borderRadiusT;
final double tabHeight;
final Color indicatorColor;
final Color activeTextColor;
final Color diactiveTextColor;
final double indicatorWheight;
final double horizontalPadding;
final Color outerBackgroundColor;
final double dviderWidth;
final TabController? tabController;
final List<Widget> tabList;
final List<Widget Function(BuildContext)> screenList;
final bool haveDivider;
const ScrollTabBar({
Key? key,
this.borderRadiusT = 4,
this.tabHeight = 48,
this.indicatorColor = Colors.blue,
this.activeTextColor = Colors.black,
this.diactiveTextColor = Colors.white38,
this.indicatorWheight = 8,
this.horizontalPadding = 8,
required this.tabController,
required this.tabList,
required this.screenList,
this.outerBackgroundColor = Colors.black,
this.dviderWidth = 4,
this.haveDivider = true,
}) : super(key: key);
#override
State<ScrollTabBar> createState() => _ScrollTabBarState();
}
class _ScrollTabBarState extends State<ScrollTabBar> {
#override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double tabLength = (width -
widget.horizontalPadding * (widget.tabList.length + 1) -
widget.horizontalPadding * (widget.tabList.length - 1)) /
widget.tabList.length;
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
decoration: BoxDecoration(
boxShadow: const [
BoxShadow(
color: Colors.black54,
blurRadius: 5.0,
offset: Offset(0.0, 0.75),
),
],
borderRadius: BorderRadius.circular(widget.borderRadiusT),
color: Colors.red,
),
height: widget.tabHeight,
child: Stack(
children: [
TabBar(
indicator: UnderlineTabIndicator(
borderSide: BorderSide(
color: widget.indicatorColor,
width: widget.indicatorWheight,
),
insets: EdgeInsets.symmetric(
horizontal: widget.horizontalPadding,
),
),
indicatorWeight: widget.indicatorWheight,
indicatorColor: widget.indicatorColor,
labelPadding: EdgeInsets.only(
bottom: 0,
right: widget.horizontalPadding,
left: widget.horizontalPadding,
),
labelColor: widget.activeTextColor,
unselectedLabelColor: widget.diactiveTextColor,
controller: widget.tabController,
tabs: widget.tabList,
),
for (int i = 1; i < widget.tabList.length; i++)
Positioned.fill(
left: (widget.horizontalPadding + tabLength + widget.horizontalPadding) * i - (widget.dviderWidth / 2),
right: width,
child: SizedBox(
height: widget.tabHeight,
child: VerticalDivider(
color: widget.outerBackgroundColor,
thickness: widget.dviderWidth,
),
),
),
],
),
),
Expanded(
child: TabBarView(
controller: widget.tabController,
children: [
for (var builder in widget.screenList) builder.call(context)
],
),
),
],
),
);
}
}
class FTabComp extends StatelessWidget {
final String title;
const FTabComp({
Key? key,
required this.title,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Tab(
key: key,
child: Container(
color: Colors.blue,
child: Stack(
clipBehavior: Clip.none,
children: [
Align(
alignment: Alignment.center,
child: Text(title),
),
],
),
),
);
}
}
Inside the Stack, you use Positioned.fill. try removing it
I am trying to make a Bottom Navigation Bar that looks exactly like this. Since I'm just a beginner to learn flutter, I am having a lot of problems one of which is not able to find the icons so I decided to use other similarly available icons. Now I just confused with my own code.
This is what I want:
this is how my Bottom Navigation Bar looks:
This is my code:
Scaffold(bottomNavigationBar:
Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
height: 50,
width: MediaQuery.of(context).size.width / 5,
decoration: BoxDecoration(color:Color(0xfffed307)),
child: Column(
children: [
Icon(Icons.store_mall_directory_outlined),
Text('My Page')
],
),
),
Container(
height: 50,
width: MediaQuery.of(context).size.width / 5,
decoration: BoxDecoration(color: Color(0xfffed307)),
child: Column(
children: [Icon(Icons.apps), Text('Election')],
),
),
Container(
height: 50,
width: MediaQuery.of(context).size.width / 5,
decoration: BoxDecoration(color: Color(0xfffed307)),
child: Image.asset('images/scan_icon.png'),
),
Container(
height: 50,
width: MediaQuery.of(context).size.width / 5,
decoration: BoxDecoration(color: Color(0xfffed307)),
child: Column(
children: [Icon(Icons.apps), Text('Add Election')],
),
),
Expanded(
child: Container(
height: 50,
width: MediaQuery.of(context).size.width / 5,
decoration: BoxDecoration(color: Color(0xfffed307)),
child: Column(
children: [Icon(Icons.groups_outlined), Text('Customer')],
),
),
),
],
)
,);
You can use floatingActionButton for the scan icon and use floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
With Flutter, to make this kind of UI is easy peasy)) Use Positioned Widget inside Stack Widget if you really wanna make this UI using bottomNavigationBar property of Scaffold Widget.
Result UI
Copy and paste the code below to see the effect:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyScreen(),
);
}
}
class MyScreen extends StatefulWidget {
const MyScreen({Key? key}) : super(key: key);
#override
_MyScreenState createState() => _MyScreenState();
}
class _MyScreenState extends State<MyScreen> {
late List<Widget> _screens;
int currentIndex = 0;
#override
void initState() {
super.initState();
_screens = [
TestScreen(title: '1st Screen'),
TestScreen(title: '2nd Screen'),
TestScreen(title: '3rd Screen'),
TestScreen(title: '4th Screen'),
TestScreen(title: '5th Screen'),
];
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack(
index: currentIndex,
children: _screens,
),
bottomNavigationBar: BottomBar(
selectedIndex: currentIndex,
children: [
BottomBarItem(icon: Icons.home),
BottomBarItem(icon: Icons.search),
BottomBarItem(icon: Icons.favorite),
BottomBarItem(icon: Icons.person),
],
onMainPressed: () {
setState(() {
currentIndex = 4;
});
},
onPressed: (index) {
setState(() {
currentIndex = index;
});
},
),
);
}
}
class BottomBarItem {
BottomBarItem({required this.icon});
IconData icon;
}
class BottomBar extends StatelessWidget {
final List<BottomBarItem> children;
final Function? onPressed;
final Function? onMainPressed;
final selectedIndex;
BottomBar({
this.children = const [],
this.onPressed,
this.onMainPressed,
this.selectedIndex,
});
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Container(
color: Colors.grey[100],
child: SafeArea(
bottom: true,
child: Container(
height: 60,
decoration: BoxDecoration(
color: Colors.grey[100],
boxShadow: [
BoxShadow(
color: Colors.grey,
blurRadius: 8.0,
offset: Offset(
0.0, // horizontal, move right 10
-6.0, // vertical, move down 10
),
),
],
),
child: Stack(
clipBehavior: Clip.none,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: children.map<Widget>(
(item) {
int index = children.indexOf(item);
bool isSelected = selectedIndex == index;
return Expanded(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
onPressed!(index);
},
child: Padding(
padding: EdgeInsets.zero,
child: Icon(
item.icon,
size: isSelected ? 35 : 30,
color: isSelected ? Colors.blue : Colors.grey,
),
),
),
),
);
},
).toList()
..insert(2, SizedBox(width: 80)),
),
Positioned(
top: -14,
width: size.width,
child: Center(
child: Container(
height: 60,
width: 60,
child: ClipOval(
child: Material(
color: selectedIndex == 4 ? Colors.blue : Colors.grey,
child: InkWell(
onTap: () {
onMainPressed!();
},
child: Center(
child: Icon(
Icons.adb,
size: 27,
color: Colors.white,
),
),
),
),
),
decoration: BoxDecoration(
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.grey,
blurRadius: 6.0,
),
],
),
),
),
),
],
),
),
),
);
}
}
class TestScreen extends StatelessWidget {
final String title;
const TestScreen({required this.title, Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
child: Text(title),
)),
);
}
}
I have a Row with two Expanded widgets as its children. There is no space/padding between a children, therefore. Each of the children contains a Container (with box decoration), which in turn contains a FlatButton. When the FlatButton is highlighted, a BoxShadow appears around the Container.
For the second button, the shadow appears just fine, overflowing part of the first button. However, when the first button is being highlighted, the right side of the BoxShadow, which is supposed to be "over" the second button, gets clipped. I assume it's because the second button (and its respective ancestors) are after the first button in the widget tree, thus being "higher".
Here is the DartPad instance I made to demonstrate the issue: https://dartpad.dev/3e1eaa23c2848ada0104bded02e1510a
My question is essentially how I could achieve, with exactly the same layout, ie. no space between the buttons, that the shadow of each button appears over the other one. That is, the shadow of "Button1" in the example is the same as that of "Button2";
Thanks!
Hi You can check the edited code.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Generated App',
theme: new ThemeData(
primarySwatch: Colors.blue,
primaryColor: const Color(0xFF2196f3),
accentColor: const Color(0xFF2196f3),
canvasColor: const Color(0xFFfafafa),
),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('App Name'),
),
body: new Container(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Center(
child: new Row(
children: [
Expanded(
child: Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 5, 0),
child: Container(
decoration: BoxDecoration(boxShadow: [
BoxShadow(
color: Colors.transparent,
blurRadius: 5.0,
),
]),
child: TestButton("Button1")),
),
)),
Expanded(
child: Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 5, 0),
child: Container(
decoration: BoxDecoration(boxShadow: [
BoxShadow(
color: Colors.transparent,
blurRadius: 5.0,
),
]),
child: TestButton("Button2")),
),
))
],
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
))),
padding: const EdgeInsets.all(0.0),
alignment: Alignment.center,
),
);
}
}
class TestButton extends StatefulWidget {
#required
final String title;
TestButton(this.title);
#override
_TestButtonState createState() => _TestButtonState();
}
class _TestButtonState extends State<TestButton> {
bool isHighlighted = false;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
height: 50,
decoration: BoxDecoration(boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(isHighlighted ? 0.5 : 0.0),
spreadRadius: isHighlighted ? 5 : 0,
)
]),
child: FlatButton(
shape: ContinuousRectangleBorder(borderRadius: BorderRadius.zero),
splashColor: Colors.black12,
color: Colors.white,
hoverColor: Colors.black12,
highlightColor: Colors.black12,
mouseCursor: MouseCursor.uncontrolled,
child: Text(widget.title),
onPressed: () => null,
onHighlightChanged: (value) {
setState(() {
isHighlighted = value;
});
},
));
}
#override
void dispose() {
super.dispose();
}
}
this below code is simple dialog implementation to show and hide Container after click on button to show, that work fine, after click on dialog to hide container work too, now i want to show again container with Navigator.of(context).overlay, it doesn't work
full source code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(home: Home());
}
}
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Directionality(
textDirection: TextDirection.rtl,
child: Center(
child: RaisedButton.icon(
icon: Icon(Icons.notifications_active),
label: Text('Notify!'),
onPressed: () {
Navigator.of(context).overlay.insert(OverlayEntry(builder: (BuildContext context) {
return SlidingLayer();
}));
},
),
),
),
);
}
}
class SlidingLayer extends StatefulWidget {
#override
State<StatefulWidget> createState() => SlidingLayerState();
}
class SlidingLayerState extends State<SlidingLayer> with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<Offset> position;
#override
void initState() {
super.initState();
controller = AnimationController(vsync: this, duration: Duration(milliseconds: 750));
position = Tween<Offset>(begin: Offset(0.0, -14.0), end: Offset.zero).animate(CurvedAnimation(parent: controller, curve: Curves.ease));
controller.forward();
}
#override
Widget build(BuildContext context) {
return Material(
color: Colors.transparent,
child: Align(
alignment: Alignment.topCenter,
child: Padding(
padding: EdgeInsets.only(top: 90.0),
child: SlideTransition(
position: position,
child: Container(
margin: EdgeInsets.all(10.0),
height: 150.0,
width: double.infinity,
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(10.0), boxShadow: [
BoxShadow(
color: Colors.black26,
blurRadius: 0.9,
spreadRadius: 0.5,
offset: Offset(0.0, 0.0),
),
]),
child: InkWell(
onTap: (){
controller.reverse();
},
child: Center(
child: Text(
'ssss',
style: TextStyle(
fontSize: 26.0,
),
),
),
),
)),
),
),
);
}
}
I'm using an AnimatedContainer so that its height can adapt (with an animation) to the Tab's content present in it. I'm supposed to have access to the current index of the Tab with DefaultTabController.of(context).index and I'm transmitting this data to a function that will rebuild the widget depending on the current tab.
When I run the code, it displays me the error, but I don't understand : does it mean that DefaultTabController returns null ?
Here's the code :
import 'package:flutter/material.dart';
import 'package:travel_agent_app/loginForm.dart';
import 'package:travel_agent_app/registerForm.dart';
import 'package:travel_agent_app/bubble_tab_indicator.dart';
class Login extends StatefulWidget {
const Login({Key key}) : super(key: key);
_LoginState createState() => _LoginState();
}
class _LoginState extends State<Login> {
double _containerHeight = 300;
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
body: Container(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
SizedBox(
height: 150,
),
Container(
padding: EdgeInsets.only(left: 20.0, right:20.0),
child: Column(
children: <Widget>[
Container(
height: 52.0,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.all(Radius.circular(100.0))
),
child: TabBar(
indicatorSize: TabBarIndicatorSize.tab,
indicator: new BubbleTabIndicator(
indicatorHeight: 45.0,
indicatorColor: Colors.blueAccent,
tabBarIndicatorSize: TabBarIndicatorSize.tab),
labelColor: Colors.white,
unselectedLabelColor: Colors.black,
onTap: setAnimatedContainerHeight(DefaultTabController.of(context).index),
tabs: <Widget>[
Tab(text: 'Login'),
Tab(text: 'Register'),
],
),
),
SizedBox(
height: 20.0,
),
AnimatedContainer(
duration: Duration(seconds: 1),
padding: EdgeInsets.all(40.0),
width: double.infinity,
height: _containerHeight,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.0),
boxShadow: [
BoxShadow(
color: Colors.black12,
offset: Offset(0.0, 15.0),
blurRadius: 15.0),
]),
child: TabBarView(
children: <Widget>[
Container(
width: 500.0,
child: LoginForm(),
),
RegisterForm(),
],
)
),
],
),
)
],
),
)
)
)
);
}
setAnimatedContainerHeight(int index){
if(index == 0){
setState(() {
_containerHeight = 300;
});
}
else{
setState(() {
_containerHeight = 450;
});
}
}
}
The issue here is the DefaultTabController context is the same as in which DefaultTabController.of(context).index is defined.
To solve the error - you need to define DefaultTabController in the parent context.
Your code working:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: DefaultTabController( // Add here
child: Login(),
length: 2,
),
);
}
}
class Login extends StatefulWidget {
const Login({Key key}) : super(key: key);
_LoginState createState() => _LoginState();
}
class _LoginState extends State<Login> {
double _containerHeight = 300;
#override
Widget build(BuildContext context) {
return Scaffold( // Remove from here
body: Container(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
SizedBox(
height: 150,
),
Container(
padding: EdgeInsets.only(left: 20.0, right: 20.0),
child: Column(
children: <Widget>[
Container(
height: 52.0,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.all(Radius.circular(100.0))),
child: TabBar(
indicatorSize: TabBarIndicatorSize.tab,
indicator: new BubbleTabIndicator(
indicatorHeight: 45.0,
indicatorColor: Colors.blueAccent,
tabBarIndicatorSize: TabBarIndicatorSize.tab),
labelColor: Colors.white,
unselectedLabelColor: Colors.black,
onTap: setAnimatedContainerHeight(
DefaultTabController.of(context).index),
tabs: <Widget>[
Tab(text: 'Login'),
Tab(text: 'Register'),
],
),
),
SizedBox(
height: 20.0,
),
AnimatedContainer(
duration: Duration(seconds: 1),
padding: EdgeInsets.all(40.0),
width: double.infinity,
height: _containerHeight,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.0),
boxShadow: [
BoxShadow(
color: Colors.black12,
offset: Offset(0.0, 15.0),
blurRadius: 15.0),
]),
child: TabBarView(
children: <Widget>[
Container(
width: 500.0,
child: LoginForm(),
),
RegisterForm(),
],
)),
],
),
)
],
),
)));
}
setAnimatedContainerHeight(int index) {
if (index == 0) {
setState(() {
_containerHeight = 300;
});
} else {
setState(() {
_containerHeight = 450;
});
}
}
}
Or using FutureBuilder:
import 'package:flutter/material.dart';
import 'package:travel_agent_app/loginForm.dart';
import 'package:travel_agent_app/registerForm.dart';
import 'package:travel_agent_app/bubble_tab_indicator.dart';
class Login extends StatefulWidget {
const Login({Key key}) : super(key: key);
_LoginState createState() => _LoginState();
}
class _LoginState extends State<Login> {
double _containerHeight = 300;
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: FutureBuilder(
future: Future.delayed(Duration.zero),
builder: (BuildContext context, AsyncSnapshot snapshot) {
return Scaffold(
// ...
// The context within here is from FutureBuilder, which include DefaultTabController
// ...
);
},
),
);
}
setAnimatedContainerHeight(int index) {
if (index == 0) {
setState(() {
_containerHeight = 300;
});
} else {
setState(() {
_containerHeight = 450;
});
}
}
}