Flutter: How to display a text from Firebase? - ios

I have searched a lot but I can't find a solution for this specific problem:
So I want to display a text in my flutter application. But this text shall be variable, so I integrated Firebase to my project. And everything is working well, so I already managed to show images from Firebase but I really don't know how to display a text.
Can you please show me how to do this? Maybe someone could show me the code I need to use to make this work?
This is my code so far, I didn't integrate the specific code to communicate with my Firebase backend, because I don't know how to do this.
import 'package:flutter/material.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
class MapsPage extends StatefulWidget {
MapsPage({Key key}) : super(key: key);
#override
_MapsPageState createState() => _MapsPageState();
}
class _MapsPageState extends State<MapsPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Firebase'),
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xffFBD23E), Color(0xffF6BE03)],
begin: Alignment.topCenter,
end: Alignment.bottomCenter),
),
),
),
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xffFEFDFD), Color(0xffBDBDB2)],
begin: Alignment.topLeft,
end: Alignment.bottomRight),
),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(12.0),
child: RichText(
text: TextSpan(
style: TextStyle(color: Colors.black),
text: 'Some text',
children: [
TextSpan(
text:
'I want this TextSpan to be variable. So if I change the data in my Firestore Database this text shall also change.',
),
TextSpan(
text: 'And some more text.',
),
],
),
),
),
],
),
),
);
}
}
Can you please help me? Thank you so much!!
Below is a screenshot of my firestore.
.

// This below returns the text
Future<Map<String, dynamic>> getData() async {
DocumentReference<Map<String, dynamic>> document =
FirebaseFirestore.instance.doc('KBADatum/6j5Fnvj0gNkSCRIx7ecH'); // path to doc
DocumentSnapshot<Map<String, dynamic>> query = await document.get();
print(query.data());
return query.data();
}
// and this is how you consume it.
FutureBuilder<Map<String, dynamic>>(
future: getData(),
builder: (BuildContext context, AsyncSnapshot<Map<String, dynamic>> snapshot) {
if (snapshot.hasError) return CircularProgressIndicator();
if (snapshot.connectionState == ConnectionState.waiting)
return CircularProgressIndicator();
return RichText(
text: TextSpan(
style: TextStyle(color: Colors.black),
text: 'Some text',
children: [
TextSpan(
text: snapshot.data['DatumJahr'], // first text
),
TextSpan(
text: 'And some more text.',
),
],
),
);
},
)

The snapshots() method provides a stream which you can subscribe to get the latest document changes. To update your ui using the stream, you can use StreamBuilder which builds itself based on the latest snapshot of interaction.
One final thing is that you can't use StreamBuilder as a child to a TextSpan. So, you will either rebuild the RichText widget or use WidgetSpan to rebuild only the span when there is an event on your stream.
Here is an example:
RichText(
text: TextSpan(
style: TextStyle(color: Colors.black),
text: 'Some text',
children: [
// Use WidgetSpan instead of TextSpan, which allows you to have a child widget
WidgetSpan(
// Use StreamBuilder to listen on the changes of your Firestore document.
child: StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore.instance
.collection('my_collection')
.doc('my_document')
.snapshots(),
builder: (context, snapshot) {
final document = snapshot.data; // Get the document snapshot
final text = document?.data()?['my_text']; // Get the data in the text field
return Text(text ?? 'Loading...'); // Show loading if text is null
},
),
),
TextSpan(
text: 'And some more text.',
),
],
),
)
Note: I tried to keep the example simple as far as possible, but you can learn more about StreamBuilder to handle errors/data and the state of connection.

Related

Reusing widgets in flutter/dart

I have the following Flutter code, and I'm trying to figure out how to put section 1 into a separate class so that I can reuse it on multiple screens, and then separately (not at the same time, but instead of), how to put section 2 (which is a larger portion of code) into a separate class and how to reuse that on multiple pages with a variable to be able to change the title. Currently, I'm just copying and pasting the entire code into each screen, but I know there has to be a better way by reusing code.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
//------------------START SECTION 2---------------------------------------------
appBar: AppBar(
backgroundColor: Colors.blue,
title: Text(
"Welcome",
style: TextStyle(color: Colors.white),
),
actions: <Widget>[
// action button
//------------------START SECTION 1---------------------------------------------
PopupMenuButton<String>(
//onSelected: showMenuSelection
//icon: new Icon(Icons.add, color: Colors.blueGrey),
itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
const PopupMenuItem<String>(
value: 'Item 1', child: Text('Item 1')),
const PopupMenuItem<String>(
value: 'Item 2', child: Text('Item 2')),
],
),
//------------------END SECTION 1---------------------------------------------
],
),
//------------------END SECTION 2---------------------------------------------
body: Center(
child: Text('Hello World'),
),
),
);
}
}
VS code lets you extract the widget with a few clicks, If you're using VS code - select the line where code for widget starts. Hit Ctrl + ., select Extract widget option, enter name of your choice. And then you can customize extracted widget to take in different parameters and return widget accordingly. Same can be done with any IDE, but I am unaware of the procedure.
Edit 1: since I am unable to post screenshots right now, I found this SO answer that could help. :) https://stackoverflow.com/a/51235410/4794396
You can try this. I'm doing this way. I've created a class in which there's a function which holds my AppBar in main.dart file.
Example:
class MyAppBar {
setAppBar(context, String title) {
return new AppBar(
backgroundColor: Colors.blue,
title: Text(
title,
style: TextStyle(color: Colors.white),
),
actions: <Widget>[
// action button
//------------------START SECTION 1---------------------------------------------
PopupMenuButton<String>(
//onSelected: showMenuSelection
//icon: new Icon(Icons.add, color: Colors.blueGrey),
itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
const PopupMenuItem<String>(
value: 'Item 1', child: Text('Item 1')),
const PopupMenuItem<String>(
value: 'Item 2', child: Text('Item 2')),
],
),
//------------------END SECTION 1---------------------------------------------
],
);
}
}
Usage will be, you have to import your main.dart file in the files where you want to set AppBar.
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color.fromRGBO(255, 255, 255, 20.0),
appBar: MyAppBar().setAppBar(context, 'Title for AppBar'),
body: new Container(), // your body goes here.
);
}
You can set the popup menu the same way. I'll give an example but you'll have to make it work your way.
class PopupMenuButtonBuilder {
setPopupButton() {
return <Widget>[
PopupMenuButton<String>(
//onSelected: showMenuSelection
//icon: new Icon(Icons.add, color: Colors.blueGrey),
itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
const PopupMenuItem<String>(
value: 'Item 1',
child: Text(
'Item 1',
),
),
const PopupMenuItem<String>(
value: 'Item 2',
child: Text(
'Item 2',
),
),
],
),
];
}
}
Usage of above class will be:
// this `actions` is of `AppBar`.
actions: PopupMenuButtonBuilder().setPopupButton(),
If you want to have different name of the PopupMenuItem you can pass the title in setPopupButton() function.

Flutter: how to add several filters to a List and show the new results

I started learning Flutter trying to make my first app. I don't have a developper's background, so I'm trying to learn everything by doin' it.
My app is receiving some user's data from a json file (name, surname, country, level, ...) and show the whole list of user's name and by tapping on a name a second page opens where you get all the details.
What I'd like to do now is to add a "settings page", where the user can filter, using two dropboxes, the country and/or the level.
If none of the dropboxes are selected the first page should show the whole list of persons by every country and from every level (as it does now), otherwise the list should be filtered to show only the persons from the country selected and only for the level selected.
I just need a hint about what to look for and study in order to realize it. Is my actual approach for the app ok?
Thanks alot for any kind of help.
Diego
main.dart
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'dart:convert';
//import pages
import './contactdetails.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'USDDN EU Judges',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'USDDN EU Judges'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Future<List<User>> _getUser() async {
var data = await http.get(
"https://www.disconnecteddog.com/home/json/usddneujudgesdatabase.json");
var jsonData = json.decode(data.body);
List<User> users = [];
for (var u in jsonData) {
User user = User(
u["Index"],
u["Name"],
u["Country"],
u["Level"],
u["Inthesportsince"],
u["Active"],
u["English"],
u["Email"],
u["Picture"]);
users.add(user);
}
print(users.length);
return users;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: <Widget>[
//
IconButton(icon: new Icon(Icons.filter_list, color: Colors.white,), onPressed: null)
],
),
body: Container(
child: FutureBuilder(
future: _getUser(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Container(
child: Center(child: Text("Loading judges database...")));
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: CircleAvatar(
backgroundImage:
NetworkImage(snapshot.data[index].picture),
),
title: Text(snapshot.data[index].name),
subtitle: Row(
children: <Widget>[
Text("Level: "),
Text(snapshot.data[index].level),
],
),
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) =>
DetailPage(snapshot.data[index])));
},
);
},
);
}
},
),
),
);
}
}
class User {
final int index;
final String name;
final String country;
final String level;
final String inthesportsince;
final String active;
final String english;
final String email;
final String picture;
User(this.index, this.name, this.country, this.level, this.inthesportsince,
this.active, this.english, this.email, this.picture);
}
Contactdetails.dart
import 'package:flutter/material.dart';
import 'package:usddn_judges/main.dart';
class DetailPage extends StatelessWidget {
final User user;
DetailPage(this.user);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(user.name),
),
body: Container(
//height: 120.0,
child: Padding(
padding: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 5.0),
child: Card(
margin: EdgeInsets.all(10.0),
elevation: 2.0,
child: new Column(
children: <Widget>[
new ListTile(
leading: new Icon(
Icons.account_box,
color: Colors.blue,
size: 26.0,
),
title: new Text(
user.name,
style: new TextStyle(fontWeight: FontWeight.w400),
),
),
new Divider(color: Colors.blue),
new ListTile(
leading: new Icon(
Icons.map,
color: Colors.blue,
size: 26.0,
),
title: Row(
children: <Widget>[
new Text("Country: "),
new Text(
user.country,
style: new TextStyle(fontWeight: FontWeight.w400),
),
],
),
),
new Divider(color: Colors.blue),
new ListTile(
leading: new Icon(
Icons.multiline_chart,
color: Colors.blue,
size: 26.0,
),
title: Row(
children: <Widget>[
new Text("Level: "),
new Text(
user.level,
style: new TextStyle(fontWeight: FontWeight.w400),
),
],
),
),
new Divider(color: Colors.blue),
new ListTile(
leading: new Icon(
Icons.language,
color: Colors.blue,
size: 26.0,
),
title: Row(
children: <Widget>[
new Text("English: "),
new Text(
user.english,
style: new TextStyle(fontWeight: FontWeight.w400),
),
],
),
),
new Divider(color: Colors.blue),
new ListTile(
leading: new Icon(
Icons.flash_on,
color: Colors.blue,
size: 26.0,
),
title: Row(
children: <Widget>[
new Text("Active: "),
new Text(
user.active,
style: new TextStyle(fontWeight: FontWeight.w400),
),
],
),
),
new Divider(color: Colors.blue),
new ListTile(
leading: new Icon(
Icons.event,
color: Colors.blue,
size: 26.0,
),
title: Row(
children: <Widget>[
new Text("In the sport since: "),
new Text(
user.inthesportsince,
style: new TextStyle(fontWeight: FontWeight.w400),
),
],
),
),
],
),
),
),
),
);
}
}
Main Contact List
Details Page
I think you should look into List.where().
https://api.dartlang.org/stable/2.1.0/dart-core/Iterable/where.html
By this you can filter your users based on the values within the filter.
users.where((user) => user.country == selectedCountry);
This is just an example, null handling and a smarter where clause is probably necessary.
I hope this will help you getting started.
Create a new Screen for filters, lets name it as FilterScreen. Then, you can use any state management framework (provider, BloC etc.) to store the filters that user entered in the FilterScreen. After returning the search screen, if there is any filter entered requery the list.

How expand text and container according text size?

I'm trying to create a card with a text within a container but I would like to show only a part of the text and when the user click on "show more", show the rest. I saw a Widget to construct text like this here, but I need expand the card container either and I don't know how to do that because I need to know how many lines the text have to expand with the correctly size. Exists a way to calculate the size according the number of lines or characters?
I tried to create the card as follows, where the DescriptionText is the Widget on the link and specify a minHeight in the Container in the hope of expanding the container along with the text but did not work.
Widget _showAnswerCard(Answer answer, User user) {
return Card(
elevation: 3.0,
color: Theme.of(context).backgroundColor,
child: Container(
constraints: BoxConstraints(minHeight: 90),
padding: EdgeInsets.all(10.0),
child: Flex(
direction: Axis.horizontal,
children: <Widget>[
Expanded(flex: 1, child: _showUserAvatar(answer)),
Expanded(flex: 3, child: _showAnswerDetails(answer, user)),
],
),
));
}
Widget _showAnswerDetails(Answer answer, User user) {
return Flex(
direction: Axis.vertical,
children: <Widget>[
Expanded(
flex: 3,
child: DescriptionTextWidget(text: answer.content),
),
Expanded(
flex: 1,
child: _showAnswerOptions(),
)
],
);
}
I'll really appreciate if someone could help me with that.
Just use Wrap widget to wrap your Card widget.
Based on your link for suggested answer. I did change to use Wrap widget.
Jus do copy/paste below code and check.
import 'package:flutter/material.dart';
class ProductDetailPage extends StatelessWidget {
final String description =
"Flutter is Google’s mobile UI framework for crafting high-quality native interfaces on iOS and Android in record time. Flutter works with existing code, is used by developers and organizations around the world, and is free and open source.";
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: const Text("Demo App"),
),
body: new Container(
child: new DescriptionTextWidget(text: description),
),
);
}
}
class DescriptionTextWidget extends StatefulWidget {
final String text;
DescriptionTextWidget({#required this.text});
#override
_DescriptionTextWidgetState createState() =>
new _DescriptionTextWidgetState();
}
class _DescriptionTextWidgetState extends State<DescriptionTextWidget> {
bool flag = true;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Wrap(
children: <Widget>[
Card(
margin: EdgeInsets.all(8),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
child: Column(
children: <Widget>[
Container(
child: Text(
widget.text,
overflow: flag ? TextOverflow.ellipsis : null,
style: TextStyle(
fontSize: 15,
),
),
),
InkWell(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text(
flag ? "show more" : "show less",
style: new TextStyle(color: Colors.blue),
),
],
),
onTap: () {
setState(() {
flag = !flag;
});
},
),
],
)),
),
],
);
}
}
Result:
The solution I can think of is to use two labels, one for displaying only one line of text and one for displaying all the text. When the button is clicked, the two labels are alternately displayed in an animated manner. There is no computer at the moment, it is not convenient to verify, I hope to give you some help in the implementation of the program.

How to place an image below a listview in flutter?

Using this simple design, how can I display the second image under the listview? In reality the list will be fetched from firebase where each item is an ExpansionTile, so the height of the listview can in no way be fixed.
The column should be scrollable so you can see the full image if you scroll down below the list.
import 'package:flutter/material.dart';
List<Widget> list = <Widget>[
ListTile(
title: Text('CineArts at the Empire',
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 20.0)),
subtitle: Text('85 W Portal Ave'),
leading: Icon(
Icons.theaters,
color: Colors.blue[500],
),
),
ListTile(
title: Text('The Castro Theater',
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 20.0)),
subtitle: Text('429 Castro St'),
leading: Icon(
Icons.theaters,
color: Colors.blue[500],
),
),
];
class CartWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return SafeArea(
child: Column(children: <Widget>[
Image.network("https://via.placeholder.com/350x150"),
Expanded(
child: ListView(
children: list,
),
),
Image.network("https://via.placeholder.com/350x500"), // error: hides above widget
]));
}
}
The way I understood your problem is that you want the bottom image to appear inside the list view instead of under it, as if it was just another item. Solution: Make it just another item!
More concrete, this is how your implementation for a helper function that enriches the list with the image may look like:
List<Widget> _buildListWithFooterImage(List<Widget> items) {
return items.followedBy([
Image.network("https://via.placeholder.com/350x500")
]);
}
Then, you could use that function during your build:
Widget build(BuildContext context) {
return SafeArea(
child: Column(
children: <Widget>[
Image.network("https://via.placeholder.com/350x150"),
Expanded(
child: ListView(
children: _buildListWithFooterImage(list)
)
),
]
)
);
}
Also, I believe your question is similar to this one.

Re: create a dropdown button in flutter

I have used a DropDownButton in my build but i want the arrow to be displayed at the end and the dropdown items to be displayed from arrow, but in my app they are displaying from the top. i have attached the screenshots for your reference.
please can you tell me how to change this or is there any other way to simply create a drop down menu.
An example would be much appreciated.
Please excuse my code as I am new to programming and any comments or suggestions are most welcome.
Many Thanks,
Mahi.
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'dart:ui';
void main(){
runApp(new BranchSetup());
}
class BranchSetup extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new _BranchSetupState();
}
}
class _BranchSetupState extends State<BranchSetup> with
WidgetsBindingObserver {
#override
Widget build(BuildContext context){
return new MaterialApp(
theme: new ThemeData(
primaryColor: const Color(0xFF229E9C),
),
title: 'Branch Setup',
home: new Scaffold(
body: new Container(
child: new ListView(
children: <Widget>[
new Container(
margin: const EdgeInsets.all(16.0),
child: new Row(
children: <Widget>[
new Expanded(
child: new TextFormField(
decoration: new InputDecoration(
labelText: 'Branch Name',
),
),
),
],
),
),
new Container(
margin: const EdgeInsets.all(16.0),
child:
new DropdownButton<String>(
items: <String>['Mens','Womans']
.map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}
).toList(),
onChanged: null,
),
),
],
),
),
),
);
}
}
This looks like a bug in Flutter. I filed an issue.
In the meantime, you can work around it by wrapping your DropdownButton in a Column.
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(home: new DemoApp()));
}
class DemoApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text('DropdownButton Example')),
body: new ListView(
children: [
new Column(
children: <Widget>[
new DropdownButton<String>(
items: <String>['Foo', 'Bar'].map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
onChanged: (_) {},
),
],
),
],
),
);
}
}
You can try out the plugin that I created : flutter_search_panel. Not a dropdown plugin, but you can display the items with the search functionality.
Use the following code for using the widget :
FlutterSearchPanel(
padding: EdgeInsets.all(10.0),
selected: 'a',
title: 'Demo Search Page',
data: ['This', 'is', 'a', 'test', 'array'],
icon: new Icon(Icons.label, color: Colors.black),
color: Colors.white,
textStyle: new TextStyle(color: Colors.black, fontWeight: FontWeight.bold, fontSize: 20.0, decorationStyle: TextDecorationStyle.dotted),
onChanged: (value) {
print(value);
},
),

Resources