I came across a problem with my fonts. Somehow the SizedBox I used which contains some Text doesn't align properly on the left in the Android Emulator like it does on the IOS simulator. It looks like this. In addition, the fontsizes don't match either.
Any Ideas how to fix this?
body: SingleChildScrollView(
child: CustomScrollView(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
slivers: [
SliverAppBar(
backgroundColor: Colors.blue,
expandedHeight: 80,
flexibleSpace: FlexibleSpaceBar(
title: FittedBox(
child: SizedBox(
width: MediaQuery.of(context).size.width,
child: const Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Align(
alignment: Alignment.centerLeft,
child: Text("Browse through the individual categories.", style: TextStyle(fontSize: 32, color: Colors.black, fontWeight: FontWeight.w900)),
),
),
)
)
),
),
buildCategories(),
],
),
),
Thanks in advance! :)
I added the centerTitle: true property to the FlexibleSpaceBar and now it looks consistent on both Android and iOS.
Was facing the same issue and upon looking at the FlexibleSpaceBar code, this is because of the default titlePadding being applied based on the centerTitle which is then based on the TargetPlatform (in this case whether iOS or Android) if you did not specify any centerTitle value. Below is the FlexibleSpaceBar code which does the application of titlePadding based on platform:
bool _getEffectiveCenterTitle(ThemeData theme) {
if (widget.centerTitle != null) return widget.centerTitle!;
assert(theme.platform != null);
switch (theme.platform) {
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
return false;
case TargetPlatform.iOS:
case TargetPlatform.macOS:
return true;
}
}
final bool effectiveCenterTitle = _getEffectiveCenterTitle(theme);
final EdgeInsetsGeometry padding = widget.titlePadding ??
EdgeInsetsDirectional.only(
start: effectiveCenterTitle ? 0.0 : 72.0,
bottom: 16.0,
);
And so, the answer is it's either you set a titlePadding or set centerTitle to true.
Related
This is the result that I want.
This is the current output that I have.
How can I achieve this result specifically the lines that are present in between the list tiles? I am using a ListView to show the rules. Below is the code for the ListTile that I am using.
Widget ruleTile(String title) {
return ListTile(
contentPadding: EdgeInsets.zero,
leading: Image.asset(
"assets/images/sun.png",
width: 40.w,
),
title: Text(
title,
style: MyTextStyle.littlesmaller,
),
);
}
You can use Stack and dotted_line package combo to create something like that:
Stack(children: [
DottedLine(
direction: Axis.vertical,
lineLength: linelength,
lineThickness: 1.0,
)
// You ListTile Code
],)
Thanks to #pmatatias comment, I figured it out. This is the updated code I used to get the desired output.
Widget ruleTile(String title, num index) {
Widget connector = const DashedLineConnector(
color: Color(0xFFFACC15),
gap: 3,
);
return TimelineTile(
node: TimelineNode(
indicator: Image.asset(
"assets/images/sun.png",
width: 40.w,
),
startConnector: index == 0 ? null : connector,
endConnector: index == rulesList.length - 1 ? null : connector,
),
nodeAlign: TimelineNodeAlign.start,
contents: ListTile(
contentPadding: EdgeInsets.zero,
title: Text(
title,
style: MyTextStyle.littlesmaller,
),
),
);
}
I'm trying to create a 2x2 grid for displaying some info in cards. Disclaimer: I'm totally new to Dart and Flutter, so expect a lot of ignorance on the topic here.
These cards should have a fixed size, have an image, display some text... and be positioned from left to right, from top to bottom.
First, I tried to use the Flex widget, but it seems to only work horizontally or vertically. Therefore, my only solution was to use two Flexes, but only showing the second when the amount of elements is higher than 2 (which would only use one row).
Then, I tried using GridView, but it doesn't work in any possible way. It doesn't matter which example from the Internet I copy and paste to begin testing: they just won't show up in the screen unless they're the only thing that is shown in the app, with no other widget whatsoever. I still don't understand why that happens.
This is my current code:
First widgets in "home_page.dart":
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Padding(padding: EdgeInsets.only(top: 30)),
Text(
'App test',
style: TextStyle(fontSize: 24),
),
EventsList(key: new Key('test')),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
The "EventList" part is a widget that should represent the grid functionality I explained before. This class gets some info from a service (which currently just sends some hardcoded info from a Future), and paints the given widgets ("Card" items, basically) into the EventList view:
class _EventsListState extends State<EventsList> {
#override
Widget build(BuildContext context) {
return FutureBuilder<List<Event>>(
future: new EventsService().getEventsForCoords(),
builder: (context, AsyncSnapshot<List<Event>> snapshot) {
if (snapshot.hasData) {
return Padding(
padding: EdgeInsets.only(left: 20, right: 20),
child: Flex(
direction: Axis.horizontal,
verticalDirection: VerticalDirection.down,
mainAxisAlignment: MainAxisAlignment.center,
children: generateProximityEventCards(snapshot.data),
));
} else {
return CircularProgressIndicator();
}
});
}
List<Card> generateProximityEventCards(List<Event> eventList) {
// Load Events from API
print(eventList);
// Render each card
return eventList.map((Event ev) {
return Card(
child: Padding(
padding: EdgeInsets.only(bottom: 15),
child: Column(
children: <Widget>[
Image(
fit: BoxFit.cover,
image: ev.imageUrl,
height: 100,
width: 150,
),
Padding(
child: Text(ev.name),
padding: EdgeInsets.only(left: 10, right: 10),
),
Padding(
child: Text(ev.address),
padding: EdgeInsets.only(left: 10, right: 10),
),
],
),
));
}).toList();
}
}
This is how it currently looks:
As I said before, I understand that the Flex widget can't really get that 2x2 grid look that I'm looking for, which would be something like this (done with Paint):
So, some questions:
How can I get a grid like that working? Have in mind that I want to have more stuff below that, so it cannot be an "infinite" grid, nor a full window grid.
Is it possible to perform some scrolling to the right in the container of that grid? So in case there are more than 4 elements, I can get to the other ones just scrolling with the finger to the right.
As you can see in the first image, the second example is bigger than the first. How to limit the Card's size?
Thank you a lot for your help!
The reason the gridview was not working is because you need to set the shrinkWrap property of theGridView to true, to make it take up as little space as possible. (by default, scrollable widgets like gridview and listview take up as much vertical space as possible, which gives you an error if you put that inside a column widget)
Try using the scrollable GridView.count widget like this and setting shrinkWrap to true:
...
GridView.count(
primary: false,
padding: /* You can add padding: */ You can add padding const EdgeInsets.all(20),
crossAxisCount: /* This makes it 2x2: */ 2,
shrinkWrap: true,
children: generateProximityEventCards(snapshot.data),
...
Is this what you exactly want?
do let me know so that I can update the code for you
import 'package:flutter/material.dart';
class List extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
title: Text('Inicio', style: TextStyle(color: Colors.black, fontSize: 18.0),),
),
body: GridView.count(
shrinkWrap: true,
crossAxisCount: 2,
children: List.generate(
50,//this is the total number of cards
(index){
return Container(
child: Card(
color: Colors.blue,
),
);
}
),
),
);
}
}
A Simple example would be:
Scaffold(
floatingActionButton: _fab(),
floatingActionButtonLocation: _fabLocation(),
body: Scrollbar(
child: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
automaticallyImplyLeading: false,
leading: null,
backgroundColor: Theme.of(context).colorScheme.secondary,
title: AutoSizeText(
_catalogSearchRatio,
style: Theme.of(context).textTheme.title.copyWith(
color: Theme.of(context).colorScheme.onSecondary),
),
floating: true,
pinned: false,
),
SliverFixedExtentList(
itemExtent: 90.0,
delegate: SliverChildBuilderDelegate((context, index) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 5.0, vertical: 5.0),
child: CatalogItems.medidaGroups
.contains(_itemsCatalogDisplay[index].group)
? _medidasCard(
index, _itemsCatalogDisplay, _catalogSearchQuery)
: _catalogCard(index, _itemsCatalogDisplay,
_catalogSearchQuery, _cartItems, _filteredGroups),
);
}, childCount: itemsCatalogDisplayLength),
),
],
controller: _catalogScrollController,
),
),
);
In the above example, a Scrollbar can be used and that's fine. BUT you can't drag the scrollbar. So I am using a package called draggable_scrollbar which lets me drag the scrollbar. However, I can't seem to replace the scrollbar I have in the example because it gives me the can't be assigned to BoxScrollView error.
It works if it's just a Listview or a Listview.builder or even a GridView
Start by importing the Cupertino package like below..
Import 'package: flutter/cupertino.dart';
Now, inside your class which contains your ScrollViews add the ScrollController like below...
final ScrollController myScrollWorks = ScrollController();
Now wrap any of your ScrollViews... which in your case is a CustomScrollView with the code below
body: PrimaryScrollController(
controller: myScrollWorks,
child: CupertinoScrollbar(
child: CustomScrollView(
slivers:[
your slivers code here
];
I was trying to clone WhatsApp(iOS version) with flutter using Cupertino Widgets.
while trying to make the header with CupertinoSliverNavigationBar i noticed that the height of CupertinoSliverNavigationBar cannot be increased.
My Code
return CupertinoPageScaffold(
child: NotificationListener<ScrollNotification>(
onNotification: (scrollNotification) {
if (scrollNotification is ScrollStartNotification) {
_onStartScroll(scrollNotification.metrics);
} else if (scrollNotification is ScrollUpdateNotification) {
_onUpdateScroll(scrollNotification.metrics);
} else if (scrollNotification is ScrollEndNotification) {
_onEndScroll(scrollNotification.metrics);
}
},
child: CustomScrollView(
slivers: <Widget>[
CupertinoSliverNavigationBar(
leading: GestureDetector(
child: Padding(
padding: EdgeInsets.only(top: 10.0),
child: Text(
"Edit",
style: TextStyle(
color: Constants.primaryColor,
fontSize: 18.0,
),
),
),
onTap: ()=>print("Tapped"),
),
trailing: GestureDetector(
child: Icon(
CupertinoIcons.create_solid,
size: 25.0,
),
onTap: ()=>print("Tapped"),
),
automaticallyImplyLeading: false,
largeTitle: Column(
children: <Widget>[
Container(
child: Text(
"Chats",
textAlign: TextAlign.left,
),
),
GestureDetector(
child: SearchBar(),
),
],
),
),
],
),
),
);
Screenshots below:
What i want to achieve
What i got
Is there any work around or anyway to increase the height? Thanks!
Flutter purists and advocates will kill me, but those sizes are part of the constants values (like MaterialDesign guidelines values), 2 quick options:
Option 1:
Modify the SDK directly:
Ctrl (or Cmd) + click in CustomScrollView, will open flutter/lib/src/cupertino/nav_bar.dart
Modify line 22 or 26:
/// This height is constant and independent of accessibility as it is in iOS.
const double _kNavBarPersistentHeight = 44.0;
/// Size increase from expanding the navigation bar into an iOS-11-style large title
/// form in a [CustomScrollView].
const double _kNavBarLargeTitleHeightExtension = 52.0; // change this one!
Option 2:
copy nav_bar.dart directly in your project, and modify it, or better yet, grab all the dependencies of CustomScrollView(), and put ur own name, and ur own values there... I guess that beyond being a standard design guideline from Apple, the ability to change those values are required for several devs. We should open a Github request maybe.
Hope you find my "hacky" solution useful!
Result:
You don't need to modify the SDK or something like that.
I have found a simple solution.
add this to CustomScrollView, adjust the anchor until you get a good UI.
CustomScrollView(
anchor: 0.07,
See the image here
I'm trying to show the title but as you can see, it does not do it correctly.
I tried to put softWrap to true but it is still the same.
The code is from flutter contacts_demo gallery
flexibleSpace: FlexibleSpaceBar(
title: const Text('Fantastic Beasts And Where To Find Them'),
background: Stack(
fit: StackFit.expand,
children: <Widget>[
Image.asset(
'people/ali_landscape.png',
package: 'flutter_gallery_assets',
fit: BoxFit.cover,
height: _appBarHeight,
),
// This gradient ensures that the toolbar icons are distinct
// against the background image.
const DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment(0.0, -1.0),
end: Alignment(0.0, -0.4),
colors: <Color>[Color(0x60000000), Color(0x00000000)],
),
),
),
],
),
),
You can use a ConstrainedBox along with MediaQuery.of(context).size.width
final mediaQuery = MediaQuery.of(context);
final availableWidth = mediaQuery.size.width - 160;
along with
title: ConstrainedBox(
constraints: BoxConstraints(
maxWidth: availableWidth,
),
child: const Text('Fantastic Beasts And Where To Find Them'),
),
I dug into a FlexibleSpaceBar sources and at least now I understand what happens. Turns out that in an expanded state title is scaled up to be 1.5 of its size, so naturally it will overflow offscreen. As user scrolls up, title is scaled down towards its source size of 1.0. At this size it will sit in the top toolbar.
Maybe this information will help someone to base their workarounds on until this is fixed.
I wondered why my hack of wrapping title in ConstraintedBox with maxWidth: MediaQuery.of(context).size.width didn't work. Now I know: I must divide this maxWidth by 1.5.
See also this bug on the Flutter github issue tracker.
The title length in combination with the font size you've set have no way to be displayed on a single line on smaller devices, for obvious reasons.
You may want to play with MediaQuery.of(context).size.width to get the device width and set the header text fontSize accordingly as a fraction of that. Try in the emulator to see which works best for your text length.
const Text(
'Fantastic Beasts And Where To Find Them',
style: TextStyle(fontSize: MediaQuery.of(context).size.width/ SOME_NUMBER),
),
Or just hardcode some font sizes based on some width intervals:
int _getFontSize(BuildContext context) {
int width = MediaQuery.of(context).size.width;
if (width < 300) {
return 10;
} else if (width < 600) {
return 13;
// etc ...
} else {
return 18;
}
}
...
const Text(
'Fantastic Beasts And Where To Find Them',
style: _getFontSize(context),
),
Thanks to dimsuz's answer it is possible to eliminate the upscaling of text in a FlexibleSpaceBar:
SliverAppBar(
actions: <Widget>[
IconButton(
icon: Icon(Icons.save),
onPressed: () {},
),
],
floating: true,
pinned: false,
snap: false,
flexibleSpace: FlexibleSpaceBar(
title: Text(title, style: TextStyle(fontSize: 20.0 / 1.5)),
centerTitle: false,
background: Container(
color: Theme.of(context).primaryColor,
),
),
expandedHeight: 120,
),
The 20.0 in fontSize I took from here.