I’m encountering an issue with layout sizing in Flutter, specifically related to a parent widget using Expanded and its child layout not respecting the specified width.
Here’s the scenario:
I have a parent widget wrapped in an Expanded widget, which is intended to take up available space in its parent’s layout. Within this parent widget, I have a child widget (e.g., Container, SizedBox) to which I’m trying to assign a specific width using the width property. However, despite setting the width, the child layout does not appear to respect this constraint and expands to fill the available space within the parent widget.
Here’s the code:
class LoginScreen extends StatelessWidget {
const LoginScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: MColors.white,
body: Row(
children: [
if(Responsive.isDesktop(context))
Expanded(child: Container( width: 300, color: MColors.grey, child: const
OnBoardingScreen())),
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(MSizes.defaultSpace, MSizes.appBarHeight,
MSizes.defaultSpace, MSizes.defaultSpace),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: SingleChildScrollView(
child: SizedBox(
width: 300,
child: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"Welcome to",
style: Theme.of(context).textTheme.headlineMedium,
),
const SizedBox(width: MSizes.spaceBtwItems,),
const Image(image:
AssetImage("assets/logos/clean_pay.png"), width: 170, height: 60,)
],
),
const SizedBox(height: MSizes.spaceBtwItems,),
SizedBox(
width: double.infinity,
child: Text(
"Login to your Cleanpay account",
style: Theme.of(context).textTheme.bodyMedium,
),
),
const SizedBox(height: MSizes.spaceBtwItems,),
Form(
child: Column(
children: [
TextFormField(
//controller: _controller,
decoration: const InputDecoration(
hintText: 'Enter email',
),
),
const SizedBox(height: MSizes.spaceBtwItems,),
TextFormField(
//controller: _controller,
decoration: const InputDecoration(
hintText: 'Enter password',
),
),
],
)
),
const SizedBox(height: MSizes.spaceBtwItems,),
Container(
width: double.infinity,
alignment: Alignment.centerRight,
child: GestureDetector(
onTap: () => {
Get.to(const ForgetPasswordPhoneOrEmailScreen())
},
child: Text(
"Forget Password",
style:
Theme.of(context).textTheme.bodyMedium?.copyWith(color: MColors.info),
),
),
),
const SizedBox(height: MSizes.spaceBtwItems,),
SizedBox(
width: double.infinity,
child: ElevatedButton(
child: const Text(
'Login' ,
),
onPressed: () => {
Get.offAll(const NavigationMenu())
},
),
),
],
),
),
),
),
Column(
children: [
const Text("Didn't have the account yet ?"),
const SizedBox(height: MSizes.spaceBtwItems,),
SizedBox(
width: double.infinity,
child: OutlinedButton(
onPressed: () {
Get.offAll(() => const SignupScreen(), transition:
Transition.cupertino, duration: const Duration(seconds: 1));
},
child: const Text("Sign up"),
),
)
]
),
]
),
),
),
],
),
);
}
}
class OnBoardingScreen extends StatefulWidget {
const OnBoardingScreen({super.key});
@override
OnBoardingScreenState createState() => OnBoardingScreenState();
}
class OnBoardingScreenState extends State<OnBoardingScreen> {
final introKey = GlobalKey<IntroductionScreenState>();
Widget _buildImage(String assetName, [double width = 350]) {
return Image.asset('assets/logos/splash_logo_light.png', width: width);
}
@override
Widget build(BuildContext context) {
// Variables
final deviceStorage = GetStorage();
final authenticationRepository = Get.find<AuthenticationRepository>();
const bodyStyle = TextStyle(fontSize: 19.0);
const pageDecoration = PageDecoration(
titleTextStyle: TextStyle(fontSize: 28.0, fontWeight: FontWeight.w700),
bodyTextStyle: bodyStyle,
bodyPadding: EdgeInsets.fromLTRB(16.0, 0.0, 16.0, 16.0),
pageColor: MColors.softGrey,
imagePadding: EdgeInsets.zero,
);
return IntroductionScreen(
key: introKey,
globalBackgroundColor: MColors.softGrey,
allowImplicitScrolling: true,
infiniteAutoScroll: false,
globalFooter: !Responsive.isDesktop(context) ? Container(
width: double.infinity,
margin: const EdgeInsets.all(MSizes.defaultSpace),
child: ElevatedButton(
child: const Text(
'Let's go right away!' ,
),
onPressed: () => {
deviceStorage.write("isFirstTime", false),
authenticationRepository.screenRedirect()
},
),
) : null,
pages: [
PageViewModel(
title: "Fractional shares",
body:
"Instead of having to buy an entire share, invest any amount you want.",
image: _buildImage('img1.jpg'),
decoration: pageDecoration,
),
PageViewModel(
title: "Learn as you go",
body:
"Download the Stockpile app and master the market with our mini-lesson.",
image: _buildImage('img2.jpg'),
decoration: pageDecoration,
),
PageViewModel(
title: "Kids and teens",
body:
"Kids and teens can track their stocks 24/7 and place trades that you approve.",
image: _buildImage('img3.jpg'),
decoration: pageDecoration,
),
PageViewModel(
title: "Full Screen Page",
body:
"Pages can be full screen as well.nnLorem ipsum dolor sit amet, consectetur
adipiscing elit. Nunc id euismod lectus, non tempor felis. Nam rutrum rhoncus est ac
venenatis.",
image: _buildImage('img3.jpg'),
decoration: pageDecoration,
),
PageViewModel(
title: "Another title page",
body: "Another beautiful body text for this example onboarding",
image: _buildImage('img2.jpg'),
decoration: pageDecoration,
),
PageViewModel(
title: "Title of last page - reversed",
bodyWidget: const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Click on ", style: bodyStyle),
Icon(Icons.edit),
Text(" to edit a post", style: bodyStyle),
],
),
decoration: pageDecoration,
image: _buildImage('img1.jpg'),
),
],
showSkipButton: false,
showDoneButton: false,
skipOrBackFlex: 0,
nextFlex: 0,
showBackButton: false,
showNextButton: false,
//rtl: true, // Display as right-to-left
next: const Icon(Icons.arrow_forward),
curve: Curves.fastLinearToSlowEaseIn,
controlsPadding: kIsWeb
? const EdgeInsets.all(12.0)
: const EdgeInsets.fromLTRB(8.0, 4.0, 8.0, 4.0),
dotsDecorator: const DotsDecorator(
size: Size(10.0, 10.0),
activeColor: MColors.secondary,
activeSize: Size(22.0, 10.0),
activeShape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(25.0)),
),
),
);
}
}