How to navigate through PageView in Flutter? - flutter

I'm trying to make widgets behind a PageView clickable by wrapping it around a GestureDetector, but it doesn't work.
Is there another way I can do this?
My code:
new GestureDetector(
behavior: HitTestBehavior.translucent,
child: new PageView(
controller: _pageController,
children: _buildForegroundPages(),
),
),

What you need is to wrap each page inside your PageView in a GestureDetector, like this.
PageView(
children: [
//Page1
GestureDetector(
onTap: () {
print("Click page1");
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => NewPage()
));
},
child: Container(
color: Colors.red,
child: Center(
child: Text("text 1"),
),
),
),
//Page2
GestureDetector(
onTap: () {
print("Click page2");
},
child: Container(
color: Colors.blue,
child: Center(
child: Text("text 1"),
),
)),
//Page3
GestureDetector(
onTap: () {
print("Click page3");
},
child: Container(
color: Colors.green,
child: Center(
child: Text("text 1"),
),
)),
],
);

Related

How can I change the labels of the Continue/Cancel buttons in flutter stepper?

Is there any way to change the text labels of the Continue and Cancel Buttons of the stepper in flutter? Stepper seems to be the perfect choice for what I want to do (long form with several "stages") and before I go try to build one from scratch just to get other labels for the buttons I thought I may ask..
Anybody knows if/how thats possible?
Yes, you can by providing a controlsBuilder callback. Which has to be a function that takes two other functions (onStepContinue and onStepCancel) which are the actions that you will have to pass to the new buttons you'll create in order for them to act as they should.
Then you can declare anything you want (in this case a row with two buttons) as long you pass the two functions (onStepContinue and onStepCancel) for them to work as its expected:
Stepper(
controlsBuilder: (BuildContext context,
{VoidCallback? onStepContinue, VoidCallback? onStepCancel}) {
return Row(
children: <Widget>[
TextButton(
onPressed: onStepContinue,
child: const Text('NEXT'),
),
TextButton(
onPressed: onStepCancel,
child: const Text('EXIT'),
),
],
);
},
steps: const <Step>[
Step(
title: Text('A'),
content: SizedBox(
width: 100.0,
height: 100.0,
),
),
Step(
title: Text('B'),
content: SizedBox(
width: 100.0,
height: 100.0,
),
),
],
);
flutter version 2.8.1
inside the Stepper you can use controlsBuilder
you can change buttons
controlsBuilder: (context,_) {
return Row(
children: <Widget>[
TextButton(
onPressed: (){},
child: const Text('NEXT'),
),
TextButton(
onPressed: (){},
child: const Text('EXIT'),
),
],
);
},
controlsBuilder: (BuildContext context, ControlsDetails details) {
final _isLastStep = _currentStep == _getSteps.length - 1;
return Container(
margin: const EdgeInsets.only(top: 50),
child: Row(children: [
Expanded(
child: ElevatedButton(
child: Text(_isLastStep ? 'Send' : 'Next'),
onPressed: details.onStepContinue)),
const SizedBox(
width: 12,
),
if (_currentStep != 0)
Expanded(
child: ElevatedButton(
child: Text('Back'),
onPressed: details.onStepCancel))
]));
},
I m late for the discussion.
But i have just done it and think it is good to share.
The code is able to control the Text for each step as the code below.
Each step will have difference text, manage to do for 3 steps. If more than that, the code will be quite messy.
Hope it helps someone who is looking for it.
controlsBuilder: (BuildContext context,
{VoidCallback onStepContinue, VoidCallback onStepCancel}) {
return Row(
children: <Widget>[
_activeCurrentStep == 0
? TextButton(
onPressed: onStepContinue,
child: const Text('NEXT'),
)
: _activeCurrentStep == 1
? Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: onStepContinue,
child: const Text('NEXT'),
),
TextButton(
onPressed: onStepCancel,
child: const Text('BACK'),
),
],
),
)
: _activeCurrentStep >= 2
? Container(
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: onStepContinue,
child: const Text('SAVE'),
),
TextButton(
onPressed: onStepCancel,
child: const Text('BACK'),
),
],
),
)
: TextButton(
onPressed: onStepCancel,
child: const Text('BACK'),
),
],
);
},
Solution for flutter version > 2.8.1
In flutter version > 2.8.1 you can not use this for change the labels or buttons:
controlsBuilder: (context, {onStepContinue, onStepCancel}) {...}
Use this:
controlsBuilder: (context, _) {...}
Or this:
controlsBuilder: (context, onStepContinue) {...}
controlsBuilder: (context, onStepCancel) {...}
This is a complete example changing the labels text and colors:
Stepper(
controlsBuilder: (context, _) {
return Row(
children: <Widget>[
TextButton(
onPressed: () {},
child: const Text(
'NEXT',
style:
TextStyle(color: Colors.blue),
),
),
TextButton(
onPressed: () {},
child: const Text(
'EXIT',
style:
TextStyle(color: Colors.blue),
),
),
],
);
},
//Rest of the Stepper code (currentStep, onStepCancel, onStepContinue, steps...)
//...
)

flutter: how to customize cuperinoAlertDialog style?

I'm working with flutter. I want to make a CupertinoAlertDialog(iOS style is required). My problem is UI designers require the background color of the alert dialog should be #F0F0F0. But I can only adjust its theme into dark or light(e.g. following picture). The code I completed is placed below.
showCupertinoDialog(
context: context,
builder: (BuildContext context){
return Theme(
data: ThemeData.dark(),
child: CupertinoAlertDialog(
title: Text('Title'),
content: Text('Some message here'),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Cancle'),
),
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('OK'),
),
],
),
);
}
);
Is that possible? Thanks for any advice.
If I recall correctly, the background color for CupertinoAlertDialog is hardcoded. However, you can create a custom dialog that can change the background color of it as well as the functions of the buttons.
You need to create a type Dialog for the showDialog function instead of showCupertinoDialog:
Dialog customDialog = Dialog(
backgroundColor: Color(0xfff0f0f0), // your color
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(40)), // change 40 to your desired radius
child: CustomAlertDialog(),
);
I also created a stateless widget called CustomAlertDialog, but if you don't want to, you can replace the CustomAlertDialog() with its content.
class CustomAlertDialog extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
height: 150,
child: Column(
children: [
Expanded(
flex: 2,
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Colors.grey, width: 1),
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
child: Center(
child: Text(
"Title",
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 20),
),
),
),
Container(
child: Center(
child: Text("Some message here"),
),
),
],
),
),
),
Expanded(
flex: 1,
child: Row(
children: [
Expanded(
flex: 1,
child: GestureDetector(
child: Container(
decoration: BoxDecoration(
border: Border(
right: BorderSide(color: Colors.grey, width: 1),
),
),
child: Center(
child: Text("Cancel"),
),
),
onTap: () {
Navigator.of(context).pop(); // replace with your own functions
},
),
),
Expanded(
flex: 1,
child: GestureDetector(
child: Container(
child: Center(
child: Text("OK"),
),
),
onTap: () {
Navigator.of(context).pop(); // replace with your own functions
},
),
),
],
),
),
],
),
);
}
}
Lastly, replace your whole showCupertinoDialog with this showDialog function:
showDialog(
barrierDismissible: true, // set false if you dont want the dialog to be dismissed when user taps anywhere [![enter image description here][1]][1]outside of the alert
context: context,
builder: (context) {
return customDialog;
},
);
Result: https://i.stack.imgur.com/cV13A.png

Flutter How to partially block touch event inside GestureDetector

I have a listview with every Item wrap inside a GestureDetector to be clickable, but is there a way to have a portion of the Item view to be not clickable? Thanks
GestureDetector(
onTap: () {
...
},
behavior: HitTestBehavior.opaque,
child: Column(
children: <Widget>[
child: SizedBox( height: 40,
child: Container(
color: Colors.green,
child: Text("Hello world"), // want to make the text area not clikable
),
),
someOtherWidgets...
],
),
Yes then you have to take particular item click and it should be blank in that case, Example InkWell click and child Text
InkWell(
onTap: () {
...
},
behavior: HitTestBehavior.opaque,
child: Column(
children: <Widget>[
child: SizedBox( height: 40,
child: Container(
color: Colors.green,
child: GestureDetector(
onTap: (){}
,
child:Text("PBX",style: TextStyle(fontSize: 15.0),)), // you can use like this text will be blank click
),
),
someOtherWidgets...
],
),

Loop Cards Flutter

I have been researching Flutter and a question arose --
I have an array with some information, and I need to add cards based on this array.
Currently, I create a loop and add the cards which follow the structure of my array and my program listed below. Note that when I call statement passing the parameters, the code runs without any problem, but the following code does not work for me:
import "package:acessorias/pages/global.variables.dart";
import "package:flutter/material.dart";
class Comunicados extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
title: Center(
child: SizedBox(
width: 150,
child: Image.asset("assets/image/logo.png"),
),
),
actions: <Widget>[
Container(
width: 60,
child: FlatButton(
child: Icon(
Icons.search,
color: Color(0xFFBABABA),
),
onPressed: () => {},
),
),
],
),
body: Container(
color: Color(0xFFF2F3F6),
child: ListView(
children: <Widget>[
comunicado(comunicados[0]["LogNome"], comunicados[0]["EmComDTH"],
comunicados[0]["EmComDesc"]),
comunicado(comunicados[1]["LogNome"], comunicados[1]["EmComDTH"],
comunicados[1]["EmComDesc"]),
comunicado(comunicados[2]["LogNome"], comunicados[2]["EmComDTH"],
comunicados[2]["EmComDesc"]),
comunicado(comunicados[3]["LogNome"], comunicados[3]["EmComDTH"],
comunicados[3]["EmComDesc"]),
comunicado(comunicados[4]["LogNome"], comunicados[4]["EmComDTH"],
comunicados[4]["EmComDesc"]),
comunicado(comunicados[5]["LogNome"], comunicados[5]["EmComDTH"],
comunicados[5]["EmComDesc"])
],
),
),
);
}
}
Widget comunicado(user, data, msg) {
return Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage("assets/image/foto.png"),
),
title: new Text(user),
subtitle: Text(data),
trailing: Icon(Icons.more_vert),
),
/*Container(
child: Image.asset("assets/image/post.png"),
),*/
Container(
padding: EdgeInsets.all(10),
child: Text(msg),
),
ButtonTheme.bar(
child: ButtonBar(
children: <Widget>[
FlatButton(
child: Icon(Icons.favorite),
onPressed: () {},
),
FlatButton(
child: Icon(Icons.share),
onPressed: () {},
),
],
),
),
],
),
);
}
Solution
body: ListView.builder(
itemCount: comunicados.length,
itemBuilder: (context, index) {
/*return ListTile(
title: Text('${comunicados[index]}'),
);*/
return comunicado(comunicados[index]['LogNome'],
comunicados[index]["EmComDTH"], comunicados[index]["EmComDesc"]);
},
),
You can use data model in another dart file like Comunicado.dart
class Comunicado{
String user;
String data;
String msg;
Comunicado(
{this.user, this.data, this.msg});
}
after that you can make list of data model with the static data or etc like
List getComunicado(){
return[
Comunicado(
user: comunicados[0]["LogNome"],
data: comunicados[0]["EmComDTH"],
msg: comunicados[0]["EmComDesc"],
),
Comunicado(
user: comunicados[1]["LogNome"],
data: comunicados[1]["EmComDTH"],
msg: comunicados[1]["EmComDesc"],
),
]
}
in my case, i put it into initial state and don't forget to declare comm
#override
void initState() {
super.initState();
comm= getComunicado();
}
for custom card
Card makeCard(Comunicado newComm) => Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage("assets/image/foto.png"),
),
title: new Text("${newComm.user}"),
subtitle: Text("${newComm.data}"),
trailing: Icon(Icons.more_vert),
),
/*Container(
child: Image.asset("assets/image/post.png"),
),*/
Container(
padding: EdgeInsets.all(10),
child: Text("${newComm.msg}"),
),
ButtonTheme.bar(
child: ButtonBar(
children: <Widget>[
FlatButton(
child: Icon(Icons.favorite),
onPressed: () {},
),
FlatButton(
child: Icon(Icons.share),
onPressed: () {},
),
],
),
),
],
),
);
and for last you can call make card on listview
ListView.builder(
scrollDirection: Axis.vertical,
itemCount: comm.length,
itemBuilder: (BuildContext context, int index) {
return makeCard(comm[index]);
},
),

Expanded() widget not working in listview

I'm new to flutter. I'm trying to render a page whose body contains Listview with multiple widgets.
_buildOrderDetails widget in the listview is widget that is build with listview.builder() , remaining are normal widgets.
The problem is page is not being scrolled .
When the body Listview is changed to column and _buildOrderDetails is given as child to the Expanded, the listview is limited to some extent of the page height and being scrolled. But when input is focused the page is overflowed
Widget build(BuildContext context){
return ScopedModelDescendant<MainModel>(
builder: (BuildContext context, Widget child, MainModel model) {
return Scaffold(
appBar: AppBar(
title: Text('Order Details'),
actions: <Widget>[
IconButton(
onPressed: () {
model.addNewOrder();
},
icon: Icon(Icons.add),
),
BadgeIconButton(
itemCount: model.ordersCount,
badgeColor: Color.fromRGBO(37, 134, 16, 1.0),
badgeTextColor: Colors.white,
icon: Icon(Icons.shopping_cart, size: 30.0,),
onPressed: () {}
),
]
),
body: ListView(
children: [
Column(
children: [
_buildItemsTitle(),
Expanded(child: _buildOrderDetails(context, model)),
]
),
Card(
child: Column(
children:[
TextField(
decoration: InputDecoration(
labelText: 'Offer Code'
),
),
RaisedButton(
onPressed: (){},
child: Text('Apply'),
)
]
),
),
Card(child: _orderAmount(context, model),),
RaisedButton(
color: Theme.of(context).accentColor,
onPressed: (){},
child: Text('Checkout',
style: TextStyle(
fontSize: 20.0,
color: Colors.white
)
),
)
]
),);});}}
Maybe it can help someone in the future, but the trick seems to be: use ListView + LimitedBox(maxHeight) + Column ...
ListView(
padding: EdgeInsets.zero,
shrinkWrap: true,
children: [
FocusTraversalGroup(
child: Form(
key: _formKey,
child: LimitedBox(
maxHeight: MediaQuery.of(context).size.height,
child: Column(
// mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Spacer(flex: 30), // Or Expanded
// More Widgets...
Spacer(flex: 70), // Or Expanded
// ....
Try not to use expanded on growing items. If you want to cover a percentage/fractional height wrap the height with a fixed height or the full height with a container that includes box contstains, then proceed to have expanded or fixed height children. also helpful is the FracionalBox
In the example you showed there is no need for expanded, the children inside will give a content height and the SingleChildScrollView will automaticly handle scrolling based on children.
Widget build(BuildContext context) {
return ScopedModelDescendant<MainModel>(
builder: (BuildContext context, Widget child, MainModel model) {
return Scaffold(
appBar: AppBar(title: Text('Order Details'), actions: <Widget>[
IconButton(
onPressed: () {
model.addNewOrder();
},
icon: Icon(Icons.add),
),
BadgeIconButton(
itemCount: model.ordersCount,
badgeColor: Color.fromRGBO(37, 134, 16, 1.0),
badgeTextColor: Colors.white,
icon: Icon(
Icons.shopping_cart,
size: 30.0,
),
onPressed: () {}),
]),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Column(children: [
_buildItemsTitle(),
Container(child: _buildOrderDetails(context, model)),
]),
Card(
child: Column(children: [
TextField(
decoration: InputDecoration(labelText: 'Offer Code'),
),
RaisedButton(
onPressed: () {},
child: Text('Apply'),
)
]),
),
Card(
child: _orderAmount(context, model),
),
RaisedButton(
color: Theme.of(context).accentColor,
onPressed: () {},
child: Text('Checkout',
style: TextStyle(fontSize: 20.0, color: Colors.white)),
),
],
),
),
);
});
}