I want to add a animation in a search bar when the user taps on it (just like the animation in whatsApp or telegram [only in iOS])
here is the animation
I used Hero widget to do so but the widget is not working, I don't know why. Here is my code for it
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
//some widgets above the search bar
Hero(
tag: 'search',
child: Container(
height: 38,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(32),
),
child: TextField(
cursorColor: Colors.blue,
decoration: InputDecoration(
hintStyle: TextStyle(fontSize: 16),
hintText: "Search here",
prefixIcon: Icon(Icons.search),
border: InputBorder.none,
),
),
),
),
//some more widgets here inside the column
])
This is part of code for 1st page and the other page is just the search bar.
This is the other page which is almost the same
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Hero(
tag: 'search',
child: Container(
height: 38,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(32),
),
child: TextField(
cursorColor: Colors.blue,
decoration: InputDecoration(
hintStyle: TextStyle(fontSize: 16),
hintText: "Search here",
prefixIcon: Icon(Icons.search),
border: InputBorder.none,
),
),
),
),
),
);
}
Also is there any other way to do it?
EDIT: It's now working fine with Hero widget but it does not show that exact behaviour as in the above gif. How should I do that, if someone has any other method to achieve that, can also answer.
Hero is used when moving between different pages here(in the above animation) we are not navigating to any other page, so, remove the Hero widget
This can be done with Transform.translate in combination with Opacity() widget in Flutter.
Wrap the respective widget with Transform.translate create a Tween Animation and change its height with the help of Offset(dx, dy) (in this case dx will be 0 and dy will be the changing height), negative dy value will move the widget upwards. Also wrap it with Opacity() and change the value with the changing value of height.
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Transform.translate(
offset: Offset(0, animatedHeightFromTweenAnimation)
child: Opacity(
opacity: animatedHeightFromTweenAnimation/maxHeightValue;
child: anyWidget()
)
)
Container(
height: 38,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(32),
),
child: TextField(
cursorColor: Colors.blue,
decoration: InputDecoration(
hintStyle: TextStyle(fontSize: 16),
hintText: "Search here",
prefixIcon: Icon(Icons.search),
border: InputBorder.none,
),
),
),//container
RaisedButton(
onPressed: () => controller.forward(), //here controller is animation controller
//the above line will start the animation
child: Text("press it"),
),
//some more widgets here inside the column
])
Related
I have been trying to adjust the size of the text field but whenever I do it I have a lot of whitespace. Whenever I add a SizedBox it starts to add lots of whitespace. I have the TextField embedded in a MaterialApp and a Scaffold. So I am stuck on this.
This is without the SizedBox:
TextField(
decoration: InputDecoration(
hintText: "Enter Your Email Address",
border: OutlineInputBorder(),
contentPadding: EdgeInsets.all(30),
),
),
This is when you add the SizedBox:
SizedBox(
height: 100,
width: 100,
child: TextField(
decoration: InputDecoration(
hintText: "Enter Your Email Address",
border: OutlineInputBorder(),
contentPadding: EdgeInsets.all(30),
),
),
),
When there is no SizedBox
When the SizedBox is added
Probably you are not using Column, that's why when you wrap your TextField with SizedBox the screen takes SizedBox's width. At the top in body of Scaffold you should use Column.\
If you already have Column, please share your whole code for this particular page, and let me have a better look.
you can do like this.
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: 45,
padding: EdgeInsets.fromLTRB(30, 0, 30, 0),
child: TextField(
textAlign: TextAlign.center,
textAlignVertical: TextAlignVertical.center,
decoration: InputDecoration(
hintText: "Enter Your Email Address",
border: OutlineInputBorder(),
contentPadding: EdgeInsets.all(30),
),
),
),]
),
Currently, the width of the widget tree is the width of the widget whose width is maximum(Here, the width of the widget tree is equal to the width of the next button).
set width of sizedBox to double.inifinity, it makes the sizedbox to occupy the available width i.e screen width.
And the widget tree occupies the entire width.
SizedBox(
height: 100,
width: double.infinity,
child: TextField(
decoration: InputDecoration(
hintText: "Enter Your Email Address",
border: OutlineInputBorder(),
contentPadding: EdgeInsets.all(30),
),
),
)
Please accept the solution if solves your problem
contentPadding: EdgeInsets.all(3),
just change this -> dont need to use SizedBox widget
You are adding a sized box which have 100 width and also 100 height ,so the sized box will be a squared box .
By increasing the width of the sized box like 300 something you can easily do this or I suggest you a way that a text field will be easily fixed in you code .
I hope this code will help you
Flexible(
child: TextFormField(
controller: _controller,
decoration: const InputDecoration(
labelText: 'Enter Something',
border: OutlineInputBorder(),
hintText: 'Enter Something ',
),
},
),
),
),
I generally used 'Sized Box' for spacing purpose in my flutter project
Use the below written code to understand how SizedBox works as spacing
class _sampleState extends State<sample> { #override Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.center,
child: Column(
children: [
SizedBox(height: 80,),
Text("Signup",style: TextStyle(fontSize: 30),),
SizedBox(height: 20,),
TextField(
decoration: InputDecoration(
// border: OutlineInputBorder(
// borderRadius: BorderRadius.circular(10.0),
// ),
filled: true,
hintStyle: TextStyle(color: Colors.white),
hintText: "Username or email",
fillColor: Color(0xff313F4D),
),
),
SizedBox(height: 50,),
ElevatedButton(onPressed: (){},
child: Text("Next"))
],
)),
);
This has been very confusing to me since the TextField wrapped in a SizedBox only, works perfectly; but it appears to be a simple image (it can't be tapped, nor focused) when I wrap that same piece of code in a Transform.translate widget.
Also, if I change the Transform.translate to a Positioned widget, the TextField works perfectly, but I'd like to understand why this is happening, because I am required to use Transform.translate over Positioned for this special project.
class Login extends StatelessWidget {
Login({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xfff4f6fa),
body: Stack(
children: <Widget>[
SizedBox(
width: 302.0,
height: 60.0,
child: TextField(
decoration: InputDecoration(
hintText: 'Correo electrónico *',
prefixIcon: Icon(Icons.send),
border: OutlineInputBorder(
borderSide:
BorderSide(width: 1.0, color: const Color(0xffe7e7e7)),
borderRadius: BorderRadius.circular(4.0),
),
),
style: TextStyle(
fontFamily: 'Nunito',
fontSize: 14,
color: const Color(0xff777777),
height: 1.4285714285714286,
),
textAlign: TextAlign.left,
onChanged: (String value) async {
},
onSubmitted: (String value) async {
},
),
),
// Positioned(
Transform.translate(
offset: Offset(36.0, 317.8),
// left: 36,
// top: 317.8,
child:
// Adobe XD layer: 'input:mail' (component)
SizedBox(
width: 302.0,
height: 60.0,
child: TextField(
decoration: InputDecoration(
hintText: 'Correo electrónico *',
prefixIcon: Icon(Icons.send),
border: OutlineInputBorder(
borderSide:
BorderSide(width: 1.0, color: const Color(0xffe7e7e7)),
borderRadius: BorderRadius.circular(4.0),
),
),
style: TextStyle(
fontFamily: 'Nunito',
fontSize: 14,
color: const Color(0xff777777),
height: 1.4285714285714286,
),
textAlign: TextAlign.left,
onChanged: (String value) async {
},
onSubmitted: (String value) async {
},
),
),
),
],
),
);
}
}
As mentioned before, both inputs show on the screen (one at the center and one at the top) only the TextField wrapped with a SizeBox (first element of the Stack, at the top of the sreen)can be tapped, nothing happens when the one at the center of the screen (second element of the stack, located there because of the translation) is tapped.
Try debugging and see the layout grid lines and correct boundaries of widget using Flutter inspector.
That should give you a better idea at why is it behaving this way.
Seems like when You use the Transform widget, it doesnt register the hit as it merely moves the boundaries and not the tap area.
Try wrapping the Transform widget with a GestureDetector and see.
You can also follow a similar issue on GitHub:
https://github.com/flutter/flutter/issues/27587
I am setting a text field which will expands when Enter is pressed in the keyboard
when i tried to set null in max lines it does not show the text inside text field
i even set that expands = true
i used media query size in somewhere which is size.height in the code
i wrapped the text field within the Flexible widget
and add some padding then the total flexible widget is wrapped within a Row
and finally the row is wrapped within a Container
so this code is not working help me to fix this
Container(
height: size.height * .059,
width: double.infinity,
child: new Row(
children: <Widget>[
new Flexible(
child: Padding(
padding: EdgeInsets.only(right: size.width * 0.007),
child: new TextField(
controller: _textFieldController,
textInputAction: TextInputAction.newline,
keyboardType: TextInputType.multiline,
maxLines: null,
expands: true,
style: TextStyle(color: Colors.black),
cursorColor: Colors.blue,
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0),
borderSide: BorderSide(color: Color(0xff8e9291))),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0),
borderSide: BorderSide(color: Color(0xff8e9291))),
prefixIcon: Icon(
Icons.message,
color: Color(0xff8e9291),
),
hintText: "Type a message",
hintStyle: TextStyle(
color: Color(0xff8e9291),
),
),
),
),
),
FloatingActionButton(
backgroundColor: Colors.blue[400],
onPressed: () {
},
tooltip: 'Send',
child: RotationTransition(
turns: AlwaysStoppedAnimation(-35 / 360),
child: Icon(
Icons.send,
size: 20,
)),
),
],
),
),
this is the Text field i'm using..
You could remove the height of the Container since that will make a fixed height, and remove the expands of the TextField since that is to make it to fill its parent height.
You could set MaxLine property to null 'maxLines: null`
this will enable textField to Expand Vertical
I need to bottom center a button that is contained within a ListView. By bottom, I mean at the bottom of the screen, or if the screen content is longer than the height of the screen, at the end of the content.
I can do this using a Column with a Spacer widget because the height is defined, however my screen has text input on it. If I use a Column instead of a ListView, the screen overflows when I'm typing.
How can I either
Bottom center a button, or
Use a Column but prevent the screen from resizing or overflowing when typing; I'd like it to ether be scrollable, or simply have the keyboard cover the screen content while typing.
Basic code example:
return Scaffold(
body: Center(
child: Container(
width: workingWidth,
child: Center(
child: ListView(children: <Widget>[
ScreenHeader("Tell Us a Little About Yourself"),
TextFormField(
maxLines: 16,
controller: bioController,
autocorrect: true,
textCapitalization: TextCapitalization.sentences,
maxLength: 500,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(paddingH5),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: colorPrimary)),
border: UnderlineInputBorder(
borderSide: BorderSide(color: colorMuted)),
hintText: "Enter your bio here...",
hintStyle: textMuted,
),
),
Spacer(), //This doesn't work because I am using a ListView instead of a Column
RoundedButton(
buttonText: 'Continue',
buttonStyle: buttonPrimary,
onPressed: () {}
),
],)
),
),
),
);
To use a Column without yellow/black stripes error when opening the keyboard, you need to wrap it into a SingleChildScrollView, but Spacer will not work in that case if you do not declare the height of its RenderFlex parent.
You can use MediaQuery.of(context).size.height to get the screen size on its context and set to your Container.
At the end you can achieve the desired layout with this:
return Scaffold(
body: SingleChildScrollView(
child: Container(
width: workingWidth,
height: MediaQuery.of(context).size.height,
child: Column(
children: <Widget>[
ScreenHeader("Tell Us a Little About Yourself"),
TextFormField(
maxLines: 16,
controller: bioController,
autocorrect: true,
textCapitalization: TextCapitalization.sentences,
maxLength: 500,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(paddingH5),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: colorPrimary)),
border: UnderlineInputBorder(
borderSide: BorderSide(color: colorMuted)),
hintText: "Enter your bio here...",
hintStyle: textMuted,
),
),
Spacer(),
RoundedButton(
buttonText: 'Continue',
buttonStyle: buttonPrimary,
onPressed: () {}
),
],
),
),
),
);
I have a Row that has 3 fields in it: 2 TextFields, 1 DropdownButtonHideUnderline wrapped in a Container. I'm trying to ensure that the first TextField takes up about 50-60% and the other two fields share the remaining space. I also want the fields to have the same height. So, something like this:
This is the code I have:
#override
Widget build(BuildContext context) {
return Container(
color: Theme.of(context).accentColor,
child: Padding(
padding: const EdgeInsets.fromLTRB(5.0, 10.0, 5.0, 10.0),
child: Row(children: <Widget>[
Expanded(
child: Container(
padding: EdgeInsets.only(right: 5.0),
child: TypeAheadField(
textFieldConfiguration: TextFieldConfiguration(
autofocus: true,
controller: widget.ingredientController,
style: DefaultTextStyle.of(context)
.style
.copyWith(fontStyle: FontStyle.italic),
decoration: InputDecoration(
border: InputBorder.none,
filled: true,
fillColor: Colors.white.withOpacity(1),
hintText: 'Ingredient',
suffixIcon: GestureDetector(
onTap: widget.addFunction,
child: Icon(
Icons.add,
color: Colors.grey,
)))),
suggestionsCallback: (pattern) async {
return await _findIngredients(pattern);
},
//If not items are found, return an empty container.
noItemsFoundBuilder: (context) {
return Container(height: 0, width: 0);
},
itemBuilder: (context, suggestion) {
return ListTile(
title: Text(suggestion.name),
);
},
onSuggestionSelected: (Ingredient suggestion) {
widget.ingredientController.text = suggestion.name;
},
))),
Expanded(
child: TextField(
maxLines: 1,
controller: widget.quantityController,
keyboardType: TextInputType.text,
autofocus: false,
decoration: InputDecoration(
border: InputBorder.none,
filled: true,
fillColor: Colors.white.withOpacity(1),
hintText: 'Qty',
))),
Expanded(flex: 1, child: UnitDropdown()),
])));
}
What I'm left with is this:
I've tried setting the flex factor on the Expanded to different things, but that just results in an overflow on the right side. I've also not found a way to force all of the widgets to have the same height.
Try this one,
Row(children : <Widget>[
Expanded(
Container(child: TextField1())
),
Expanded(
Row(children : <Widget>[
Expanded(child: TextFiled2()),
Expanded(child: DropDown())
]);
)
]);
Or else, You can use MediaQuery to get the exact size of the screen.
Example:
Width : MediaQuery.of(context).size.width * 0.5;
Width : MediaQuery.of(context).size.width * 0.25;
Width : MediaQuery.of(context).size.width * 0.25;
Here you have, the key is to encapsulate the TextField, Dropdown, or whatever component you have in a Container, and define the actual size from the Container, tweaking the predefined internal Paddings of each widget (if you have the chance, sometimes is not available).
double itemsHeight = 30;
Widget getTextField({String hint = 'Ingredients', Widget suffix}) {
// use Container to define the size of the child,
// and reset the original inner paddings!
return Container(
height: itemsHeight,
child: TextField(
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.zero,
borderSide: BorderSide(color: Colors.white, width: 1)),
hintText: hint,
contentPadding: EdgeInsets.all(
0), // change each value, and set 0 remainding ones.
suffixIcon: suffix,
),
expands: false,
maxLines: 1,
controller: TextEditingController(),
),
);
}
return Scaffold(
body: Container(
color: Colors.green.withOpacity(.2),
margin: EdgeInsets.symmetric(vertical: 50, horizontal: 20),
child: Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Flexible(
flex: 2,
child: getTextField(
hint: 'Ingredients',
suffix: Icon(
Icons.add,
size:
18, // option 1: reduce the size of the icon, and avoid the padding issues..
)),
),
Flexible(
flex: 1,
child: getTextField(
hint: 'Qty',
// option2: trick to match the expanded height of the icon on the previous field
// make an icon transparent :)
suffix: Icon(
Icons.account_box,
color: Colors.transparent,
)),
),
Flexible(
flex: 1,
child: Container(
// use this to match the Flex size..., is like using Expanded.
width: double.infinity,
// container defines the BoxConstrains of the children
decoration: BoxDecoration(
color: Colors.white24,
border: Border.all(color: Colors.white, width: 1),
),
height: itemsHeight,
child: DropdownButton(
hint: Text("Unit"),
onChanged: (i) {},
underline: Container(),
items: List.generate(5, (i) {
return DropdownMenuItem(child: Text("item $i"));
})),
),
),
],
),
),
);
screenshot of result: