scrolling to the top when typing on TextField on Flutter - flutter

I added TextFormField on SliverPersistentHeaderDelegate. After scroll to the middle/bottom and then typing on to the textField, SliverList automatically come to the top. How do I disable this?
Full Code.
class MyWidget extends StatelessWidget {
static const String route = '/myWidget';
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: CustomScrollView(
slivers: <Widget>[
SliverPersistentHeader(
pinned: true,
delegate: MyDynamicHeader(),
),
SliverList(
delegate: SliverChildBuilderDelegate((BuildContext context, int index) {
return Container(
height: 200,
color: Color(Random().nextInt(0xffffffff)),
);
},
)
)
],
)
)
);
}
}
class MyDynamicHeader extends SliverPersistentHeaderDelegate {
int index = 0;
#override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
return LayoutBuilder(
builder: (context, constraints) {
final Color color = Colors.primaries[index];
final double percentage = (constraints.maxHeight - minExtent)/(maxExtent - minExtent);
if (++index > Colors.primaries.length-1)
index = 0;
return Container(
decoration: BoxDecoration(
boxShadow: [BoxShadow(blurRadius: 4.0, color: Colors.black45)],
gradient: LinearGradient(
colors: [Colors.blue, color]
)
),
height: constraints.maxHeight,
child: SafeArea(
child: Center(
child: Row(
children: <Widget>[
CircularProgressIndicator(
value: percentage,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
InkWell(
onTap: (){
print('is working');
},
child: Container(
height: 50,
width: 100,
color: Palette.orelPay,
),
),
Expanded(child: TextFormField(
//controller: searchController,
decoration: InputDecoration(
contentPadding:
EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
hintText: "Search on OrelBuy",
border: OutlineInputBorder(
borderSide:
BorderSide(color: Palette.background, width: 32.0),
borderRadius: BorderRadius.circular(50.0)),
fillColor: Palette.background,
filled: true,
enabledBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Palette.background, width: 32.0),
borderRadius: BorderRadius.circular(50.0)),
focusedBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Palette.background, width: 32.0),
borderRadius: BorderRadius.circular(50.0))),
),)
],
),
)
),
);
}
);
}
#override
bool shouldRebuild(SliverPersistentHeaderDelegate old) => false;
#override
double get maxExtent => 250.0;
#override
double get minExtent => 80.0;
}

you can use physics of CustomScrollView widget to control scroll.
CustomScrollView(
physics: PageScrollPhysics(), // added
slivers: <Widget>[

Related

Cant make a listview builder in a column that is in a row, flutter

I want to make a screen that has 2 columns beside eachother. Both columns are going to have a dynamic listview.builder and a textinput so I can put in new values and show them in those listviews. It is for a dart game calculator that I can track what I threw before. When I use the code underneath with body: Column (so 1 column with the dynamic listview.builder and textinput it works) But when I wrap it in a row and 2 columns I get the following error.
RenderBox was not laid out: RenderShrinkWrappingViewport#5063b relayoutBoundary=up15 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
Here is some code for you to try out. If you want to let it fail uncomment both Expanded and Textinput.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: GamePage(),
);
}
}
class GamePage extends StatefulWidget {
const GamePage({super.key});
#override
State<GamePage> createState() => _GamePageState();
}
class _GamePageState extends State<GamePage> {
List<String> thrownScoresOne = [];
List<String> thrownScoresTwo = [];
int playerOne501 = 501;
int playerTwo501 = 501;
final TextEditingController _playerOneScoreController =
TextEditingController();
final TextEditingController _playerTwoScoreController =
TextEditingController();
#override
void dispose() {
_playerOneScoreController.dispose();
_playerTwoScoreController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Game"),
),
body: SafeArea(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 32),
width: double.infinity,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
children: [
Container(
child: Text("Player one"),
),
Container(
child: Text(playerOne501.toString()),
),
// Expanded(
// child: ListView.builder(
// shrinkWrap: true,
// itemCount: thrownScoresOne.length,
// itemBuilder: (BuildContext context, int index) {
// return Text(thrownScoresOne[index]);
// }),
// ),
// Flexible(
// child: Container(
// child: TextField(
// controller: _playerOneScoreController,
// decoration: InputDecoration(
// hintText: "Score",
// border: OutlineInputBorder(
// borderSide: Divider.createBorderSide(context)),
// focusedBorder: OutlineInputBorder(
// borderSide: Divider.createBorderSide(context)),
// enabledBorder: OutlineInputBorder(
// borderSide: Divider.createBorderSide(context)),
// filled: true,
// contentPadding: const EdgeInsets.all(8),
// ),
// onSubmitted: (text) {
// thrownScoresOne.add(text);
// _playerOneScoreController.clear();
// setState(() {});
// },
// ),
// ),
// ),
],
),
Column(
children: [
Container(
child: Text("Player two"),
),
Container(
child: Text(playerTwo501.toString()),
),
// Expanded(
// child: ListView.builder(
// shrinkWrap: true,
// itemCount: thrownScoresTwo.length,
// itemBuilder: (BuildContext context, int index) {
// return Text(thrownScoresTwo[index]);
// }),
// ),
// Flexible(
// child: Container(
// child: TextField(
// controller: _playerTwoScoreController,
// decoration: InputDecoration(
// hintText: "Score",
// border: OutlineInputBorder(
// borderSide: Divider.createBorderSide(context)),
// focusedBorder: OutlineInputBorder(
// borderSide: Divider.createBorderSide(context)),
// enabledBorder: OutlineInputBorder(
// borderSide: Divider.createBorderSide(context)),
// filled: true,
// contentPadding: const EdgeInsets.all(8),
// ),
// onSubmitted: (text) {
// thrownScoresTwo.add(text);
// _playerTwoScoreController.clear();
// setState(() {});
// },
// ),
// ),
// ),
],
),
],
),
),
),
);
}
}
I've tried with singlescrollview but that also doesnt help my problem.
Wrap Row's Column with Expanded widget.
class _GamePageState extends State<GamePage> {
List<String> thrownScoresOne = [];
List<String> thrownScoresTwo = [];
int playerOne501 = 501;
int playerTwo501 = 501;
final TextEditingController _playerOneScoreController =
TextEditingController();
final TextEditingController _playerTwoScoreController =
TextEditingController();
#override
void dispose() {
_playerOneScoreController.dispose();
_playerTwoScoreController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Game"),
),
body: SafeArea(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 32),
width: double.infinity,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
child: Column(
children: [
Container(
child: Text("Player one"),
),
Container(
child: Text(playerOne501.toString()),
),
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: thrownScoresOne.length,
itemBuilder: (BuildContext context, int index) {
return Text(thrownScoresOne[index]);
}),
),
Flexible(
child: Container(
child: TextField(
controller: _playerOneScoreController,
decoration: InputDecoration(
hintText: "Score",
border: OutlineInputBorder(
borderSide: Divider.createBorderSide(context)),
focusedBorder: OutlineInputBorder(
borderSide: Divider.createBorderSide(context)),
enabledBorder: OutlineInputBorder(
borderSide: Divider.createBorderSide(context)),
filled: true,
contentPadding: const EdgeInsets.all(8),
),
onSubmitted: (text) {
thrownScoresOne.add(text);
_playerOneScoreController.clear();
setState(() {});
},
),
),
),
],
),
),
Expanded(
child: Column(
children: [
Container(
child: Text("Player two"),
),
Container(
child: Text(playerTwo501.toString()),
),
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: thrownScoresTwo.length,
itemBuilder: (BuildContext context, int index) {
return Text(thrownScoresTwo[index]);
}),
),
Flexible(
child: Container(
child: TextField(
controller: _playerTwoScoreController,
decoration: InputDecoration(
hintText: "Score",
border: OutlineInputBorder(
borderSide: Divider.createBorderSide(context)),
focusedBorder: OutlineInputBorder(
borderSide: Divider.createBorderSide(context)),
enabledBorder: OutlineInputBorder(
borderSide: Divider.createBorderSide(context)),
filled: true,
contentPadding: const EdgeInsets.all(8),
),
onSubmitted: (text) {
thrownScoresTwo.add(text);
_playerTwoScoreController.clear();
setState(() {});
},
),
),
),
],
),
),
],
),
),
),
);
}
}

Scroll animation like yelp app in flutter

I'm trying to make a CustomScrollView similar to this:
I'm using a SliverAppBar but it seems that it is not the right way. My code so far:
CustomScrollView(
slivers: <Widget>[
SliverAppBar(
expandedHeight: 340,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
background: BackgroundImageWidget(),
centerTitle: true,
// title: Text("Search by cities or activitry in Kreis Kleve"),
title: SearchButtonWidget(),
),
),
),
SliverList(...)
What I get:
I cant figure out why the SearchButtonWidget is so huge at first. When it's shrinked it has the right size.
Is sliverAppBar with fliexibleSpace even the right approach?
Edit: can someone also tell me how to make the search button overlapping with the widget below? I guess sliverAppBar can't do that.
Edit 2: maybe it's a white background added under the image. I need to investigate this.
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
top: true,
child: CustomScrollView(
slivers: <Widget>[
SliverPersistentHeader(
delegate: MySliverAppBar(
expandedHeight: 250,
title: Container(
margin: EdgeInsets.symmetric(horizontal: 20.0, vertical: 0),
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.all(Radius.circular(5.0))),
child: Row(children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 20.0, right: 10.0),
child: Icon(Icons.search),
),
Expanded(
child: TextFormField(
keyboardType: TextInputType.text,
textInputAction: TextInputAction.done,
cursorColor: Colors.black,
autofocus: false,
decoration: InputDecoration(
filled: true,
fillColor: Colors.transparent,
contentPadding: EdgeInsets.symmetric(
vertical: 10, horizontal: 15),
hintText: "Search",
border: InputBorder.none,
disabledBorder: OutlineInputBorder(
borderSide:
new BorderSide(color: Colors.transparent),
borderRadius: new BorderRadius.circular(2),
),
focusedBorder: OutlineInputBorder(
borderSide:
new BorderSide(color: Colors.transparent),
borderRadius: new BorderRadius.circular(2),
)),
),
)
]),
)),
pinned: true,
),
SliverList(
delegate: SliverChildBuilderDelegate((context, index) {
return Container(
child: ListTile(
title: Text("${index}a"),
));
}, childCount: 25))
],
),
),
);
}
.
class MySliverAppBar extends SliverPersistentHeaderDelegate {
final double expandedHeight;
final Widget title;
MySliverAppBar({#required this.expandedHeight, this.title});
final _avatarMarginTween = EdgeInsetsTween(
begin: EdgeInsets.only(bottom: 20),
end: EdgeInsets.only(
bottom: 0.0,
));
final _searchMarginTween = EdgeInsetsTween(
begin: EdgeInsets.only(bottom: 0),
end: EdgeInsets.only(bottom: 8,));
final _avatarAlignTween =
AlignmentTween(begin: Alignment.bottomCenter, end: Alignment.center);
#override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
double tempVal = 75 * maxExtent / 100;
final progress = shrinkOffset > tempVal ? 1.0 : shrinkOffset / tempVal;
final avatarMargin = _avatarMarginTween.lerp(progress);
final searchMargin = _searchMarginTween.lerp(progress);
final searchAlignment = progress > 0.8 ? _avatarAlignTween.lerp(progress) : _avatarAlignTween.lerp(0);
return Stack(
fit: StackFit.expand,
overflow: Overflow.visible,
children: <Widget>[
Padding(
padding: avatarMargin,
child: Image.network(
"https://images.pexels.com/photos/396547/pexels-photo-396547.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
fit: BoxFit.cover,
),
),
Center(
child: Opacity(
opacity: shrinkOffset / expandedHeight > 0.7 ? shrinkOffset / expandedHeight : 0.0,
child: Container(
color: Colors.red,
)
),
),
Padding(
padding: searchMargin,
child: Align(
alignment: Alignment.bottomCenter,
child: title,
),
)
],
);
}
#override
double get maxExtent => expandedHeight;
#override
double get minExtent => kToolbarHeight;
#override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true;
}

Design this animation using SliverAppBar flutter

Here's what I want to build but I am able to achieve this
by the following code,
#override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled){
return [
SliverAppBar(
expandedHeight: 120,
floating: false,
pinned: false,
flexibleSpace: Container(
padding: EdgeInsets.all(10),
height: 160,
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Align(
alignment: Alignment.topCenter,
child: Text(
'Hello World',
)),
Padding(
padding: EdgeInsets.only(top: 16),
child: Image.asset(
'assets/images/banner.png',
),
),
],
),
),
),
];
},
body: ListView.builder(),
),
);
}
I have tried SliverAppBar using flexible and expanded, but was not able to achieve.
Update -
First element of list is going behind text field. I want to scroll only when the animation is completed
updated answer,
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
TransitionAppBar(
extent: 250,
avatar: Text("Rancho"),
title: Container(
margin: EdgeInsets.symmetric(horizontal: 20.0, vertical: 0),
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.all(Radius.circular(5.0))),
child: Row(children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 20.0, right: 10.0),
child: Icon(Icons.search),
),
Expanded(
child: TextFormField(
keyboardType: TextInputType.text,
textInputAction: TextInputAction.done,
cursorColor: Colors.black,
autofocus: false,
style: TextField_Style,
decoration: InputDecoration(
filled: true,
fillColor: Colors.transparent,
contentPadding:
EdgeInsets.symmetric(vertical: 10, horizontal: 15),
hintText: "Search",
border: InputBorder.none,
disabledBorder: OutlineInputBorder(
borderSide: new BorderSide(color: Colors.transparent),
borderRadius: new BorderRadius.circular(2),
),
focusedBorder: OutlineInputBorder(
borderSide: new BorderSide(color: Colors.transparent),
borderRadius: new BorderRadius.circular(2),
)),
),
)
]),
),
),
SliverList(
delegate: SliverChildBuilderDelegate((context, index) {
return Container(
color: Colors.blue,
child: ListTile(
title: Text("${index}a"),
));
}, childCount: 25))
],
),
);
}
.
class TransitionAppBar extends StatelessWidget {
final Widget avatar;
final Widget title;
final double extent;
TransitionAppBar({this.avatar, this.title, this.extent = 250, Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return SliverPersistentHeader(
pinned: true,
delegate: _TransitionAppBarDelegate(
avatar: avatar,
title: title,
extent: extent > 200 ? extent : 200
),
);
}
}
class _TransitionAppBarDelegate extends SliverPersistentHeaderDelegate {
final _avatarMarginTween = EdgeInsetsTween(
begin: EdgeInsets.only(bottom: 70, left: 30),
end: EdgeInsets.only(left: 0.0, top: 30.0));
final _avatarAlignTween =
AlignmentTween(begin: Alignment.bottomLeft, end: Alignment.topCenter);
final Widget avatar;
final Widget title;
final double extent;
_TransitionAppBarDelegate({this.avatar, this.title, this.extent = 250})
: assert(avatar != null),
assert(extent == null || extent >= 200),
assert(title != null);
#override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
double tempVal = 34 * maxExtent / 100;
final progress = shrinkOffset > tempVal ? 1.0 : shrinkOffset / tempVal;
print("Objechjkf === ${progress} ${shrinkOffset}");
final avatarMargin = _avatarMarginTween.lerp(progress);
final avatarAlign = _avatarAlignTween.lerp(progress);
return Stack(
children: <Widget>[
AnimatedContainer(
duration: Duration(milliseconds: 100),
height: shrinkOffset * 2,
constraints: BoxConstraints(maxHeight: minExtent),
color: Colors.redAccent,
),
Padding(
padding: avatarMargin,
child: Align(
alignment: avatarAlign,
child: avatar
),
),
Padding(
padding: EdgeInsets.only(bottom: 10),
child: Align(
alignment: Alignment.bottomCenter,
child: title,
),
)
],
);
}
#override
double get maxExtent => extent;
#override
double get minExtent => (maxExtent * 68) / 100;
#override
bool shouldRebuild(_TransitionAppBarDelegate oldDelegate) {
return avatar != oldDelegate.avatar || title != oldDelegate.title;
}
}

showModalBottomSheet triggers Futurebuilder

I'm really frustrated on this one.
I have 3 functions that calls showModalBottomSheet in each function.
2 Modals that are Stateful and 1 Stateless.
I'm having problem with the other Stateful Modal.
They are both called using InkWell's onTap function. and both are also not occupying the whole screen therefore shows the main page.
MY STATEFUL MODAL THAT DOESN'T TRIGGER THE FUTURE/ DOESN'T REFRESH THE PAGE:
void showCommentsModal(int id) {
showModalBottomSheet(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
backgroundColor: Color(colorBackground),
isScrollControlled: true,
context: context,
builder: (BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
color: Color(colorBackground),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20), topRight: Radius.circular(20))),
height: MediaQuery.of(context).size.height / 1.5,
width: MediaQuery.of(context).size.width,
child: ViewCommentModal(
postID: id,
userList: userList,
),
);
},
);
}
THE OTHER STATEFUL MODAL THAT TRIGGERS THE FUTURE/ REFRESHES THE LIST:
addCommentModal(int i) {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
padding:
EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: AddCommentModal(
onPost: (String text) {
APIServices.commentPost(context, i.toString(), text);
Navigator.pop(context);
},
),
);
},
);
}
what makes the addCommentModal trigger the future? please help.
EDIT:
I've caught the suspect!
here is my AddCommentModal code:
class AddCommentModal extends StatefulWidget {
final ValueChanged<String> onPost;
AddCommentModal({#required this.onPost});
#override
_AddCommentModalState createState() => _AddCommentModalState();
}
class _AddCommentModalState extends State<AddCommentModal> {
final commentController = TextEditingController();
String defaultProfilePhoto = "";
#override
void initState() {
defaultProfilePhoto = Constants.userFirstName[0].toUpperCase();
super.initState();
}
#override
void dispose() {
commentController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
child: Row(
children: <Widget>[
Container(
width: 50,
height: 50,
child: ClipRRect(
borderRadius: new BorderRadius.circular(50),
child: Constants.userProfilePhoto == null
? Container(
color: Color(colorPrimary),
alignment: Alignment.center,
child: Text(
defaultProfilePhoto,
style: TextStyle(
color: Color(colorText), fontSize: 20),
),
)
: Image.network(
APIServices.httpDomain + Constants.userProfilePhoto,
fit: BoxFit.cover,
)),
),
Expanded(
child: Container(
margin: EdgeInsets.only(
left: 10,
),
child: TextFormField(
controller: commentController,
decoration: new InputDecoration(
suffixIcon: IconButton(
onPressed: () => widget.onPost(commentController.text),
icon: Icon(
FontAwesomeIcons.paperPlane,
size: 15,
color: Theme.of(context).primaryColor,
)),
contentPadding: EdgeInsets.all(10),
hintText: "Add a comment ...",
fillColor: Colors.white,
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(20.0),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(20)),
borderSide:
BorderSide(width: 1, color: Color(0xFFff8b50)))),
keyboardType: TextInputType.text,
style: new TextStyle(fontFamily: "Poppins", fontSize: 15),
),
))
],
));
}
}
The issue that causes the page to refresh is because of the SoftKeyboard that pops up whenever the TextFormField is focused.
When I show the the modal, it runs smoothly. but when I start to tap the field, the page refreshes as if the future is once again called.

How to reuse a widget in flutter

I am learning flutter I want a particular widget to be reused with different images at run time.
How to attain this is giving me difficulties I would like to know how to get this.
I am writing the peice of code kindly suggest what is a correct way
scaffold: CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
trailing: Image.asset('assets/Menu_Button.png'),
automaticallyImplyLeading: false,
backgroundColor: Colors.blueAccent,
),
child: SafeArea(
child: Material(
child: Container(
child: Column(
children: [
Column(
children: <Widget>[
new Stack(children: <Widget>[
new Container(
child: background.Row1
),
Container(
color: Colors.blueAccent,
child: Image.asset('assets/card_bg.png')
),
]
),
Container(
color: Colors.blueAccent,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ShowingOptions('assets/image1.png').Options,//*****calling function with parameter so that it can put widget**********//
ShowingOptions('assets/image2.png').Options,
ShowingOptions('assets/image3.png').Options,
ShowingOptions('assets/image4.png').Options,
],
),
background.Row2,
background.Row3
],
),
),
))
),
);
}
}
/**********function defination starts *************/
ShowingOptions(image) {
Widget Options = padding: EdgeInsets.only(bottom: 5, left: 7,
right: 7, top: 5),
child: Container(
height: 55.0,
width: 55.0,
child: Padding(
padding: EdgeInsets.all(1),
child: CircleAvatar(
backgroundColor: Colors.transparent,
radius: 10,
child: new Image.asset(image, height: 150, width:
150),
)),
decoration: new BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
border: new Border.all(
color: Colors.orange,
width: 5.0,
),
)
),
);
}
}
/**********function defination ends *************/
What Iam doing is making a funciton and when I am calling the function 'showOptions('assets/image1')' I am passing the image that I need to show.
Inside the function defination I am writing a widget that I wanted to be placed whenevr I call that funcition bys showing the image that I have passed
the way I implemented this whole is not working want a solution. I know this is not the proper way as I am new I would like to have some guidance.
Create a Custom Widget,
Create a Stateless or Stateful Class
declare Required Vairables
return your Custom Widget
below is Example of CustomButton with onPressed event.
//Create a Stateless or Stateful Class
class CustomButton extends StatelessWidget {
//declare Required Vairables
final String buttonText;
final VoidCallback onPressed;
final bool loading;
//constructor
CustomButton({this.buttonText,this.onPressed,this.loading});
#override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 30,right: 30),
child: Container(
decoration: BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(100)),
color: Colors.red),
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.all(Radius.circular(100)),
splashColor: Colors.green,
onTap: onPressed,
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Center(child:
loading==true?
CircularProgressIndicator(backgroundColor: Colors.white,)
:
Text(buttonText,style: TextStyle(fontSize: 30,color: Colors.white),)),
),
),
),
),
),
),
],
);
}
}
Use :
CustomButtonSmall(buttonText: "Direction",onPressed: (){})
Here is a wonderfully explained example of how to achieve this easily.
I just copy the code from there. You basically have to create a separate class for the widget you have in mind:
import 'package:flutter/material.dart';
class AppTextFormField extends StatelessWidget {
//
AppTextFormField({
this.controller,
this.hintText,
this.helpText,
this.prefixIcon,
this.suffixIcon,
this.isPassword,
this.enabled,
this.readOnly,
this.borderColor,
});
final TextEditingController controller;
final String hintText;
final String helpText;
final IconData prefixIcon;
final IconData suffixIcon;
final bool isPassword;
final bool enabled;
final bool readOnly;
final Color borderColor;#override
Widget build(BuildContext context) {
return Container(
child: TextFormField(
controller: controller,
readOnly: null == readOnly ? false : true,
obscureText: null == isPassword ? false : true,
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.greenAccent,
width: 1.0,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.greenAccent,
width: 1.0,
),
),
border: OutlineInputBorder(
borderSide: BorderSide(
color: null == borderColor ? Colors.teal : borderColor,
width: 1.0,
),
),
hintText: null == hintText ? '' : hintText,
helperText: null == helpText ? '' : helpText,
prefixIcon: null == prefixIcon ? null : Icon(prefixIcon),
suffix: null == suffixIcon ? null : Icon(suffixIcon),
enabled: null == enabled ? true : false,
),
),
);
}
}
And then in the class where you want to use the widget you call the it like this:
Container(
child: Column(
children: [
AppTextFormField(
controller: _emailController,
helpText: 'Email',
hintText: 'Email',
prefixIcon: Icons.email,
),
AppTextFormField(
controller: _passwordController,
helpText: 'Password',
hintText: 'Password',
isPassword: true,
prefixIcon: Icons.lock_open,
),
You don't have to use all the methods, just the ones you need.