I'm thinking about making different layout for Tablet/iPad version but I'm new to Flutter so I'm not really sure how to make it. I'll be really appreciated if I can get any suggestion on how to do it.
Right now If I run on Tablet, my cards are stretch out and I'm trying to fix it right now. Also I'm trying to add a divider and column on the right side (attached pic of the design below) so that I can add more text.
This is my cards
Widget build(BuildContext context) {
return Container(
height: 180,
child: SingleChildScrollView(
child: Card(
elevation: 8.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: Column(children: [
Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 10,0),
child: Row(children: [
Text(
title,
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
Spacer(),
Container(
child: IconButton(
icon: Icon(Icons.favorite),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context)=> DetailsPage("Favorite")));
},
))
]),
),
Divider(color: Colors.black),
Row(children: [
//Legend
tileWidget(TileItem(
topText: "Top",
middleText: "Middle",
bottomText: "Bottom")),
Container(
color: Colors.red,
height: 60, width: 2),
(tileItems.length < 1) ? null : tileWidget(tileItems[0]),
Container(
color: Colors.green,
height: 60, width: 2),
(tileItems.length < 2) ? null : tileWidget(tileItems[1]),
Container(
color: Colors.black26, height: 60, width: 2),
(tileItems.length < 3) ? null : tileWidget(tileItems[2])
]),
]),
),
),
);
}
To get the screen width, use MediaQuery.of(context).size.width
Make a widget for any width under 600dp (ie. the phone) and another for any width above (ie. the tablet).
Then your code will look something like this:
body: OrientationBuilder(builder: (context, orientation) {
if (MediaQuery.of(context).size.width > 600) {
isTablet= true;
} else {
isTablet= false;
} etc...
}
Here is a helpful resource: https://medium.com/flutter-community/developing-for-multiple-screen-sizes-and-orientations-in-flutter-fragments-in-flutter-a4c51b849434
Related
I'm building an AR app with Flutter and using the ar_flutter_plugin.
The position of the AR widget seems to be fixed to the top left and it doesn't move anywhere else. Whatever the other widgets in the tree, doesn't change anything. It's always at top left corner (see image).
It works with a dummy widget just fine (compare second img).
Child Ar widget
Widget build(BuildContext context) {
return SizedBox(
width: widget.width,
height: widget.height,
child: Column(
children: [
Expanded(
child: Column(children: [
Expanded(
child: ARView(
onARViewCreated: onARViewCreated,
planeDetectionConfig:
PlaneDetectionConfig.horizontalAndVertical,
),
),
Align(
alignment: Alignment(1, 1),
child: FloatingActionButton(onPressed: takePicture))
]),
),
],
));
}
Parent Widget
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Title'),
),
key: scaffoldKey,
backgroundColor: FlutterFlowTheme.of(context).primaryBackground,
body: SafeArea(
child: GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Stack(
children: [
Container(
width: 350,
height: 350,
child: ObjectsOnPlanesWidget(
// child: custom_widgets.ArPlaceholder(
width: double.infinity,
height: double.infinity,
modelUrl: widget.modelUrl,
),
),
Align(
alignment: AlignmentDirectional(-0.23, -0.92),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(8, 24, 8, 24),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
width: 30,
height: 30,
decoration: BoxDecoration(
color:
FlutterFlowTheme.of(context).secondaryBackground,
borderRadius: BorderRadius.circular(12),
),
child: InkWell(
onTap: () async {
Navigator.pop(context);
},
child: Icon(
Icons.chevron_left,
color: Colors.black,
size: 24,
),
),
),
Text(
'Try On',
style: FlutterFlowTheme.of(context).bodyText1,
),
Container(
width: 30,
height: 30,
decoration: BoxDecoration(
color:
FlutterFlowTheme.of(context).secondaryBackground,
borderRadius: BorderRadius.circular(12),
),
child: Icon(
Icons.share_outlined,
color: Colors.black,
size: 24,
),
),
],
),
),
),
Align(
alignment: AlignmentDirectional(0, 0.95),
child: Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: FlutterFlowTheme.of(context).secondaryBackground,
borderRadius: BorderRadius.circular(12),
),
child: Icon(
Icons.photo_camera,
color: Colors.black,
size: 24,
),
),
),
],
),
),
),
);
}
I want to put the camera in the background and put other widgets (such as photo-taking-button) on top of it.
How do I reposition it into a container? At least under the App Bar?
Logically this should have worked, what i would suggest you try would be to first have a SafeArea widget.
SafeArea(
child: build(buildContext),
),
I had a similar issue in the past and using this solved it.
Also, there seems to be an open issue which seems related to this with the following possible solution :
With Flutter 2.10.5. it works without problems. This seems to be a Flutter 3 problem.
The way platforms views are rendered was changed in the 3.0 release.
probably same issue:
flutter/flutter#106246
explained here:
flutter/flutter#103630
I hope this will be fixed in new Flutter 3 releases soon.
And also this
I try the master channel Flutter v3.1.0-0.0.pre.1372 and the issue is fixed there.
Fixed will come to a stable channel soon with Flutter v3.1.0.
Also, I am not sure why are you using SizedBox as your parent widget.
Why not try a basic Container instead?
Good luck, Let me know if I can help with anything else
I am tasked with the challenge of getting a black banner to show when a user returns from a screen on that same tab upon ordering an item on another screen. The current code below only shows the black banner appropriately if the user leaves by selecting another tab then returns to the screen. The part that I need to be dynamically presented starts with "if (OrderProvider.listOrderSummary.isNotEmpty)". I believe that this involves making a stateless widget stateful, but that results in errors that suggest that may not be the right approach.
class GridItems extends StatelessWidget {
GridItems({#required this.infinityPageController});
final InfinityPageController infinityPageController;
#override
Widget build(BuildContext context) {
final List<Item> itemList = Provider.of<List<Item>>(context);
if (itemList == null) {
return Center(
child: CupertinoActivityIndicator(
radius: 20,
),
);
}
final List<Item> mapItemList = itemList.toList();
return Column(
children: <Widget>[
TopMenuNavigation(
infinityPageController: infinityPageController,
title: 'ALL ITEMS',
),
Divider(
color: Colors.grey,
),
Expanded(
child: GridView.builder(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemCount: itemList.length,
itemBuilder: (BuildContext contex, int index) {
return Center(
child: InkWell(
onTap: () {
Navigator.of(context)
.pushNamed('/order', arguments: mapItemList[index]);
},
child: Container(
width: 310,
margin: EdgeInsets.all(7),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(width: 1, color: Colors.grey),
borderRadius: BorderRadius.all(
Radius.circular(7.0),
),
),
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.only(left: 10, top: 10),
width: double.infinity,
child: Text('${mapItemList[index].itemName}'),
),
Expanded(
child: Image.network(
'${mapItemList[index].imageUrl}',
),
),
],
),
),
),
);
},
),
),
if (OrderProvider.listOrderSummary.isNotEmpty)
GestureDetector(
onTap: () {
Navigator.of(context).pushNamed('/review_order');
},
child: Container(
height: 55,
color: Colors.black,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Spacer(),
Text(
'REVIEW ORDER (${OrderProvider.listOrderSummary.length} items)',
style: TextStyle(
fontSize: 17,
color: Colors.white,
fontFamily: 'OpenSans',
fontWeight: FontWeight.bold),
),
SizedBox(width: 8),
Icon(
Icons.navigate_next,
color: Colors.white,
size: 35,
),
SizedBox(
width: MediaQuery.of(context).size.height * 0.065,
),
],
),
),
)
else
SizedBox(),
],
);
}
}
You have to somehow rebuild your screen (or part of it) where you want to return to. This is where a state-management solution should come into place :).
Create a BLoC or a ValueNotifier and rebuild the widget with a StreamBuilder or a ValueListenableBuilder. If you want to make it simple just create a shared state inside a stateful widget between your tab screens and call setState if the black banner should appear
Can someone help me get this layout with the first circle over the second?
image
I have this function:
Widget overlapped() {
final overlap = 25;
final items = [
Container(
padding: EdgeInsets.only(right: 2),
decoration: new BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
),
child: CircleAvatar(
radius: 22,
backgroundImage: AssetImage('assets/example_logo.png'),
backgroundColor: Colors.black,
),
),
CircleAvatar(
radius: 22,
backgroundColor: Colors.white,
child: ClipOval(
child: Image.network(
"https://upload.wikimedia.org/wikipedia/commons/thumb/5/53/Google_%22G%22_Logo.svg/1200px-Google_%22G%22_Logo.svg.png",
errorBuilder: (context, exception, stackTrace) {
return Container(color: Colors.white);
},
height: 35,
))),
CircleAvatar(
child: Text('+2', style: TextStyle(color: Colors.white)),
backgroundColor: Theme.of(context).canvasColor),
];
List<Widget> stackLayers = List<Widget>.generate(items.length, (index) {
return Container(
padding: EdgeInsets.fromLTRB(index.toDouble() * overlap, 0, 0, 0),
child: items[index],
);
});
return Stack(children: stackLayers);
}
This function whenever I add an item to the array, it adds a widget on the right. But I want the first to be above the second, the second of the third, etc ...
you could use the Stack widget :
Stack(
children:<Widget>:[
Positioned(
right: 130.0,
child:Container(
shape: BoxShape.circle,
)
),
Positioned(
left: 130.0,
child:Container(
shape: BoxShape.circle,
)
),
]
)
Use Stack and Positioned together.
import 'package:flutter/material.dart';
class OverLap extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Overlap'),
),
body: Container(
padding: const EdgeInsets.all(8.0),
width: 500.0,
child: Stack(
children: <Widget>[
//Change according to your icon
Icon(
Icons.flaky,
size: 50.0,
color: Colors.red,
),
Positioned(
left: 20.0,
//Change according to your icon
child: Icon(
Icons.flaky,
size: 50.0,
color: Colors.blue,
),
),
],
),
),
);
}
}
I want to have more(in this example 4) items in Row. I tried use Expanded or Flexible or mainAxisAlignment: MainAxisAlignment.spaceEvenly to fill up all width of screen. But I want to heve items lets say specific width and height 50 pixels, and GestureDetector which is around item to be 1/4 of screen(4 items = full width). So everywhere I tap in the row something will be selected. My problem is that every my solution deforms items(circles) or circle must be very huge to width = height to not be deformed.
I also tried wrapping whole _ratingEmoji in Expanded and giving ratingItem.ratingIndicator constraints to max width but with same result.
Row of items:
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
for (var ratingItem in editGroceryRatingProvider.foodRatings)
_ratingEmoji(editGroceryRatingProvider, ratingItem, context),
],
),
Item:
Widget _ratingEmoji(EditGroceryRatingProvider editGroceryRatingProvider,
SelectedFoodRating ratingItem, BuildContext context) {
return GestureDetector(
child: ratingItem.selected
? Container(
width: MediaQuery.of(context).size.width / 8,
height: MediaQuery.of(context).size.width / 8,
padding: const EdgeInsets.all(2.0),
decoration: BoxDecoration(
border: Border.all(
color: Color(0xFF312ADB),
width: 3.0,
),
borderRadius: BorderRadius.circular(32.0)),
child: Center(
child: ratingItem.ratingIndicator,
),
)
: ratingItem.ratingIndicator,
onTap: () => editGroceryRatingProvider.updateSelectedRating(ratingItem),
);
}
RatingIndicator which is "circle" item to be on the screen:
Container(
decoration: BoxDecoration(
border: Border.all(
color: color,
width: 1.5,
),
borderRadius: BorderRadius.circular(64.0),
),
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.white,
width: 3.0,
),
borderRadius: BorderRadius.circular(64.0),
),
child: ClipOval(
child: Container(
width: width ?? MediaQuery.of(context).size.width / 7,
height: height ?? MediaQuery.of(context).size.width / 7,
color: color,
),
),
),
);
Thanks a lot.
Update:
Items should stay as they are on screenshot, but "whole" row should be clickable(means even if you click between 2 items, one closer to click should be selected)
Check, please solution.
The whole area is clickable. You just need to add your item instead of mine.
#override
Widget build(BuildContext context) {
final colors = [Colors.red, Colors.blue, Colors.brown, Colors.cyan];
return Scaffold(
body: Container(
alignment: Alignment.center,
color: const Color(0xffFAFAFA),
child: Row(
children: List.generate(
colors.length,
(index) => Expanded(
child: GestureDetector(
onTap: () => print('Tapped:$index'),
child: Container(
height: 50,
color: Colors.transparent,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: colors[index],
),
),
)),
)),
),
),
);
I'm kinda confused with how responsive layouts are made with flutter can you guys point me to the right direction or where in my codes will be wrapped in Expanded widget?
I tried wrapping the containers with Extended but It keeps showing an error and I'm getting confused now. I'm still a beginner, to be honest. Thank you very much!
Also, when I searched I found out that I should avoid using hardcoded sizes most of the time. So I want to learn when to apply Extended widget in order to make my screen responsive.
my code is below:
import 'package:flutter/material.dart';
class RegisterPage extends StatefulWidget {
RegisterPage({Key key}) : super(key: key);
#override
_RegisterPageState createState() => _RegisterPageState();
}
class _RegisterPageState extends State<RegisterPage> {
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: Color(0xff0D192A),
body: Container(
child: ListView(
children: <Widget>[
Column(
children: <Widget>[
Padding(
padding: EdgeInsets.all(10.0),
child: Container(
height: 200,
width: 200,
child: Image(
image: AssetImage("assets/images/vlogo.png"),
),
),
),
Padding(
padding: EdgeInsets.all(40.0),
child: Center(
child: Text("Register an Account",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 20)),
)),
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Text("Email Address",
style: TextStyle(
fontSize: 10.0, color: Colors.grey[400])),
],
),
],
),
),
SizedBox(height:10.0),
Container(
margin: EdgeInsets.fromLTRB(20, 0, 20, 0),
padding: EdgeInsets.all(5.0),
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(10),
),
child: Center(
child: Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Enter your email address",
hintStyle: TextStyle(color: Colors.grey[400]),
),
),
),
)
),
SizedBox(height:20.0),
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Text("Choose Password",
style: TextStyle(
fontSize: 10.0, color: Colors.grey[400])),
],
),
],
),
),
SizedBox(height:10.0),
Container(
margin: EdgeInsets.fromLTRB(20, 0, 20, 0),
padding: EdgeInsets.all(5.0),
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(10),
),
child: Center(
child: Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Enter your email address",
hintStyle: TextStyle(color: Colors.grey[400]),
),
),
),
)
),
SizedBox(height: 50),
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 20, 0),
child: InkWell(
onTap: () {
setState(() {
});
},
child: Container(
height: 50,
decoration: BoxDecoration(
color: Color.fromRGBO(211, 184, 117, 100)
),
child: Center(
child: Text("Login", style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 20),
),
),
),
),
),
],
),
],
),
),
),
);
}
}
Explore this plugin: This is one of the most effective plugins I have ever used for making responsive design.
https://pub.dev/packages/responsive_screen
Or
Use MediQuery() for getting the screen height and width i.e:-
Example:
#override
Widget build(BuildContext context) {
dynamic screenHeight = MediaQuery.of(context).size.height;
dynamic screenwidth = MediaQuery.of(context).size.width;
//use screenHeight and screenWidth variable for defining the height and
//width of the Widgets.
return Container(
height:screenHeight * .2, //It will take the 20% height of the screen
width: screenwidth * .5, //It will take the 50% width of the screen
//height: screenHeight, //It will take 100% height
child: Image(
image: AssetImage("assets/images/vlogo.png"),
);
}
You can make each screen responsive in flutter by just using MediaQuery or LayoutBuilder Concepts.
For your application, replace all your custom sizes like
width : MediaQuery.of(context).size.width * 0.1
height : MediaQuery.of(context).size.height * 0.3
MediaQuery gives you the sizes and orientation of the screen.
Even your padding, margin and other dimensions also should be calculated using MediaQuery to make it responsive.
Here, MediaQuery.of(context).size.width will give you the width of the current device screen and MediaQuery.of(context).size.height will give you the height of the current device screen.
Also, you can use LayoutBuilder Widget like,
LayoutBuilder(
builder: (context, constraints) {
if(constraints.maxWidth > 500) {
getLandscapeLayout();
} else {
getPortraitLayout();
}
},
)
LayoutBuilder is a widget which provides the dimensions of its parent so we can know how much space we have for the widget and can build it our child accordingly.
So these are two most powerful concepts are available in flutter to make your apps fully responsive.