TextOverFlow Flutter - flutter

I have a certain Text widget , when it overflows I have 3 options. Either fade ,visible, ellipsis or clip. But I don't want to choose between them . I want if a text has overflow then don't show the text.
Edit :
I'm working on a code clone to this design
Assuming that the textStyle is unknown.
How could I achieve that?
Code:
class SwipeNavigationBar extends StatefulWidget {
final Widget child;
SwipeNavigationBar({this.child});
#override
_SwipeNavigationBarState createState() => _SwipeNavigationBarState();
}
class _SwipeNavigationBarState extends State<SwipeNavigationBar> {
#override
Widget build(BuildContext context) {
return Consumer<Controller>(
builder: (_, _bloc, __) {
return SafeArea(
child: AnimatedContainer(
duration: Duration(seconds: 01),
color: Colors.white,
curve: Curves.easeIn,
height: !_bloc.x ? 50 : 200,
child: Row(
children: [
Column(
verticalDirection: VerticalDirection.up,
children: [
Expanded(child: Icon(Icons.dashboard)),
Expanded(
child: RotatedBox(
quarterTurns: -45,
child: Text(
'data',
softWrap: false,
style: TextStyle(
textBaseline: TextBaseline.alphabetic
),
),
),
),
],
)
],
),
),
);
},
);
}
}

To mimic the design you might want to look into using the Stack widget. However, to answer your question, you'd want to set softWrap to false.
Align(
alignment: Alignment.topLeft,
child: SizedBox(
width: 100,
child: Text(
'Some text we want to overflow',
softWrap: false,
),
),
)
softWrap is really the key here. Although, I added the Align and SizedBox widgets to allow this to be used anywhere, regardless of what parent widget you are using (since some widgets set tight constraints on their children and will override their children's size preference).
CodePen Example
Edit: 5/6/2020
With the release of Flutter v1.17 you now have access to a new Widget called NavigationRail which may help you with the design you're looking for.

Use ternary operator to check the length of the text that you are passing to the Text widget and based on that pass the text itself or an empty string.
String yourText;
int desiredLengthToShow = 10; //Change this according to you.
...
Text(
child: yourText.length > desiredLengthToShow ? "" : yourText,
);

Related

Flutter Card child content height is larger than its parent

I'm trying to use a GridView to handle displays for multiple Card, each Card contains of an Image. Unfortunately it turns out that the Image is taking a larger height than its parent (see attached picture for the details).
I'm pretty new to Flutter layout so any ideas why this is happening and how I can resolve this? I want the layout to be something like this:
Display 2 cards on each line.
The Card width or height should not be fixed.
The Image height should be scaled according to its width.
class SquadSelectionScreen extends StatelessWidget {
final List<Team> teams;
const SquadSelectionScreen({super.key, required this.teams});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Squads'),
),
body: GridView.count(
crossAxisSpacing: 10,
crossAxisCount: 2,
padding: const EdgeInsets.all(16),
children: teams
.map(
(team) => SquadView(team: team),
)
.toList(),
),
);
}
}
class SquadView extends StatelessWidget {
final Team team;
const SquadView({super.key, required this.team});
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
context.push('/squads/${team.code}');
},
child: Card(
elevation: 1,
child: Column(
children: [
Image(
image: NetworkImage(team.imageUrl),
),
const SizedBox(
height: 8,
),
Center(
child: Text(team.name),
),
],
),
),
);
}
}
Using GridView.count has a very visible drawback, namely the size of the aspect ratio of the grid will always be one (1:1 or Square) and can't be changed.
So if you look at the code above, you can't set an image with the same aspect ratio because the text will sink.
The first suggestion for me if you still want to use GridView.count is
Wrapping your Image with AspectRatio that has value higher than one (example set Ratio to 4/3, 5/3, 16/9, or landscape looks). Note: 4/3 = is higher than 1, 16/9 = is higher than 1, etc..
Then wrap the Text Widget with Expanded()
Example code:
class SquadView extends StatelessWidget {
final Team team;
const SquadView({super.key, required this.team});
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {},
child: Card(
elevation: 1,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
AspectRatio(
aspectRatio: 4/3, // you can set the value to 16/9 or anything that result is higher than one
child: Image(
image: NetworkImage(team.imageUrl),
fit: BoxFit.cover, // set How the image looks to Fit
),
),
const SizedBox(
height: 8,
),
Expanded(
child: Center(
child: Text(team.name, overflow: TextOverflow.ellipsis),
),
),
],
),
),
),
);
}
}
I suggest you try GridView.builder or another GridView. You can look at the documentation here
or this third package this will be good for to try flutter_staggered_grid_view. The flutter_staggered_grid_view is more flexible to create GridView with various size.

How do I stop overflow

I am still new to coding, I have created multiple textbutton.icon's but they overflow. How do i stop the overflow. Even if i put is in a row or column it still overflows. I also would like to put more spacing between each row of buttons but that just makes it overflow more. Here is the multiple class code:
class home_buttons {
List<Widget> jeffButtons = [
Button1(),
Button2(),
Button3(),
Button4(),
Button5(),
Button6(),
Button7(),
Button8(),
Button9(),
];
}
Here is the button code:
class Button1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 9.0, 0.0, 0.0),
child: TextButton.icon(
onPressed: () => {},
icon: Column(
children: [
Icon(
Icons.search,
color: Colors.white,
size: 75,
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
'Contact Us',
style: TextStyle(
color: Colors.white,
),
),
),
],
),
label: Text(
'', //'Label',
style: TextStyle(
color: Colors.white,
),
),
),
);
}
}
You can wrap your widgets with the SingleChildScrollView to enable scrolling.
Or if you want to fit the screen inside a Column or Row Widget you can wrap individual widgets with a Flexible Widget
Flutter listview normally have undefined height. The total height of listview is defined based on the items in the list. So when you declare listview directly you get overflow issue.
So as a solution you need to specify the height for the outer container, or use sizedbox to define the height.
Specifying height will solve your issue of overflow. To provide space between buttons you can also wrap that in a container and use the benefit of margin or padding to handle it efficiently.
Please find this code snippet to use Media to find height of device
Container(
height: MediaQuery.of(context).size.height,
color: Colors.white,
child: SingleChildScrollView(
child: Column(
children: [
Here instead of SingleChildScrollView You can use listview or listbuilder which will solve your overflow issue
Hope this helps. Let me know If you want more details. Thanks

Animated Switcher in combination with case conditioned Streambuilder

Following question:
I managed to get a lot further with my dosage calculator app and the state management procedure and now I'm trying to scale things up visually speaking.
So I wanted to change the built widget based on a dropdown menu which actually worked out fine but I'm trying to implement an AnimatedSwitcher so every time the user changes the dropdown menu, the old widget fades out and the new one in instead of just switching. Searched for solutions, found one but I don't know if I implemented it the right way, since I'm not getting any animation, but no error message neither.
I'm supposing I either used the wrong child or something like a unique key is missing (which I don't know how to implement)
Here are the necessary parts of my code:
DropdownMenu:
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child:DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: selectedItem,
onChanged: (String string) => setState(() {
streamController.sink.add(string);
return selectedItem = string;
}),
selectedItemBuilder: (BuildContext context) {
return items.map<Widget>((String item) {
return Text(item,
//style: TextStyle(fontWeight: FontWeight.bold),
textAlign: TextAlign.right,
);
}).toList();
},
items: items.map((String item) {
return DropdownMenuItem<String>(
child: Text('$item',
//style: TextStyle(fontWeight: FontWeight.bold),
textAlign: TextAlign.right,
),
value: item,
);
}).toList(),
),
),
);
}
}
StreamBuilder and AnimatedSwitcher:
StreamBuilder(
stream: streamController.stream,
builder: (context, snapshot) {
return AnimatedSwitcher(
duration: Duration(seconds: 1),
child: updateBestandteile(snapshot.data),
);
},
),
Example of condition:
Padding updateBestandteile(String i) {
switch (i) {
case "MMF":
{
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 200,
decoration: BoxDecoration(
color: b,
borderRadius: BorderRadius.circular(10.0)
),
child: Align(
alignment: Alignment.center,
child: Row(
children: [
Column(
children: [
Text('Zu verwendende Präparate:',
style: TextStyle(fontWeight: FontWeight.bold)),
Text('Medetomidin 1mg/ml'),
Text('Midazolam 5mg/ml'),
Text('Fentanyl 0.5mg/ml'),
Text('NaCl 0,9%'),
],
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
),
Column(
children: [
Text('Anzumischende Menge:',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text((MedetomidindosierungmgprokgKGW*selectedamount*selectedweight/(1000*Medetomidinmgproml)).toString()+"ml"),
Text((MidazolamdosierungmgprokgKGW*selectedamount*selectedweight/(1000*Midazolammgproml)).toString()+"ml"),
Text((FentanyldosierungmgprokgKGW*selectedamount*selectedweight/(1000*Fentanylmgproml)).toString()+"ml"),
Text((((MedetomidindosierungmgprokgKGW*selectedamount*selectedweight/(1000*Medetomidinmgproml))+(MidazolamdosierungmgprokgKGW*selectedamount*selectedweight/(1000*Midazolammgproml))+(FentanyldosierungmgprokgKGW*selectedamount*selectedweight/(1000*Fentanylmgproml)))*4).toString()+"ml"),
],
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
),
],
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
),
),
),
);
}
break;
Hope you might be able to help as you did last time :) Thanks in advance!
Cheers,
P
The issue might be that you are not setting a key. If the new child widget is of the same type as the old widget type then AnimatedSwitcher will NOT animate between them since as as far as the framework is concerned, they are the same widget. Set a unique ValueKey on each child child widget that you wish to animate.
Please refer to Flutter Docs for AnimatedSwitcher and check out the AnimatedSwitcher Widget of the Week video by Flutter Team.
If the "new" child is the same widget type and key as the "old" child,
but with different parameters, then AnimatedSwitcher will not do a
transition between them, since as far as the framework is concerned,
they are the same widget and the existing widget can be updated with
the new parameters. To force the transition to occur, set a Key on
each child widget that you wish to be considered unique (typically a
ValueKey on the widget data that distinguishes this child from the
others).

Manage multiple form validation in PageView flutter

I have multiple forms inside a PageView, Forms are in different files like registration_form.dart contains the Sign-Up form and so on. In my App, each page contains a different Form. I want that when the user clicks on "Continue", the form will be validated and in an error situation, the user will be warned. I call all the pages in one class called Body as shown below. The "Continue" button is inside of it in the Opacity container. If there is a better approach to follow as a solution I am open to recommendations.
#override
Widget build(BuildContext context) {
return SafeArea(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: MediaQuery.of(context).size.height * 0.65,
child: Flex(
direction: Axis.horizontal,
children: [
Flexible(
child: PageView(
controller: _controller,
//physics: new NeverScrollableScrollPhysics(),
children: [
RegisterForm(),
WelcomeForm(),
//CompanyForm(),
//CompanyNextForm(),
//CompanyLogoForm(),
//FinancingDataForm(),
//UtilityForm(),
//MatrixInformationForm(),
//MatrixInformationNextForm(),
//MatrixInformationLastForm(),
//PriceBuildingForm(),
//InstallKitForm(),
//InstallKitDetailedForm(),
//CustomPricingForm(),
//CustomPricingNextForm(),
//FillRow1Form(),
//FillItem1Row1Form(),
//FillItem2Row1Form(),
//FillItem3Row1Form(),
//FillRow2Form(),
//FillItem1Row2Form(),
//FillItem2Row2Form(),
//FillItem3Row2Form(),
//FillRow3Form(),
//FillItem1Row3Form(),
//FillItem2Row3Form(),
//FillItem3Row3Form(),
//InvoicingForm(),
//FinancingForm(),
//FinancingNextForm(),
//FinancingLastForm(),
//FinalizeForm(),
//DoneForm(),
//BookingForm(),
],
),
),
],
),
),
SizedBox(
height: ResponsiveLayout.isSmallScreen(context)
? 10
: ResponsiveLayout.isMediumScreen(context)
? 10
: 10,
),
Opacity(
opacity: 1, //currentIndex == 20 ? 0 : 1,
child: Container(
height: 50,
decoration: BoxDecoration(
color: Color.fromRGBO(16, 88, 198, 1),
borderRadius: BorderRadius.all(Radius.circular(8)),
),
child: GestureDetector(
onTap: () {
_controller.nextPage(
duration: Duration(milliseconds: 300),
curve: Curves.easeIn);
},
child: Container(
width: MediaQuery.of(context).size.width,
height: 100,
decoration: BoxDecoration(
color: Color.fromRGBO(16, 88, 198, 1),
borderRadius: BorderRadius.all(Radius.circular(8)),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
height: 100.0,
child: Center(
child: RichText(
text: TextSpan(children: [
WidgetSpan(
child: Text(
'Continue ',
style: TextStyle(
color: Colors.white,
fontSize: ResponsiveLayout
.isSmallScreen(context)
? 12
: ResponsiveLayout.isMediumScreen(
context)
? 12
: 15,
),
)),
WidgetSpan(
child: Icon(
Icons.arrow_forward,
size: ResponsiveLayout.isSmallScreen(
context)
? 12
: ResponsiveLayout.isMediumScreen(
context)
? 12
: 15,
color: Colors.white,
),
),
]),
),
)),
],
),
),
)),
),
],
),
),
);
}
Okay. I was struggling with the same question recently and was looking for a good approach. Maybe this answer will be helpful for any other developer looking for the answer.
Approach
Currently, in my case, I used form keys for validations and function callbacks. This solution did the job for me because I needed to take input as raw text. Others like multiple choice options similar where there were predefined outputs.
To describe my solution more explicitly. Consider this example, we want to get basic details of the user like name, age, city etc. For user input like the name, we can use TextFormField. This will give access to the onChanged callback for validation. To access the response in the PageView widget containing the class. You can use the TextEditingController.
Now, we can then simply add the Form widget at the parent of the basic form widget build method.
Finally for multiple choice questions. We can provide a callback function like onTap to the widget of PageView. This function will be called whenever the user interacts with the dropdown or similar widget.
Note: If we have multiple forms in the PageView widget. You will be needing separate form keys for individual forms.
Code Example
So, we have the main form_screen.dart containing the PageView widget and basic_profile.dart containing our form. Both the files should look something like this:
form_screen.dart
...
// define the variables and keys here
final _basicProfileKey = GlobalKey<FormState>();
final _userName = TextEditingController();
late String _userGender;
...
// callback function that we will be passing to the BasicProfile
// widget on the other page
void _userGender(String value) {
_userGender = value;
}
...
// the submission callback that will be called whenever the user
// clicks on the next or save button available in the class file
// (this file) containing the PageView widget
void _submissionCallback(){
if(_pageViewIndex == 0) {
final validationStatus = _basicProfileKey.currentState?.validate() ?? false;
if(validationStatus) {
// implement your logic here and then move to next page in the pageview
}
}
}
...
// Build method widget tree containing the PageView and BasicProfile
// widgets
child: PageView(
children: [
BasicProfile(
basicProfileKey: _basicProfileKey,
userName: _userName,
userGenderCallback: userGender
),
]
),
basic_profile.dart
...
// declare the variables for this widget which we will be initialised
// via constructor
final GlobalKey<FormState> basicProfileKey;
final TextEditingController userName;
final Function(String) userGenderCallback;
...
#override
void initState(){
// initialise the default values here if any and call the
// callback function received above
userGenderCallback(_defaultValue);
}
...
Widget build(BuildContext context){
...
child: Form(
key: basicProfileKey,
...
TextFieldForm(
onValidate: (){
// do the validation here
}
)
...
DropDown(
onChanged: (value) {
// logic for validation
userGenderCallback(value);
}
)
}
In my approach used setState as the state management solution but other state solutions can also be used for easier state sharing between the widgets.
Hope this helps!

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.