Custom dialog widget that scales height dynamically to child content - flutter

I want to build a custom dialog whose child is a widget displaying the HTML content. I'm struggling with making the dialog's height size to its child. Currently, I'm giving the container a fixed height as otherwise it would crash due to unbounded height for Column. The package i use to display HTML content: Easy Web View.
My code:
class CustomContentDialog extends StatelessWidget {
CustomContentDialog({required this.content});
final String content;
#override
Widget build(BuildContext context) {
return Center(
child: Material(
child: Container(
width: MediaQuery.of(context).size.width * 0.3,
height: MediaQuery.of(context).size.height * 0.8,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding:
const EdgeInsets.only(left: 24, bottom: 16, top: 16),
child: Text(
'Title',
),
),
IconButton(
onPressed: () {
Navigator.of(context).pop();
},
icon: const Icon(
Icons.close,
color: Colors.grey,
size: 20,
),
)
],
),
const Divider(
indent: 10,
endIndent: 10,
color: Color(0xFFE9E9E9),
),
Flexible(
fit: FlexFit.loose,
child: Padding(
padding: const EdgeInsets.only(left: 24.0),
child: EasyWebView(
src: src,
onLoaded: () {},
isHtml: true,
isMarkdown: false,
convertToWidgets: false,
key: const Key('HTML'),
),
),
),
],
),
),
),
);
}
}
What I've achieved so far:

Related

A widget in my SliverAppBar is causing a bottom overflow, how do i correct this in flutter?

I use a SliverAppBar and use flexibleSpace title instead of the default sliver title, on portrait mode, it is perfectly fine as shown :
But when i get to landscape mode it causes a bottom overflow by 13px, VScode tells me the renderflex is caused by a column.
This is how it looks like in landscape :
It is so messy that when i discovered this bug i couldn't continue coding until i fix this and this is what i've been trying to do :(
I will give my SliverAppBar code and also the widget used in the sliverapp flexibleSpace title as snippet below
I have tried using Expanded instead of Flexible, but it causes even more errors.
I also tried using some screen utility packages in pub.dev but seem like i don't use it properly.
Main view with sliverapp :
class HomeView extends GetView<HomeController> {
#override
Widget build(BuildContext context) {
controller.initScrollController();
return WillPopScope(
onWillPop: Helper().onWillPop,
child: Scaffold(
body: RefreshIndicator(
onRefresh: () async {
Get.find<LaravelApiClient>().forceRefresh();
controller.refreshHome(showMessage: true);
Get.find<LaravelApiClient>().unForceRefresh();
},
child: CustomScrollView(
physics: const AlwaysScrollableScrollPhysics(),
controller: controller.scrollController,
shrinkWrap: false,
slivers: <Widget>[
SliverAppBar(
backgroundColor: Color(0xffFFFFFF),
expandedHeight: MediaQuery.of(context).size.height * 0.18,
elevation: 0.5,
floating: false,
iconTheme: IconThemeData(color: Get.theme.primaryColor),
actions: [NotificationsButtonWidget()],
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.parallax,
title: MainProfileDetails(),//i suspect this is the widget causing the bug
),
),
SliverToBoxAdapter(
child: Wrap(
children: [
JobSummaryView(),
//BookingsListWidget(),
],
),
),
],
)),
),
);
}
}
MainProfileDetails() code:
class MainProfileDetails extends StatelessWidget {
const MainProfileDetails({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Obx(() {
return Padding(
padding: const EdgeInsets.only(left: 5.0),
child: Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Stack(
children: [
GestureDetector(
onTap: () {
Get.toNamed(Routes.PROFILE);
},
child: Container(
child: Stack(
children: [
SizedBox(
width: 60,
height: 60,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(80)),
child: CachedNetworkImage(
height: 100,
width: double.infinity,
fit: BoxFit.cover,
imageUrl: Get.find<AuthService>()
.user
.value
.avatar
.thumb,
placeholder: (context, url) => Image.asset(
'assets/img/loading.gif',
fit: BoxFit.cover,
width: double.infinity,
height: 80,
),
errorWidget: (context, url, error) =>
Icon(Icons.error_outline),
),
),
),
Positioned(
top: 35,
left: 30,
right: 0,
child: Get.find<AuthService>()
.user
.value
.verifiedPhone ??
false
? Icon(Icons.check_circle,
color: Color(0xffB0BEC1), size: 24)
: Icon(Icons.error_outline),
)
],
),
),
),
],
),
SizedBox(
width: 10,
),
Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Flexible(
flex: 2,
child: Padding(
padding: const EdgeInsets.only(left: 1.0),
child: Text(
'Hello, ${Get.find<AuthService>().user.value.name}',
style: GoogleFonts.poppins(
color: Color(0xff34495E), fontSize: 9),
),
),
),
Flexible(
flex: 2,
child: Padding(
padding: const EdgeInsets.only(top: 1.0, bottom: 1.0),
child: Text(
'Good Stitching',
style: GoogleFonts.poppins(
fontSize: MediaQuery.of(context).size.width * 0.04,
color: Color(0xff000000),
fontWeight: FontWeight.w600),
),
),
),
Flexible(
child: Container(
decoration: BoxDecoration(
color: Color(0xffeeeeee),
borderRadius: BorderRadius.circular(15),
),
child: Padding(
padding: const EdgeInsets.only(
top: 3.0, bottom: 3.0, left: 10.0, right: 10.0),
child: Get.find<AuthService>().user.value.verifiedPhone ??
false
? Text(
'Verified',
style: GoogleFonts.poppins(
fontSize:
MediaQuery.of(context).size.width * 0.025,
fontStyle: FontStyle.italic),
)
: Text(
'Unverified',
style: GoogleFonts.poppins(
fontSize:
MediaQuery.of(context).size.width * 0.025,
fontStyle: FontStyle.italic),
),
),
)),
],
),
//NotificationsButtonWidget(),
],
),
);
});
}
}
Please i need your time and assistance on this one. Thank you!
After many hours of asking for help here, i decided to go with simple AppBar in flutter as SliverAppBar flexibleSpace title is only customisable to a limit.
And that was goodbye to orientation issues.
Thanks everyone for your support.

Flutter: Space above Divider line is not the same as below

Here's my code:
import 'package:flutter/material.dart';
class HomePage extends StatelessWidget {
const HomePage({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF282B32),
body: Column(
children: <Widget>[
createRow(
context,
"https://i.stack.imgur.com/6Utrc.jpg?s=256&g=1",
"GuildProtect is a powerful, baterries-included moderation bot for your *safe* server!"
),
createDivider(),
createRow(
context,
"https://cdn.discordapp.com/avatars/967406876029501462/bd3c60dcf55c83fba41b15fba89f798a.webp?size=256",
"This is a very beatiful (because it's pink) avatar of this shitty website creator, enjoy!"
)
]
)
);
}
Row createRow(BuildContext context, String imageUrl, String text) {
const containerHeight = 256.0;
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
alignment: Alignment.centerLeft,
height: containerHeight,
padding: const EdgeInsets.only(left: 50, top: 25),
child: Image.network(imageUrl),
),
Container(
alignment: Alignment.centerRight,
height: containerHeight,
padding: const EdgeInsets.only(right: 50, top: 25),
child: Text(
text,
style: TextStyle(
color: const Color(0xFFFFFCF9),
fontWeight: FontWeight.bold,
fontSize: DefaultTextStyle.of(context).style.apply(fontSizeFactor: 1.3).fontSize,
),
),
),
]
);
}
Divider createDivider() {
return const Divider(
color: Color(0xFF131518),
indent: 30,
endIndent: 30,
thickness: 1,
height: 20,
);
}
}
Here's the result:
Result
It's becomes clear when looking at divider line near the images that space above divider and up to first image is not the same as space below divider and down to the second image.
I want to divider's height divide by 2 and take the same amount of space below and above divider. Any clue how to do it?
The padding is only applied on top
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
alignment: Alignment.centerLeft,
height: containerHeight,
padding: const EdgeInsets.only(left: 50, top: 25),
It would be better to include bottom as well.
padding: const EdgeInsets.only(left: 50, top: 25,bottom:25 ),
I will prefer wrapping the top row with padding widget in this case or using SizedBox/Padding around createDivider

Flutter: How can i put the text widget center in screen

I need to put the title' in the center even to fit any screen, I know can I sized box to move the title in the center, but when using the different device the dimensions surely will change and become the title the different places.
this is code :
class NotificationDoctor extends StatelessWidget {
TextStyles textStyles = TextStyles.HEADING;
Texts texts;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
decoration: BoxDecoration(
color: Theme.of(context).primaryColorDark,
borderRadius: BorderRadius.only(bottomLeft: Radius.circular(15.0))),
height: 130.h,
child: Padding(
padding: EdgeInsets.only(top: 40.h),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.only(
right: 15.w,
top: 15.h,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
FlatButton(
child: ArrowIcon(
arrowColor: Color(0xFFEEF4F9),
backgroundColor:
Theme.of(context).primaryColor.withOpacity(.9),
),
onPressed: () {
Navigator.pop(context);
},
),
// SizedBox(
// width: 55,
// ),
Center(
child: Texts(
'Notifications',
style: TextStyles.HEADING,
color: Color(0xFFEEF4F9),
),
),
],
),
),
],
),
),
),
));
}
}
use the padding like this
Padding(
padding: EdgeInsets.symmetric(vertical: 5.h, horizontal: 3.h),
child: Container(),
);
read more at https://pub.dev/packages/sizer

Flutter - material design 2 semi transparent appbar

I want to get effect like this - when scrolled up, appbar is transparent with listview visible below it:
And scrolled down, only white color - first item below appbar:
My window layout:
return Container(
color: AppTheme.nearlyWhite,
child: SafeArea(
top: false,
bottom: false,
child: Scaffold(
backgroundColor: AppTheme.nearlyWhite,
body: Stack(
children: <Widget>[
DrawerUserController(
screenIndex: _drawerIndex,
drawerWidth: MediaQuery.of(context).size.width * 0.75,
animationController: (AnimationController animationController) => _sliderAnimationController = animationController,
onDrawerCall: (DrawerIndex drawerIndexdata) => _onDrawerCall(drawerIndexdata, _forceRefresh),
onDrawerTap:(DrawerIndex drawerIndexdata) => _onDrawerTap(drawerIndexdata),
screenView: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(8, MediaQuery.of(context).padding.top + 8, 8, 8),
child: _createAppBar(),
),
Expanded(
child:
Container(
color: Colors.white,
child: _screenView,
)
),
],
),
),
new FabDialer(_fabMiniMenuItemList, Colors.blue, new Icon(Icons.add))
],
),
),
),
);
}
_screenView is simple Listview().builder() and it shows InkWell widget for each item. My appbar is custom, defined like this:
_createAppBar() {
return SizedBox(
height: AppBar().preferredSize.height,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 8, left: 8),
child: Container(
width: AppBar().preferredSize.height - 8,
height: AppBar().preferredSize.height - 8,
),
),
Expanded(
child: Center(
child: Padding(
padding: const EdgeInsets.only(top: 4),
child: Column(
children: <Widget>[
Text(
_menuSelected,
style: TextStyle(
fontSize: 22,
color: AppTheme.darkText,
fontWeight: FontWeight.w400,
),
),
Text(
globals.cityName,
style: TextStyle(
fontSize: 15,
color: AppTheme.darkerText,
fontWeight: FontWeight.w400,
),
),
],
),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 8, right: 8),
child: Container(
width: AppBar().preferredSize.height - 8,
height: AppBar().preferredSize.height - 8,
color: Colors.white,
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius:
BorderRadius.circular(AppBar().preferredSize.height),
child: Icon(Icons.refresh, color: AppTheme.dark_grey,),
onTap: () => setState(() => _forceRefresh = true),
),
),
),
),
],
),
);
}
That's how it looks now with first list item visible:
So, almost there, but when scrolled down, appbar won't be transparent:
I tried to mess around with setting my appbar backround to color with transparency, without success. Also I need to get my widgets actually overlapped (ListView needs to overlap my appbar) and it generates error messages from Flutter.
Any ideas how to do that properly?
set extendBodyBehindAppBar: true in Scaffold widget. Then use Opacity widget like this,
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: Home()));
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: PreferredSize(
preferredSize: const Size.fromHeight(kToolbarHeight),
child: Opacity( //Wrap your `AppBar`
opacity: 0.8,
child: AppBar(
title: Text("Demo"),
),
),
),
body: ListView.builder(
itemCount: 30,
itemBuilder: (context, index) {
return ListTile(
title: Text("Tile: $index"),
);
},
),
);
}
}
#override
Widget build(BuildContext context) {
return Container(
child: Stack(
children:[
Container(
color:Colors.white,
padding:EdgeInsets.all(10),
child:ListView.builder(
itemCount:25+1,
//length + 1 is beacause to show 1st item at the beginning
shrinkWrap:true,
itemBuilder:(con,ind){
return ind==0 ?
Container(height:70)
:ListTile(
title:Text('Item $ind',
style:TextStyle(color:Colors.black,))
);
}
)
),
Container(
height:70,
color:Colors.transparent,
child:Card(
color:Colors.white.withAlpha(80),
child: Row(
children:[
Expanded(
flex:1,
child: IconButton(
icon:Icon(Icons.list,color:Colors.black,size:25),
onPressed:(){
//todo
}
),
),
Expanded(
flex:3,
child: Text('Title',
style:TextStyle(color:Colors.black,)),
),
Expanded(
flex:1,
child: IconButton(
icon:Icon(Icons.search,color:Colors.black,size:25),
onPressed:(){
//todo
}
),
),
Expanded(
flex:1,
child: IconButton(
icon:Icon(Icons.more_vert,color:Colors.black,size:25),
onPressed:(){
//todo
}
),
)
]
),
)
)
]
)
);
}

What is best way to remove overflowing by a lot of pixels in Flutter?

I have Stepper in my app, and I have problems with placing textfield on screen, when I want to text some text in textfield, appears keyboard and over it shows me that:
A RenderFlex overflowed by 139 pixels on the bottom.
I read some articles and understood, that I have to use FittedBox, but I dunno how to use it with best way. How can I reach my goal?
Code:
#override
Widget build(BuildContext context) {
globalHeight = (MediaQuery.of(context).size.height) * 0.85;
return Scaffold(
body: AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.light,
child: Container(
decoration: BoxDecoration(color: colorsBackround[_currentPage]),
child: Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
height: globalHeight,
child: PageView(
physics: ClampingScrollPhysics(),
controller: _pageController,
onPageChanged: (int page) {
setState(() {
_currentPage = page;
});
},
children: <Widget>[
// some code
Padding(
padding: EdgeInsets.all(10.0),
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Image(
image: AssetImage(
itemIcon[_currentPage],
),
height: 300.0,
width: 300.0,
),
Text(
'Укажите ваш возраст',
style: kTitleStyle,
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.8,
height: 50.0,
child: Padding(
padding: EdgeInsets.only(
top: 20.0,
left: 20,
right: 20,
bottom: MediaQuery.of(context)
.viewInsets
.bottom),
child: TextField(
controller: ageController,
keyboardType: TextInputType.number,
onChanged: (text) {
setState(() {
if (text.isNotEmpty) {
inputs[1] = true;
} else {
inputs[1] = false;
}
});
},
decoration: InputDecoration(
labelText: 'Возраст',
),
style: TextStyle(fontSize: 18.5),
)),
),
],
),
),
),
//some code
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: _buildPageIndicator(),
),
_currentPage != _numPages - 1
? Expanded(
child: Container(
child: Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: Align(
alignment: FractionalOffset.bottomLeft,
child: FlatButton(
onPressed: () {
_pageController.previousPage(
duration: Duration(milliseconds: 500),
curve: Curves.ease,
);
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Icon(
Icons.arrow_back,
color: Colors.white,
size: 26.0,
),
SizedBox(width: 10.0),
Text(
'Назад',
style: TextStyle(
fontFamily: 'Century Gothic',
color: Colors.white,
fontSize: 14.5,
),
),
],
),
),
)),
Expanded(
child: Align(
alignment: FractionalOffset.bottomRight,
child: FlatButton(
onPressed: () {
_pageController.nextPage(
duration: Duration(milliseconds: 500),
curve: Curves.ease,
);
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Дальше',
style: TextStyle(
fontFamily: 'Century Gothic',
color: Colors.white,
fontSize: 14.5,
),
),
SizedBox(width: 10.0),
Icon(
Icons.arrow_forward,
color: Colors.white,
size: 26.0,
),
],
),
),
)),
],
)))
: Text(''),
],
),
),
),
),
bottomSheet: _currentPage == _numPages - 1
? Container(
height: 75.0,
width: double.infinity,
color: Theme.of(context).scaffoldBackgroundColor,
child: GestureDetector(
onTap: () => print('Get started'),
child: Center(
child: Padding(
padding: EdgeInsets.only(bottom: 15.0),
child: Text(
'Начать',
style: TextStyle(
fontFamily: 'Century Gothic',
color: Colors.white,
fontSize: 21.0,
fontWeight: FontWeight.bold,
),
),
),
),
),
)
: Text(''),
);
}
}
There is no direct solution to prevent overflowing issues, it depends on your current code. So, here you use
Add to your Scaffold
resizeToAvoidBottomInset: false
Wrap your widget in SingleChildScrollView
SingleChildScrollView(
child: YourColumn(),
)
That happens because when opening the keyboard, the body is resized to avoid the keyboard appear over the text field, and since your content isn't scrollable the content of the body gets overflowed. Check this property of the Scaffold:
/// If true the [body] and the scaffold's floating widgets should size
/// themselves to avoid the onscreen keyboard whose height is defined by the
/// ambient [MediaQuery]'s [MediaQueryData.viewInsets] `bottom` property.
///
/// For example, if there is an onscreen keyboard displayed above the
/// scaffold, the body can be resized to avoid overlapping the keyboard, which
/// prevents widgets inside the body from being obscured by the keyboard.
///
/// Defaults to true.
final bool resizeToAvoidBottomInset;
If you put that to false, the body won't be resized so the content won't be overflowed.
If you leave it as default, you need to make the body scrollable. In your case, you could change the root Column for a ListView and you will need to remove the Expanded wrap of the third item of the column.
But I recommend you to try to simplify the structure of the widgets.
Wrap your widget with a SingleChildScroll widget and that should work and solve the overflow issue