How can I make the whole page scrollable? - widget

Instead of just scrollable FirebaseAnimatedList, I want to make the whole page scrollable i.e. the parent Column widget that includes the form and the FirebaseAnimatedList.
I'm stuck at this since long and tried various different widget but couldn't make it.
Please Help.
Column(
children: <Widget>[
Flexible(
flex: 0,
child: Center(
child: Form(
key: formkey,
child: Flex(
direction: Axis.vertical,
children: <Widget>[
ListTile(
leading: Icon(Icons.subject),
title: TextFormField(
initialValue: "",
onSaved: (val) => board.subject = val,
validator: (val) => val == "" ? val : null,
),
),
ListTile(
leading: Icon(Icons.message),
title: TextFormField(
initialValue: "",
onSaved: (val) => board.body = val,
validator: (val) => val == "" ? val : null,
),
),
Padding(
padding: EdgeInsets.all(10.0),
child: FlatButton(
child: Text(
"POST",
style: TextStyle(color: Colors.white),
),
color: Colors.blueGrey,
onPressed: () {
handleSubmit();
},
),
),
],
),
),
),
),
Flexible(
child: FirebaseAnimatedList(
query: databaseReference,
itemBuilder: (_, DataSnapshot snapshot,
Animation<double> animation, int index) {
return Card(
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.blueAccent,
),
title: Text(boardMessages[index].subject),
subtitle: Text(boardMessages[index].body),
),
);
},
),
),
],
),
With SingleChildScrollView I'm able to scroll the page by holding form widget but it doesn't scroll by holding the FirebaseAnimatedList widget.
LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
return SingleChildScrollView(
child: new ConstrainedBox(
constraints: new BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
child: new Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
new Container(
height: 180.0,
child: Center(
child: Form(
key: formkey,
child: Flex(
direction: Axis.vertical,
children: <Widget>[
ListTile(
leading: Icon(Icons.subject),
title: TextFormField(
initialValue: "",
onSaved: (val) => board.subject = val,
validator: (val) => val == "" ? val : null,
),
),
ListTile(
leading: Icon(Icons.message),
title: TextFormField(
initialValue: "",
onSaved: (val) => board.body = val,
validator: (val) => val == "" ? val : null,
),
),
Padding(
padding: EdgeInsets.all(10.0),
child: FlatButton(
child: Text(
"POST",
style: TextStyle(color: Colors.white),
),
color: Colors.blueGrey,
onPressed: () {
handleSubmit();
},
),
),
],
),
),
),
),
new Container(
height: 2000.0,
child: FirebaseAnimatedList(
query: databaseReference,
itemBuilder: (_, DataSnapshot snapshot,
Animation<double> animation, int index) {
return Card(
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.blueAccent,
),
title: Text(boardMessages[index].subject),
subtitle: Text(boardMessages[index].body),
),
);
},
),
),
],
),
),
);
},
)
And what should be the height of Container containing the FirebaseAnimatedList?

Try changing Column() to ListView() as so
also try adding a listview on the outside of your FirebaseAnimatedList
Container()
ListView(
children: <Widget>[
Flexible(
flex: 0,
child: Center(
child: Form(
key: formkey,
child: Flex(
direction: Axis.vertical,
children: <Widget>[
ListTile(
leading: Icon(Icons.subject),
title: TextFormField(
initialValue: "",
onSaved: (val) => board.subject = val,
validator: (val) => val == "" ? val : null,
),
),
ListTile(
leading: Icon(Icons.message),
title: TextFormField(
initialValue: "",
onSaved: (val) => board.body = val,
validator: (val) => val == "" ? val : null,
),
),
Padding(
padding: EdgeInsets.all(10.0),
child: FlatButton(
child: Text(
"POST",
style: TextStyle(color: Colors.white),
),
color: Colors.blueGrey,
onPressed: () {
handleSubmit();
},
),
),
],
),
),
),
),
Flexible(
child: FirebaseAnimatedList(
query: databaseReference,
itemBuilder: (_, DataSnapshot snapshot,
Animation<double> animation, int index) {
return Card(
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.blueAccent,
),
title: Text(boardMessages[index].subject),
subtitle: Text(boardMessages[index].body),
),
);
},
),
),
],
),

You want the whole page to be scrollable which means it need to wrap the content inside ScollView(ListView).
Which will make having scrollView(FirebaseAnimatedList) inside an another ScrollView(ListView). Flutter cannot handle this by its own. We have to give some more information to it.
Options:
Provide the height for the inner scrollView.
Container(
height: 500.0, //some constant value
child: FirebaseAnimatedList(...))
It doesn't scroll by holding the FirebaseAnimatedList widget.
Make the innerScollView not scrollable.
FirebaseAnimatedList(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: ...)
It does scroll by holding the FirebaseAnimatedList widget. Note: But it will load all the elements in the list(say you have 200 items, it will load all 200 items whether the item is visible or not).

You can add FirebaseAnimatedList and other items in ListView, like below:
ListView(
shrinkWrap: true,
children: <Widget>[
_buildCard(),
FirebaseAnimatedList(...),
]);
You should disable FirebaseAnimatedList scroll too
FirebaseAnimatedList(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true, ...)

Related

Flutter ListView condition only Displays the first item in a list

I am quite new to Flutter and Dart development.
I am trying to display a list of all of the items in a JSON List that match a particular criteria, with the criteria being a type of alcohol in this case. I have created an IF statement at the top of what the ListBuilder returns, but it only returns the first item in the list when it matches the criteria. For example, I have three objects where the category is "Rum", but it still only returns the first one. Any help or advice would be greatly appreciated! Thank you!
class CocktailCategoryList extends StatefulWidget {
#override
_CocktailListState createState() => _CocktailListState();
}
class _CocktailListState extends State<CocktailCategoryList> {
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: Container(
height: 55,
width: 55,
child: FittedBox(
child: Container(
height: 60,
width: 60,
child: FloatingActionButton(
backgroundColor: Color.fromRGBO(86, 99, 255, 100),
onPressed: () {
},
child: Icon(
Icons.shuffle,
color: Colors.white,
size: 35,
),
),
),
),
),
floatingActionButtonLocation:
FloatingActionButtonLocation.miniCenterDocked,
bottomNavigationBar: BottomAppBar(
elevation: 20,
shape: CircularNotchedRectangle(),
child: Container(
height: 55,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
iconSize: 30,
padding: EdgeInsets.only(left: 28),
icon: Icon(
Icons.home,
),
onPressed: () {
Navigator.pop(context);
},
),
IconButton(
iconSize: 30,
padding: EdgeInsets.only(right: 28),
icon: Icon(
Icons.list,
color: Colors.purple[700],
),
onPressed: () {},
),
IconButton(
iconSize: 30,
padding: EdgeInsets.only(left: 28),
icon: Icon(Icons.person),
onPressed: () {},
),
IconButton(
iconSize: 30,
padding: EdgeInsets.only(right: 28),
icon: Icon(Icons.search),
onPressed: () {},
),
],
),
),
),
appBar: AppBar(
backgroundColor: Colors.white,
iconTheme: IconThemeData(
color: Colors.black,
),
centerTitle: true,
title: Text(
"Cocktails",
style: TextStyle(color: Colors.black),
),
),
body: Center(
child: FutureBuilder(
builder: (context, snapshot) {
var cocktailData = json.decode(snapshot.data.toString());
return ListView.builder(
itemCount: cocktailData == null ? 0 : cocktailData.length,
itemBuilder: (BuildContext context, int index) {
if (cocktailData[index]['category'] == "Rum"){
Column(
children: [
SafeArea(
minimum: EdgeInsets.fromLTRB(15, 0, 15, 0),
child: GestureDetector(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CocktailPage(
cocktailData[index]['name'],
cocktailData[index]['subtitle'],
cocktailData[index]['category'],
cocktailData[index]['instructions'],
cocktailData[index]['image'],
cocktailData[index]['ingredients'],
))),
child: Container(
width: MediaQuery.of(context).size.width,
child: Wrap(children: [
Image(
image: NetworkImage(cocktailData[index]['image']),
),
]),
),
),
),
GestureDetector(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CocktailPage(
cocktailData[index]['name'],
cocktailData[index]['subtitle'],
cocktailData[index]['category'],
cocktailData[index]['instructions'],
cocktailData[index]['image'],
cocktailData[index]['ingredients'],
))),
child: ListTile(
visualDensity:
VisualDensity(horizontal: 0, vertical: -1),
title: Row(
children: [
Text(
cocktailData[index]['name'],
style: TextStyle(fontWeight: FontWeight.bold),
),
SizedBox(
width: 5,
),
CategoryTag(
cocktailData[index]['category']) //Button Here
],
),
subtitle: Text(cocktailData[index]['subtitle']),
),
),
SizedBox(height: 10)
],
);
}else {
SizedBox();
}
}
);
},
future:
DefaultAssetBundle.of(context).loadString('assets/testJson.json'),
),
),
);
}
}
One thing I noticed is that you are not returning the Column widget in your ListView.builder() inside of the if statement. The anonymous builder function that you provide to the ListView.builder() should always return a widget.

Flutter Expandable List View

how can i put my list view into a expandable list view
body: RefreshIndicator(
onRefresh: getData,
key: _refresh,
child: loading
? Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: list.length,
itemBuilder: (context, i) {
final x = list[i];
debugPrint(x.toString());
return Container(
padding: EdgeInsets.all(20.0),
child: Row(
children: <Widget>[
Expanded(
first will be shown is the transaction ID and the vessel name and theres a arrow down that when you click it will display all the information in it
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Transaction ID:\t' + x["transaction_id"],
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold),
),
Text('Vessel Name:\t' + x["vesselname"],
style: TextStyle(fontSize: 20.0)),
Text('Vessel Number:\t' + x["voyageno"],
style: TextStyle(fontSize: 20.0)),
Text('Ship Call #:\t' + x["scn"],
style: TextStyle(fontSize: 20.0)),
Text('Status:\t' + x["status"],
style: TextStyle(
fontSize: 20.0,
color: x["status"] == 'pending'
? Colors.red
: Colors.green)),
Divider()
],
),
),
],
),
);
},
),
));
}
}
You can use the Expandable Panel widget for that.

Pagination inside a CustomScrollView - Flutter

I have implemented a CustomScrollview in which i have the SliverGrid whereI'm successfully fetching the data from the server, but i need to provide the pagination over here, i need some assistance as how can acheive that whether by adding a button and incrementing the values or by adding an infinite scroll view and doing the pagination. But how to deal with the UI too is my problem here, so can any one assist me on this.
#override
Widget build(BuildContext context) {
print("Home");
return WillPopScope(
onWillPop: exitApp,
child: Scaffold(
appBar: AppBar(
leading: Image.asset('assets/images/ic_logo.png'),
actions: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: FlatButton.icon(
onPressed: () {},
icon: Icon(Icons.location_on),
label: Text('Mysuru, India'),
textColor: Colors.white,
),
),
],
),
body: CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: SizedBox(
child: _search(),
),
),
SliverToBoxAdapter(
child: SizedBox(
child: FutureBuilder(
future: _getCat(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Center(
child: CircularProgressIndicator(),
);
} else {
return Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Categories'),
GestureDetector(
onTap: (){
Navigator.push(context, MaterialPageRoute(builder: (context) => CategoriesScreen()));
},
child: Text('VIEW ALL >', style: TextStyle(decoration: TextDecoration.underline, color: Colors.redAccent),),
)
],
),
),
Container(
height: 120,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(2.0),
child: InkWell(
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => SubCategoriesScreen(snapshot.data[index].id,snapshot.data[index].title)));
},
child: Container(
width: 100,
child: ListTile(
title: Image.network(
snapshot.data[index].image,
height: 60,
width: 100,
),
subtitle: Container(
alignment: Alignment.topCenter,
child: Text(
snapshot.data[index].title,
style: TextStyle(fontSize: 10),
)),
),
),
),
);
// return Text(snapshot.data[index].id);
}),
),
],
);
}
},
),
),
),
SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 250.0,
mainAxisSpacing: 0.0,
crossAxisSpacing: 0.0,
childAspectRatio: 0.7,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return GestureDetector(
onTap: () {
print(data[index]['adid']);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ProductDetailsScreen(data[index]['adid'])));
},
child: Container(
margin: EdgeInsets.all(5),
decoration:
BoxDecoration(border: Border.all(color: Colors.grey)),
child: Padding(
padding: const EdgeInsets.all(10),
child: Column(
children: <Widget>[
Expanded(
flex: 5,
child: Align(
alignment: Alignment.center,
child: Image.network(
data[index]['adcoverimg'],
fit: BoxFit.cover,
),
),
),
SizedBox(
height: 10,
),
Expanded(
flex: 2,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'\u20B9' + data[index]['ads_price'],
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
data[index]['adname'],
style: TextStyle(fontWeight: FontWeight.w500),
maxLines: 1,
),
Text(
data[index]['addesc'],
maxLines: 1,
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Icon(
Icons.location_on,
size: 18,
),
Text(data[index]['ads_location'])
],
)
],
),
)
],
),
),
),
);
},
childCount: data == null ? 0 : data.length,
),
),
],
),
),
);
}
And this is how I'm fetching the data from the server
Future<String> getProducts() async {
String url = Constant.productsUrl;
Map<String, String> headers = {'Content-Type': 'application/json'};
final response = await http.get(url, headers: headers);
setState(() {
var jsonResponse = json.decode(response.body);
data = jsonResponse['record'];
});
}
And this is my URL http://url.com/Web_Api/viewads/startindex/limit/cityname

Flutter i want to display the data after searching

listviewGood day do you have an idea on how to make a search bar that do not show first the list view when no one searching my data is from mysql sorry new at flutter
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('New Transaction'),
backgroundColor: Color(0xff083663),
),
body: RefreshIndicator(
onRefresh: fetchNotes,
key: _refresh,
child: loading
? Center(
child: CircularProgressIndicator(),
)
: ListView.builder(
itemBuilder: (context, i) {
return i == 0 ? _searchBar() : _listItem(i - 1);
},
itemCount: _notesForDisplay.length + 1,
),
));
}
This is my search bar where the user will input his/her search
_searchBar() {
return Container(
padding: const EdgeInsets.all(10.0),
child: Card(
child: ListTile(
leading: Icon(Icons.search),
title: TextField(
decoration:
InputDecoration(hintText: "Search", border: InputBorder.none),
onChanged: (text) {
text = text.toLowerCase();
setState(() {
_notesForDisplay = _notes.where((note) {
var noTitle = note.vesselname.toLowerCase();
return noTitle.contains(text);
}).toList();
});
},
),
),
),
);
}
this is the list view for my search i want this to show after the user inputted a value in the search bar
_listItem(i) {
final x = _notesForDisplay[i];
return Container(
padding: EdgeInsets.all(20.0),
child: Row(
children: <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Vessel Name:\t' + x.vesselname,
style: TextStyle(fontSize: 18.0, fontWeight: FontWeight.bold),
),
Text('Voyage #:\t' + x.voyageno,
style: TextStyle(fontSize: 18.0)),
Text('Ship Call #:\t' + x.scn,
style: TextStyle(fontSize: 18.0)),
Divider()
],
),
),
IconButton(
icon: Icon(
Icons.add_circle_outline,
size: 30.0,
),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => Transaction(x)));
}),
],
),
);
}
}
Define a bool variable that indicate the visibility state of the list view:
bool _isListViewVisible = false;
Add it to the setState code block:
setState(() {
_isListViewVisible = true; //Or you can check the text length
_notesForDisplay = _notes.where((note) {
var noTitle = note.vesselname.toLowerCase();
return noTitle.contains(text);
}).toList();
});
Then put the list in a visibility widget:
return Visibility(
visible: _isListViewVisible,
child: Container(
padding: EdgeInsets.all(20.0),
child: Row(
children: <Widget>[
....
],
),
));

How to send arguments to another screen? Flutter

I am trying to send the arguments of a "participant" to another screen, I could do it with a ListView and load the list of events, but it is not working in the same way with the participants, now if the list works, but when I tap and I want to see the info of the "participant" everything comes out in null:
In this part I create the participant and generate the list to be able to visualize it, and by giving the tap I send the info of this (according to me)
Widget _crearListadoParticipantes() {
return FutureBuilder<List<Participantes>>(
future: eventosProvider.cargarParticipantes(evento, participantes),
builder: (context, snapshot) {
if ( snapshot.hasData ) {
final participantes = snapshot.data;
return ListView.builder(
itemCount: participantes.length,
itemBuilder: (context, i) {
return _crearParticipante(context, participantes[i], evento);
}
);
} else if (snapshot.hasError){
return Center(child: Text("${snapshot.error}"));
} else {
return Center( child: CircularProgressIndicator());
}
},
);
}
Widget _crearParticipante(BuildContext context, Participantes participantes, EventoModel evento) {
return Padding(
padding: EdgeInsets.all(12.0),
child: GestureDetector(
child: RichText(
softWrap: false,
text: TextSpan(
style: TextStyle(
color: Colors.black,
fontFamily: "Lato_LightItalic",
fontStyle: FontStyle.italic,
fontSize: 20.0,
fontWeight: FontWeight.w400
),
children: [
TextSpan(text: ' '+'${participantes.numero}',
style: TextStyle(
fontWeight: FontWeight.w600
)
),
TextSpan(text: " "),
TextSpan(text: '${participantes.apellido} ${participantes.nombre}',)
],
),
),
onTap: () => Navigator.pushNamed(context, 'destalleParticipante', arguments: evento),
),
);
}
And this is where I am supposed to receive the arguments of the participant to whom I tapped, but as I say, a null returns
class DetalleParticipante extends StatefulWidget {
#override
_DetalleParticipanteState createState() => _DetalleParticipanteState();
}
class _DetalleParticipanteState extends State<DetalleParticipante> {
final eventosProvider = new EventosProvider();
EventoModel evento = new EventoModel();
Participantes participantes = new Participantes();
#override
Widget build(BuildContext context) {
final EventoModel eventoData = ModalRoute.of(context).settings.arguments;
if ( eventoData != null ) {
evento = eventoData;
}
print(participantes.nombre);
return Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(0),
child: AppBar(
backgroundColor: Color(0xFF249FE2),
),
),
backgroundColor: Colors.white,
body: Container(
color: Colors.white,
child: Column(
children: <Widget>[
_encabezadoParticipante(context, AssetImage("assets/icon/info_corredor.png"), participantes, evento),
],
),
),
);
}
Widget _backBottom() {
return FloatingActionButton(
elevation: 0.0,
backgroundColor: Colors.white,
child: Icon(
Icons.arrow_back,
size: 45.0,
color: Colors.black,
),
onPressed: (){
Navigator.pop(context);
},
);
}
Widget _encabezadoParticipante(BuildContext context, AssetImage image, Participantes participantes, EventoModel evento) {
return Container(
color: Colors.grey[600],
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
_backBottom(),
Flexible(
child: Padding(
padding: EdgeInsets.all(8.0),
child: Text('${participantes.apellido}',
textAlign: TextAlign.center,
maxLines: 3,
softWrap: true,
style: TextStyle(
color: Colors.white,
fontFamily: "Lato",
fontStyle: FontStyle.italic,
fontSize: 30.0,
fontWeight: FontWeight.bold
),
),
),
),
Image(image: image,
fit: BoxFit.cover,
),
],
),
),
);
}
}