Flutter: How to add a Listview under a scrollable Map - list

i have a problem. I want to create a list under the map that i created. The map is working, but if i want to put a list under the map i get some fails. This is an OpenStreetMap not Google Maps, cause i need it for my project. i just need advise how i can put a 'list' or a Text with icons under the map.
import 'package:flutter/material.dart';
import 'package:geolocation/geolocation.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong/latlong.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
/*create Controller for map
*MapController provides map properties and allows map movement
*/
MapController controller = new MapController();
//ask for permission to use the device's gps
getPermission() async {
final GeolocationResult result =
await Geolocation.requestLocationPermission(
permission: const LocationPermission(
//permission settings for android and ios
android: LocationPermissionAndroid.fine,
ios: LocationPermissionIOS.always));
return result;
}
/*if permission is granted, request current location (high accuracy)
*return coordinates of current location (Position)
*/
getLocation() {
return getPermission().then((result) async {
if (result.isSuccessful) {
final coords =
await Geolocation.currentLocation(accuracy: LocationAccuracy.best);
return coords;
}
});
}
//view map, move to current lat/long and zoom
buildMap() {
getLocation().then((response) {
response.listen((value) {
if (value.isSuccessful) {
controller.move(
new LatLng(value.location.latitude, value.location.longitude),
17.0);
}
});
});
}
//Application view
#override
Widget build(BuildContext context) {
return new Scaffold(
drawer: Drawer(
child:Container(
color: Color.fromRGBO(0, 111, 118, 0.9),
child: ListView(
// Important: Remove any padding from the ListView.
children: <Widget>[
Text('Menü',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white, fontSize: 25),),
ListTile(
title: Text('LogIn', style: TextStyle(color: Colors.white, fontSize: 20.0),),
leading: Icon(Icons.arrow_forward, color: Colors.white,),
onTap: () {
// Update the state of the app.
// ...
},
),
ListTile(
title: Text('Ort hinzufügen', style: TextStyle(color: Colors.white, fontSize: 20.0),),
leading: Icon(Icons.arrow_forward, color: Colors.white,),
onTap: () {
// Update the state of the app.
// ...
},
),
ListTile(
title: Text('Hilfe', style: TextStyle(color: Colors.white, fontSize: 20.0),),
leading: Icon(Icons.arrow_forward, color: Colors.white,),
onTap: () {
// Update the state of the app.
// ...
},
),
ListTile(
title: Text('Einstellungen', style: TextStyle(color: Colors.white, fontSize: 20.0),),
leading: Icon(Icons.arrow_forward, color: Colors.white,),
onTap: () {
// Update the state of the app.
// ...
},
),
],
),
),
),
appBar: new AppBar(
title: new Text('GeoGuide'),
backgroundColor: Color.fromRGBO(0, 111, 118, 0.8),
),
//create new FlutterMap
body: new Container(
width: 420,
height: 300,
child: new FlutterMap(
mapController: controller,
//center: current location
options: new MapOptions(center: buildMap(), minZoom: 15.0),
layers: [
//implement osm-template
new TileLayerOptions(
urlTemplate:
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
subdomains: ['a', 'b', 'c']),
]),
),
);
}
}

Related

how to make history with textfield in flutter?

class _SimpleDialogState extends State<SimpleDialog> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final TextEditingController _textEditingController = TextEditingController();
#override
void initState() {
super.initState();
baseurl = Prefs().geturlBase();
}
#override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Base URL'),
content: Form(
key: _formKey,
child: TextFormField(
keyboardType: TextInputType.multiline,
maxLines: null,
//controller: _textEditingController,
initialValue: baseurl,
onChanged: (val) {
setState(() {
baseurl = val;
print(baseurl);
});
},
decoration: InputDecoration(
hintText: "Please Enter Base Url",
border:
OutlineInputBorder(borderRadius: BorderRadius.circular(15)),
),
validator: (value) {
// return value!.isNotEmpty ? null : "Enter Base Url";
return Uri.parse(value.toString()).host == ''
? "Enter Base Url"
: null;
},
)),
actions: <Widget>[
Center(
child: InkWell(
onTap: () {
buildShowDialog(context);
if (_formKey.currentState!.validate()) {
baseurl = baseurl.trim();
checkBaseUrl(baseurl, context);
// Navigator.of(context).pop();
print('baseurl=====base------$baseurl');
}
},
child: Container(
width: 100,
height: 40,
padding: EdgeInsets.all(12.0),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(20.0),
),
child: Text(
"Connect",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white),
),
),
),
)
],
);
}
}
This is a dialog box where I can change my baseURL. Now, I need history when I touch textfield, history should appear and I can able to select the data from history to text field and also able to delete history, not all history particular data from that list. how can I able to achieve this kinda logic??.
An input_history_text_field widget is automatically saved and suggested as you type.

How to avoid overwriting a List Item when using the same name?

In my project the user can add and edit List Items. The Problem is, that if the user add a List item with an already existing List name, the old one gets overwritten, with the error 'Multiple widgets used the same GlobalKey'. How can I avoid that, so that the user can add multiple items with the same name?
import 'package:flutter/material.dart';
class PlanOverview extends StatefulWidget {
const PlanOverview({Key key}) : super(key: key);
#override
_PlanOverviewState createState() => _PlanOverviewState();
}
class _PlanOverviewState extends State<PlanOverview> {
List<String> plans = ['Plan A', 'Plan B'];
void addPlan(String newPlan) {
setState(() {
plans.add(newPlan);
});
Navigator.of(context).pop();
}
void newEntry() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: TextField(
onSubmitted: addPlan,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
icon: Icon(Icons.text_snippet_outlined),
labelText: 'Name des Plans'),
),
);
});
}
void edit(int i) => showDialog(
context: context,
builder: (context) {
final plan = plans[i];
return AlertDialog(
content: TextFormField(
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
icon: Icon(Icons.text_snippet_outlined)),
initialValue: plan,
onFieldSubmitted: (_) => Navigator.of(context).pop(),
onChanged: (name) => setState(
() {
plans[i] = name;
},
)));
});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Trainingspläne'),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.only(bottomLeft: Radius.circular(10.0), bottomRight: Radius.circular(10.0)),
),
actions: [
IconButton(
onPressed: newEntry,
icon: Icon(Icons.add),
),
],
),
body: ReorderableListView.builder(
itemCount: plans.length,
onReorder: (oldi, newi) => setState(() {
final i = newi > oldi ? newi - 1 : newi;
final plan = plans.removeAt(oldi);
plans.insert(i, plan);
}),
itemBuilder: (context, i) {
final plan = plans[i];
return ListTile(
tileColor: Color.fromARGB(255, 34, 34, 34),
key: ValueKey(plan),
contentPadding: EdgeInsets.symmetric(horizontal: 20, vertical: 5),
title: Text(plans[i]),
onTap: () {
Navigator.push<Widget>(
context,
MaterialPageRoute(
builder: (context) =>
ExerciseTable(key: GlobalKey(), title: plans[i])));
},
trailing: IconButton(
icon: Icon(Icons.edit),
onPressed: () {
edit(i);
}),
);
}),
);
}
}
When the user creates an element and adds it to the list, you can check the list for an element with the same name and if it exists, add its index to its name this way there cant be two elements with the same name.
You dont need to show the index part of the name to the user if you dont want to, its just for control purposes.
If you have a search bar where the user types the name of the element he wants to access you can use auto complete to show the elements tht contains what the user is typing.

Flutter Navigator - How to pass DocumentSnapshot<List> to Detail Page?

I'm searching for a solution to pass my snapshot via Navigator or others to my Detail Page.
class SoccerList extends StatelessWidget {
#override
Widget build(BuildContext context) {
final database = Provider.of<FirestoreDatabase>(context, listen: false);
return StreamBuilder<List<Soccer>>(
stream: database.soccerStream(),
builder: (_, snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
final soccer = snapshot.data;
if (soccer == null) {
return Scaffold(
body: Center(
child: Text('User list is empty',
style: Theme.of(context).textTheme.headline6),
),
);
}
return ListView.builder(
itemCount: soccer.length,
itemBuilder: (context, index) {
final item = soccer[index];
return Container(
margin: EdgeInsets.fromLTRB(15, 5, 15, 5),
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5), //color of shadow
spreadRadius: 5, //spread radius
blurRadius: 7, // blur radius
offset: Offset(0, 2), // changes position of shadow
//first paramerter of offset is left-right
//second parameter is top to down
),
//you can set more BoxShadow() here
],
),
child: ListTile(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailBetScreen(soccer: soccer)
//[index],
)
);
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
leading: IconButton(
iconSize: 24,
icon: new SvgPicture.asset('assets/ball/fussball7.svg'), onPressed: () { },
),
title: item.displayname != null? Text(item.displayname) : Text(item.sporttype),
subtitle: Text(item.sporttype),
),
);
},
);
}
The error message is:
Exception caught by widgets library:
type 'List' is not a subtype of type 'DocumentSnapshot'
The relevant error-causing widget was
MaterialApp
How do i pass this snapshot (soccer) to a Detail Page? Sure the snapshot contains a List....i need both. Thnaks in advance for any idea!
This is my Stream:
Stream<List<Soccer>> soccerStream() => _service.soccerStream<Soccer>(
path: FirestorePath.bets(),
builder: (data, documentId) => Soccer.fromMap(data, documentId),
);
And this is my Detail Screen:
class DetailBetScreen extends StatelessWidget {
final DocumentSnapshot soccerBet;
DetailBetScreen({Key key, #required this.soccerBet}) : super(key: key);
You can try this:
class DetailBetScreen extends StatelessWidget {
final dynamic soccerBet;
DetailBetScreen({Key key, #required this.soccerBet}) : super(key: key);

Dart Lists - I created a list of widgets and add a widget called 'StarterDayTile' which works fine, but can't then remove in the next if statement

I cannot remove the 'StarterDayTile' in the line that I say dayList.remove(StarterDayTile());
This is where I originally took the screenshot from:
Apparently I have to add lots more details because my post is mostely code and I don't know what to add so I am now just writing random stuff to pass the bot who is preventing me from posting I hope this works now.
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:moody/data_screen.dart';
import 'package:moody/starter_day_tile.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:page_transition/page_transition.dart';
import 'day_tile.dart';
class HomeScreen extends StatefulWidget {
final String displayDate;
final String displayEmoji;
final int displayHapp;
HomeScreen({this.displayHapp, this.displayDate, this.displayEmoji});
#override
_HomeScreenState createState() => _HomeScreenState();
}
List<Widget> dayList = [];
class _HomeScreenState extends State<HomeScreen> {
#override
void initState() {
super.initState();
if (widget.displayEmoji != null && widget.displayDate != null && widget.displayHapp != null){
print('2');
setState(() {
dayList.insert(0, DayTile(date: widget.displayDate, emoji: widget.displayEmoji, happ: widget.displayHapp));
});
}
if (dayList.length == 0){
dayList.add(StarterDayTile());
}
else if (dayList.length == 2){
dayList.remove(StarterDayTile());
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.indigoAccent,
onPressed: () {
FocusScope.of(context).requestFocus(FocusNode()); // Keyboard down
Navigator.pushReplacement(
context,
PageTransition(
type: PageTransitionType.rightToLeftWithFade,
child: DataScreen()));
},
child: Icon(Icons.message),
),
backgroundColor: Colors.white12,
appBar: PreferredSize(
preferredSize: Size.fromHeight(60),
child: Hero(
tag: 'hero1',
child: AppBar(
elevation: 15,
backgroundColor: Colors.indigoAccent,
automaticallyImplyLeading: false,
title: Center(
child: Text(
'Moody',
style: TextStyle(fontFamily: 'Baloo', fontSize: 35),
),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
bottom: Radius.circular(20),
),
),
leading: Padding(
child: IconButton(icon: Icon(Icons.menu), onPressed: () {}),
padding: EdgeInsets.only(right: 0, left: 10),
),
actions: <Widget>[
Padding(
padding: EdgeInsets.only(right: 10, left: 0),
child: IconButton(
icon: Icon(Icons.pie_chart),
onPressed: () {},
)),
],
),
),
),
body: ListView.builder(
reverse: false,
scrollDirection: Axis.vertical,
itemCount: dayList.length,
itemBuilder: (context, index) {
return dayList[index];
},
),
);
}
}
Try this; since it is the first object you want to remove
dayList.removeAt(0);
Solved it!!
I made a bool called startDayTileExists and made it a global variable and then when I added the StarterDayTile to the list I made it equal true and then I changed the dayList.remove() to a dayList.removeAt(1); but made an extra requirement in the if that startDayTileExists had to equal true then in the if I removed it and made startDayTileExists equal to false again.
Thanks for all your help!

How can i save my data in list that it can be used in entire lifecycle of application in flutter?

In my flutter application i am using mvp with clean architecture and my server return 5 items when it hit api, and when i scroll more it again hit api and get next 5 items. And i am saving these items in a list so that i can not call api again and again for already fetched items and this list was used in listview.builder. I had used bottom navigation bar and when i move from product items tab to any other tab and from there came to products items it again fetch products from api and thats not what i want. I want to show that list which was already fetched by that list in products list tab whenever i return back.
Video of my problem.
import 'dart:async';
import 'package:bakery_application/Bloc/TECartBloc.dart';
import 'package:bakery_application/Singleton/CartManager.dart';
import 'package:bakery_application/data/dataSource/product/remote/ProductRemoteDataSource.dart';
import 'package:bakery_application/data/model/responseDTO/ProductResponseDTO.dart';
import 'package:bakery_application/data/model/responseDTO/models/products.dart';
import 'package:bakery_application/data/model/responseDTO/models/productsList.dart';
import 'package:bakery_application/domain/repository/product/ProductRepo.dart';
import 'package:bakery_application/ui/productdetailscreeen/ProductDetailScreen.dart';
import 'package:bakery_application/ui/productscreen/IProductPresenter.dart';
import 'package:bakery_application/ui/productscreen/IProductView.dart';
import 'package:connectivity/connectivity.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:bakery_application/localmodels/ProductModel.dart';
import 'package:bakery_application/widgets/TEProductIncrementor.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
import 'package:provider/provider.dart';
import 'ProductPresenter.dart';
class ProductScreen extends StatefulWidget {
Key key;
List<Products> myList = new List<Products>();
int _pageNumber = 1;
ProductScreen({
this.key,
}) : super(key: key);
#override
_ProductScreenState createState() => _ProductScreenState();
}
class _ProductScreenState extends State<ProductScreen> implements IProductView {
_ProductScreenState() {
productPresenter = ProductPresenter(
this,
ProductRepo(
ProductRemoteDataSource(),
),
);
}
bool circularindicator = false;
Color circularColor;
double circularOpacity;
IProductPresenter productPresenter;
AsyncSnapshot snapshotList;
var _connectionStatus = 'Unknown';
Connectivity connectivity;
StreamSubscription<ConnectivityResult> subscription;
ScrollController _scrollController = ScrollController();
bool cupertinoProgress;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.orange,
automaticallyImplyLeading: false,
title: Text(
'Product',
style: TextStyle(color: Colors.white),
),
),
body:
StreamBuilder(
stream: productPresenter.getProducts,
builder: (context, AsyncSnapshot<ProductsList> snapshot) {
if (snapshot.hasData) {
return productListView(widget.myList);
} else if (snapshot.hasError) {
return Text(snapshot.error.toString());
}
return Center(
child: Container(
child: CircularProgressIndicator(),
),
);
},
),
);
}
Future<Null> refreshList() async {
await Future.delayed(Duration(seconds: 2));
setState(() {});
return null;
}
Widget productListView(List snapshot) {
return RefreshIndicator(
onRefresh: refreshList,
child:
ListView.builder(
key: widget.key,
controller: _scrollController,
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemBuilder: (BuildContext context, int index) {
if(index+1 == widget.myList.length) {
CupertinoActivityIndicator();
}
var plist = widget.myList[index];
return GestureDetector(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailScreen(
product: plist,
),
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: 120,
height: 130,
child: Image(
image: NetworkImage(plist.image),
),
),
Container(
child: Flexible(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
plist.name,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
Text(
plist.description,
softWrap: true,
textAlign: TextAlign.left,
),
SizedBox(
height: 7,
),
Row(
children: <Widget>[
Text(plist.price.toString(),
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
)),
Spacer(),
Text(plist.brand),
],
),
TEProductIncrementor(
product: plist,
),
//TODO reverse it alse
],
),
),
),
),
],
),
Row(
children: <Widget>[
Expanded(
child: Divider(
color: Colors.grey.shade300,
),
),
],
)
],
),
),
);
},
itemCount: widget.myList.length,
),
);
}
productlist(BuildContext context, int index
}
#override
hideProgress(ProductsList response) {
setState(() {
// Here you can write your code for open new view
cupertinoProgress=false;
});
for (var c in response.products) {
widget.myList.add(c);
}
}
#override
showError(String error) {
// TODO: implement showError
return null;
}
#override
showProgress() {
print('Successful');
setState(() {
cupertinoProgress=true;
});
}
#override
void initState() {
super.initState();
connectivity = new Connectivity();
print('Init state called');
print('Init state called');
print('Init state called');
subscription =
connectivity.onConnectivityChanged.listen((ConnectivityResult result) {
_connectionStatus = result.toString();
print(_connectionStatus);
if (result == ConnectivityResult.wifi ||
result == ConnectivityResult.mobile) {
widget.myList.isEmpty
? productPresenter.fetchProducts(widget._pageNumber.toString())
:
widget._pageNumber = widget._pageNumber + 1;
productPresenter.fetchProducts(widget._pageNumber.toString(),);
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
widget._pageNumber = widget._pageNumber + 1;
print(widget._pageNumber);
productPresenter.fetchProducts(widget._pageNumber.toString(),);
}
});
} else {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Center(
child: Container(
child: Icon(
Icons.add_alert,
color: Colors.orange,
size: 20,
),
),
),
content: Text('Check your internet'),
actions: <Widget>[
new FlatButton(
child: new Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
});
}
#override
void dispose() {
subscription.cancel();
super.dispose();
}
getMoreData() async {
}
}
The main problem you're facing is that each time the user scrolls of the tab you're in and returns to it, the app re-fetches the data again.
You can use IndexedStack to make the data only loads once, for that you can edit your code to be this way.
class BaseScreenState extends State<BaseScreen> {
List<Widget> _pages = [Page1(), Page2(), Page3()];
#override
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack(
index: currentIndex,
children: _pages,
),
);
}
}