How to increase height of CupertinoSliverNavigationBar - flutter

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

Related

How can I set initial position for slidable_button

I'd like to use slidable_button found here to set a bar happy hour on or off in my app. It doesn't have an initial position so I need to use two buttons, one to set happy hour on and another to turn it off. Ideally I'd like to have it initialize in either the left position or the right position depending on the current state. Unfortunately the package is very new and the author is not contactable.
Is there a way I could modify this code to set an initial button position left or right?
Here is the code I have so far. I have two buttons in separate rows in a column but have only shown the code for one as they are similar.
Center(
child: SlidableButton(
width: MediaQuery.of(context).size.width / 3,
buttonWidth: 60.0,
color: Colors.green,
buttonColor: Colors.blue,
dismissible: true,
label: Center(child: Text(_user.turnOnString!)),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(''),
Text('Start'),
],
),
),
onChanged: (position) {
if (position == SlidableButtonPosition.right) {_startHappyHour(context, _user);}
},
),
),
switch button would be more suitable for your situation, like lite_rolling_switch, you can set initial value(on/off):
LiteRollingSwitch(
//initial value
value: true,
textOn: 'disponible',
textOff: 'ocupado',
colorOn: Colors.greenAccent[700],
colorOff: Colors.redAccent[700],
iconOn: Icons.done,
iconOff: Icons.remove_circle_outline,
textSize: 16.0,
onChanged: (bool state) {
//Use it to manage the different states
print('Current State of SWITCH IS: $state');
},
),

Can I possibly always display the this TimePicker Widget?

I am trying to create an app where the user is able to select the time and the date, I want to make it such that the TimePicker is always showing on the screen for the user. I have managed to do this but I am unable to get the Time that is set by the user as there is no OnChanged method available.
Furthermore, I cannot change the functionality of the cancel and the Ok button that is displayed.
Here is the code:
Scaffold(
backgroundColor: Color(0xff2E2E42),
appBar: PreferredSize(preferredSize: Size.fromHeight(50),
child: CustomAppBar("Add Alarm")),
body: Column(
children: [
TimePickerDialog(initialTime: TimeOfDay.now(), onEntryModeChanged: (TimePicker){
print(TimePicker);
},),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 42.0),
child: Column(
// mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MaterialButton(onPressed: (){pickDate(context);},
child: Column(
children: [
Center(
child: Text(getDate(), style: TextStyle(
color: Colors.white,
fontSize: 30,
),),
),
],
),)
],
),
),
],
),
);
This is what the output looks like:
Thanks for helping :)
Unfortunately there is no easy way to convert TimePickerDialog into a non-dialog version, because much of it is hardcoded. This is unlike the date picker counterpart, where we can choose to either use DatePickerDialog or standalone DayPicker, MonthPicker, YearPicker widgets.
You basically have 3 choices, none of them is great.
Copy the dialog code (time_picker.dart file) into your project and modify it to suit your needs.
Use CupertinoTimerPicker (very different visual style).
Create your own, build it however you like.

How to create a form with add more field in flutter using flutter_form_builder?

Flutter Web
So I have a button called add tags which opens up a modal. The Modal has only one text field and two buttons called add another tag and submit.
Now what I want to do is when the user clicks the add another tag button the app will generate another text field.
I've already seen some videos and read the documentation but since I need to work on a modal and the modal has defined size I'm not sure how to handle issues like
What happens if the user adds a lot of tags. How can I make the modal scrollable?
I'm new to flutter_form_builder so I'm not sure if the modal can handle it or not.
Here's my code:
final _formKey = GlobalKey<FormBuilderState>();
Future buildAddTagsForm(BuildContext context,
{Function()? notifyParent}) async {
return await showDialog(
barrierDismissible: false,
barrierColor: Colors.black.withOpacity(0.5),
context: context,
builder: (context) {
var screen = MediaQuery.of(context).size;
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
content: SingleChildScrollView(
child: Container(
height: screen.height / 2,
width: screen.height > 650 ? 600.00 : screen.height * 1,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: FormBuilder(
key: _formKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: Icon(
Icons.cancel_presentation_rounded,
),
),
],
),
SizedBox(
height: 10,
),
FormBuilderTextField(
name: 'Tag Name',
decoration: InputDecoration(labelText: 'Tag name'),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context),
]),
),
SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MaterialButton(
color: CustomColors.buttonColor,
child: Text(
"Add another tag",
style: TextStyle(
color: Colors.white,
),
),
onPressed: () {},
)
],
),
SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MaterialButton(
color: CustomColors.buttonColor,
child: Text(
"Submit",
style: TextStyle(
color: Colors.white,
),
),
onPressed: () {},
)
],
),
],
),
),
),
),
),
);
},
);
},
);
}
I'm assuming by "modal" we're talking about the AlertDialog here:
return AlertDialog(
content: SingleChildScrollView(
By using SingleChildScrollView as the AlertDialog content:, we can have any size / any number of text fields we like in the dialog. If their number are too many for the height of dialog inside our screen, the content will scroll.
Although, its immediate child Container with height prevents the SingleChildScrollView from doing its magic:
return AlertDialog(
content: SingleChildScrollView(
child: Container(
height: screen.height / 2,
I think the above AlertDialog would not scroll because it would never be big enough to need to scroll. Plus, any fields added that combine to be taller than that specified height (screen.height / 2) will cause an overflow warning and be cutoff visually.
So to answer question #1: "What happens if the user adds a lot of tags. How can I make the modal scrollable?"
using SingleChildScrollView is the right idea
lets swap the position of the Container with height and the SingleChildScrollView and this should allow the dialog to grow & scroll as needed as columns in FormBuilder increase
Your question #2: "I'm new to flutter_form_builder so I'm not sure if the modal can handle it or not."
flutter_form_builder shouldn't affect how SingleChildScrollView works
Example
Here's a partial example of an AlertDialog with scroll view content: that can grow in number.
Widget build(BuildContext context) {
return Container(
height: 300,
child: AlertDialog(
content: SingleChildScrollView(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: items,
),
),
),
actions: [
OutlinedButton(
child: Text('Add Row'),
onPressed: _incrementCounter
)
]
),
);
}
The complete example runnable in DartPard is here. (Add a 6 or 7 rows and then scroll the content.)
Warning
There's a gotcha with using the above AlertDialog inside a sized Container. That Container with height is not enough to constrain the AlertDialog size.
Your showDialog builder: (that pushes the AlertDialog into existence) must provide additional constraints in order for the sized Container to have constraints to size itself within. Without these constraints, the AlertDialog will grow until it matches the device viewport size. I believe this is a quirk with how showDialog is written, since I'm guessing it's a modal layer on top of the current stack of routes. (Someone can correct me if I'm wrong.) It's only constraint is the physical device, but nothing else. By wrapping builder:'s output with a constraining widget (such as Center) the output will be able to size itself.
To see this in action, remove the Center widget from the full example above an re-run it. The dialog will grow to fill the screen when adding rows instead of being at max 300px in height.
child: OutlinedButton(
child: Text('Open Dialog'),
onPressed: () => showDialog(
context: context,
builder: (context) => Center(child: MyDialog())
),
)

Making a 2x2 grid in Flutter

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,
),
);
}
),
),
);
}
}

How do I place my widget in the top Center location using Media Query in Flutter?

I have the following dial located at the center of my screen.
I have called three different part to construct this dial.
However it seems to be stuck in the center of my screen and I want to shift it to the top center portion. Ive tried changing the alignments but it doesn't seem to work.
This is my code:
This is the dependency I'm using: https://pub.dev/packages/flutter_neumorphic
import 'package:flutter_neumorphic/flutter_neumorphic.dart';
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
pedometerOuterDial(context),
pedometerInnerDial(context),
Center(child: stepText()),
],
);
}
Widget stepText() {
return Text(
'4800\nSteps',
style: khomeStyle.copyWith(color: kOrange),
);
}
Widget pedometerOuterDial(context) {
final percentage = 30.0;
return Padding(
padding: const EdgeInsets.all(80.0),
child: Align(
alignment: Alignment.topCenter,
child: Neumorphic(
boxShape: NeumorphicBoxShape.circle(),
padding: EdgeInsets.all(10),
style: NeumorphicStyle(
depth: NeumorphicTheme.embossDepth(context),
),
child: CustomPaint(
painter: NeuProgressPainter(
circleWidth: 20,
completedPercentage: percentage,
defaultCircleColor: Colors.transparent,
),
child: Center(),
),
),
),
);
}
Widget pedometerInnerDial(context) {
return Align(
child: Neumorphic(
boxShape: NeumorphicBoxShape.circle(),
padding: EdgeInsets.all(80),
style: NeumorphicStyle(
color: Colors.white,
depth: NeumorphicTheme.depth(context),
),
),
);
}
Also I haven't used Media Query here for any of the dials, so will that be an issue for displaying on other devices?
Since you are using a stack widget, the best way to do this is to use a positioned widget. You can place the widget on top by wrapping it with Positioned and setting the top property to 0.
Here is an example:
Positioned(
top:0,
child:YourWidget(),
),
Alignment won't work for the stack widget because it only aligns the items when there are extra space around it. Example: It works in a Column or Row since they occupy space and allow the widgets inside it to be placed and move around the occupied space.