Error: type 'String' is not a subtype of type 'int' of 'index' - flutter

(Edit: I have 3 files
main , trending and text. Let me show them.) I am showing you 2 of them here - where the mainly important portions are.
I think the problem is within 'trending' page where trending[index] is not accepting as String. The api is from tmdb which is a list of maps and has 'poster path'. Donot know what the problem is.
Main =>
class _HomeState extends State<Home> {
#override
void initState() {
loadmovies();
super.initState();
}
List trendingmovies = [];
List topratedmovieslist = [];
List tvlist = [];
final String apikey = '974ecf335095695927b80cb92fbe6200';
final readaccesstoken = 'eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI5NzRlY2YzMzUwOTU2OTU5MjdiODBjYjkyZmJlNjIwMCIsInN1YiI6IjYzMzAwZmJkYWJkYWZjMDA3Y2Q5OWRkZCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.LZkUXKdyN5YCWJcfV6wYLVejGvYp22BzAQowBUWe5Ys';
loadmovies() async{
final tmdb = TMDB(
ApiKeys(apikey, readaccesstoken),
logConfig: const ConfigLogger(
showLogs: true,//must be true than only all other logs will be shown
showErrorLogs: true,
),);
Map result = await tmdb.v3.trending.getTrending();
Map topratedmovies = await tmdb.v3.movies.getTopRated();
Map tv = await tmdb.v3.tv.getTopRated();
setState(() {
trendingmovies = result['results'];
topratedmovieslist = topratedmovies['results'];
tvlist = tv['results'];
});
print(trendingmovies);
print(topratedmovieslist);
print(tvlist);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const modified_text(text:'Film Library', color: Colors.white70, size: 20,
),
backgroundColor: Colors.transparent,
),
body: ListView(
children: [
TrendingMovies(trending: [trendingmovies],)
],
),
);
}
}
Edit: This is the trending file. I have noted that initialized list doesn't contain poster_path like with tmdb but the main file has extracted it to a list.
Trending ->
import 'package:film_library/utils/text.dart';
import 'package:flutter/material.dart';
class TrendingMovies extends StatelessWidget {
const TrendingMovies({Key? key, required this.trending}) : super(key: key);
final List trending;
#override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const modified_text (text:'Trending Movies', size: 30, color: Colors.white,),
SizedBox(height: 300,
child: ListView.builder(itemCount: trending.length,
scrollDirection: Axis.horizontal,
itemBuilder: (context,index){
return InkWell(
onTap: (){
},
child: SizedBox(
width: 140,
child: Column(
children: [
Container(
height: 200,
decoration: BoxDecoration(
image: DecorationImage(image: NetworkImage(
'http://image.tmdb.org/t/p/w500' + trending[index] ['poster_path']))
)
),
modified_text(text: trending[index]['title'], color: Colors.brown, size: 20,)
],
),
),
);
}),
)
],
),
);
}
}
Edit: There is text file as well but it is nothing but just used as some Font class. I have created model class like - List trending but it too says that - Error: A value of type 'List' can't be assigned to a variable of type 'Trending Movies', and shows error on same poster_path. Maybe the syntax is wrong with calling it as #jacksparrow, did while it doesnt show the error here with [index] ['poster_path'] but that one of the title.

I would suggest that please create model class from json response of your Trending movies API and then create list of trending movies using that model like as below :
List<TrendingMovies> trending ;

It is better to fetch data from API by making model class and fromJson method of that particular json response. It makes more easier to understand use data in it.
import 'package:film_library/utils/text.dart';
import 'package:flutter/material.dart';
class TrendingMovies extends StatelessWidget {
const TrendingMovies({Key? key, required this.trending}) : super(key: key);
List<TrendingMovies> trendingMoviesList ;
#override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const modified_text (text:'Trending Movies', size: 30, color: Colors.white,),
SizedBox(
height: 300,
child: ListView.builder(
itemCount: trending.length,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
final trendingMovie= trendingMoviesList[index];
return InkWell(
onTap: () {},
child: SizedBox(
width: 140,
child: Column(
children: [
Container(
height: 200,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
"http://image.tmdb.org/t/p/w500${trendingMovie.poster_path}"),
),
),
),
modified_text(text: trendingMovie.title, color: Colors.brown, size: 20,)
],
),
),
);
}),
)
],
),
);
}
}

Related

How to do I add new column after endling of loop inside Gridview?

I want to add a new column after the end of the loop inside Gridview.
Right now in my code I add the append functionality in floatingActionButton but I want to add this append functionality in the column after every end of the column loop.
Like this:- need to add a new column after end of loop
Please see this image for a better understanding.
I hope you understand what I want to say.
Right now my output is like this:- see there is floatingActionButton where i add append functionality to add a new column
Here is my code:-
import 'package:flutter/material.dart';
import 'package:mindmatch/utils/widget_functions.dart';
import 'package:mindmatch/custom/BorderIcon.dart';
import 'package:mindmatch/screens/Relation.dart';
import 'package:flutter_svg/flutter_svg.dart';
void main() {
runApp(new MaterialApp(
home: new Photos(),
));
}
class Photos extends StatefulWidget {
var usrid;
Photos({Key? key, #required this.usrid}) : super(key: key);
#override
_Photos createState() => _Photos();
}
class _Photos extends State<Photos>{
int counter = 0;
//List<Widget> _list = List<Widget>();
List<Widget> _list = <Widget> [];
#override
void initState() {
for (int i = 0; i < 2; i++) {
Widget child = _newItem(i);
_list.add(child);
};
}
void on_Clicked() {
Widget child = _newItem(counter);
setState(
() => _list.add(child),
);
}
Widget _newItem(int i) {
Key key = new Key('item_${i}');
Column child = Column(
key: key,
children: [
Stack(
children: [
Card(
elevation: 0,
shape: RoundedRectangleBorder(
side: BorderSide(
color: Color(0xffa1a1a1),
),
borderRadius: BorderRadius.all(Radius.circular(12)),
),
child: SizedBox(
//width: 300,
height: 100,
child: Center(child:
Icon(
Icons.image,
color: Color(0xffcccccc),
size: 60,
),
),
),
),
Positioned(
top: 9,
right: 9,
child: InkWell(
onTap: () => _removeItem(i),
child: SvgPicture.asset(
width: 20,
'assets/images/close.svg',
height: 20,
),
),
)
]
),
]
);
counter++;
return child;
}
void _removeItem(int i) {
print("====remove $i");
print('===Removing $i');
setState(() => _list.removeAt(i));
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Photo'),
backgroundColor: Colors.deepPurpleAccent,
),
floatingActionButton: new FloatingActionButton(onPressed: on_Clicked, child: new
Icon(Icons.add),),
body: new Container(
padding: new EdgeInsets.all(32.0),
child: Column(
children: [
Expanded(
child: GridView(
//padding: const EdgeInsets.all(8.0),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 10.0,
mainAxisSpacing: 15,
//childAspectRatio: 2/1,
),
children: [
itemBuilder: List.generate(_list.length, (index) {
//generating tiles with people from list
return _newItem(index);
},
]
return Column(
)
),
)
)
],
),
),
);
}
}
Please help how I add a new Column after the end of the loop on that column i add onTap property where i add append functionality to add new column when click.
Here is the code of the new column with add icon
InkWell(
onTap: (){},
child: Column(
children: [
Stack(
children: const [
Card(
elevation: 0,
color: Color(0xff8f9df2),
shape: RoundedRectangleBorder(
side: BorderSide(
color: Color(0xff8f9df2),
),
borderRadius: BorderRadius.all(Radius.circular(12)),
),
child: SizedBox(
//width: 300,
height: 100,
child: Center(child:
Icon(
Icons.add,
color: Colors.white,
size: 80.0,
),
),
),
)
]
),
]
),
)
You can extend item-count (item Length) by one and use last index to show add widget.
children: List.generate(itemLength + 1,
(index) => index == itemLength ? Text("new Item") : _newItem(index)),
I have created sample demo. you can foloow this. Hope this you want this same.
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class CustomObject{
String name;
bool isDummy;
CustomObject(this.name , this.isDummy);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyClass(),
),
),
);
}
}
class MyClass extends StatefulWidget {
#override
State<MyClass> createState() => _MyClassState();
}
class _MyClassState extends State<MyClass> {
List<CustomObject> _list =[];
#override
void initState() {
_list =[
CustomObject('test',false),
CustomObject('test 2',false),
CustomObject('',true), ///this is extra item to achieve
];
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body : Padding(
padding: const EdgeInsets.all(8.00),
child : GridView.builder(
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200,
childAspectRatio: 3 / 2,
crossAxisSpacing: 20,
mainAxisSpacing: 20),
itemCount: _list.length,
itemBuilder: (BuildContext ctx, index) {
return Container(
alignment: Alignment.center,
child: (!_list[index].isDummy) ? Text(_list[index].name) :
Icon(Icons.add,size: 40.00,),
decoration: BoxDecoration(
color: Colors.amber,
borderRadius: BorderRadius.circular(15)),
);
}),
),
);
}
}
Output :
Let me know if any query or anything.

Not getting values when querying list in search bar implementation Flutter

I need some help when implementing the search bar funcionality in Flutter.
I am implementing flappy_search_bar: https://pub.dev/packages/flappy_search_bar
However, it does return any value when I try to search something.
Is there anything I am missing? Seems trivial this kind of implementations, just query some list and include the results in other list but I cannot figure out the way to do it.
class MainPage extends StatefulWidget {
const MainPage({Key? key}) : super(key: key);
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
TextEditingController textController = TextEditingController();
Future<List<dynamic>> search(String search) async {
await Future.delayed(Duration(seconds: 2));
List<dynamic> dogs = BreedList.where((dog) => dog['breed'].contains(search)).toList();
return dogs;
// return List(search.length, (int index) {
// return DogClass(breed: "$search $index");
// });
}
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Column(children: [
Container(
margin: const EdgeInsets.only(top: 60, bottom: 15),
padding: const EdgeInsets.only(left: 20, right: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Center(
child: Container(
width: MediaQuery.of(context).size.width -
(MediaQuery.of(context).size.width / 3.5),
height: 80,
child: SearchBar<dynamic>(
searchBarStyle: SearchBarStyle(borderRadius: BorderRadius.circular(20)),
onSearch: search,
cancellationWidget: Text('Cancel'),
emptyWidget: SizedBox.shrink(),
shrinkWrap:true,
onItemFound: (dynamic dogs, int index) {
return Container(
child: ListTile(
title: Text(dogs.breed.toString())
),
);
}),
//child: const Icon(Icons.search, color: Colors.white),
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(Dimensions.radius20),
color: Colors.white),
),
)
],
),
),
//wrapping with this widgets the scroll problem is solved in list
const Expanded(
child: SingleChildScrollView(
child: BookPageBody(),
)),
]));
}
}

How can I send data from bottom sheet to parent widget?

I have list of products in bottom sheet, when I choose any product I want to parent's widget to add it, unfortunately my product adds only after hot reload, or when I create a new route from bottom sheet to parent's widget, how can I solve this problem, any ideas? Here is the part of the bottom sheet code
class IceBottomSheet extends StatefulWidget {
const IceBottomSheet({Key? key}) : super(key: key);
#override
_IceBottomSheetState createState() => _IceBottomSheetState();
}
class _IceBottomSheetState extends State<IceBottomSheet> {
final _model = ProductWidgetsModel();
#override
Widget build(BuildContext context) {
List<Widget> productWidgetList = [];
products.forEach((product) =>
productWidgetList.add(SingleProductWidget(product: product)));
return Provider(
model: _model,
child: Expanded(
child: GridView.count(
crossAxisSpacing: 10,
mainAxisSpacing: 16,
shrinkWrap: true,
crossAxisCount: 2, children: productWidgetList),
),
);
}
}
class SingleProductWidget extends StatefulWidget {
final Product product;
const SingleProductWidget({Key? key, required this.product})
: super(key: key);
#override
State<SingleProductWidget> createState() => _SingleProductWidgetState();
}
class _SingleProductWidgetState extends State<SingleProductWidget> {
#override
Widget build(BuildContext context) {
final model = Provider.of(context)?.model;
return Padding(
padding: const EdgeInsets.all(5.0),
child:
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(
width: double.infinity,
height: 100,
child: DecoratedBox(
decoration: BoxDecoration(
image: DecorationImage(
image: widget.product.image,
),
shape: BoxShape.circle,
border: Border.all(
color: model?.idSelected == widget.product.id
? Colors.yellow
: Colors.grey,
width: 5.0,
style: BorderStyle.solid,
),
),
child: GestureDetector(
onTap: () {
model?.idSelected = widget.product.id;
// Route route =
// MaterialPageRoute(builder: (context) => BerryPage(context,));
// Navigator.push(context, route);
if(model?.idSelected == 1){
menuRow.removeAt(2);
Navigator.pop(context);
choice.insert(2, Adds(id: 102, name: 'Холодок', img: 'https://autogear.ru/misc/i/gallery/73434/2759438.jpg'));
}
}),
),
),
And here is the part of parent's widget code, it is inside GestureDetector
else if (index == 2){
setState(() {
});
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (BuildContext builder) {
return Container(
height: 250,
child: Column(
children: [
SizedBox(
height: 10,
),Row(
children: [
Padding(
padding: EdgeInsets.only(left: MediaQuery.of(context).size.width*0.25 + MediaQuery.of(context).size.width *0.12),
child: Text(
'Холодок',
style: TextStyle(
fontFamily: 'Newfont',
fontSize: 22,
),
),
),
SizedBox(width: MediaQuery.of(context).size.width*0.25,),
IconButton(icon: Icon(Icons.close),onPressed: (){Navigator.pop(context);},)
],
),
Divider(),
IceBottomSheet(),
],
));
},
);
So when you open the BottomSheet you have to add await before it, so when you call Navigator.pop(context, data_you_want_to_pass_to_parent) it will wait for some data to be returned.
final data = await openBottomSheet();
inside the bottomSheet when you want to close, just pass the the desired data as so
Navigator.pop(context, data_you_want_to_pass_to_parent);

Flutter List View Builder Using API

I am able to fetch data from API and I can show it in the List View, but i want to show the first card as the latest updated data.
I tried to use the Reverse property of List View Builder, it some how solve my problem but gave rise to another problem. Now i need to scroll upward in order to see latest updated data.
Help me through it
I just want to show the latest updated data at the top and then scroll down to see another data.
Please Help Me.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class PromotersDetails extends StatefulWidget {
final String url,title;
PromotersDetails({Key key, #required this.url, #required this.title}) : super(key: key);
#override
_PromotersDetailsState createState() => _PromotersDetailsState(url,title);
}
class _PromotersDetailsState extends State<PromotersDetails> {
fetchSelfies() async {
var url1;
url1 = await http.get(Uri.parse(
url));
var res = json.decode(url1.body);
print(res);
return json.decode(url1.body)['selfies'];
}
String url,title;
_PromotersDetailsState(this.url, this.title);
#override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width * 0.6;
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
centerTitle: false,
title: Text(
title,
style: TextStyle(fontSize: 25.0, color: Colors.white),
),
elevation: 0.0,
backgroundColor: Colors.green,
),
body: FutureBuilder(
future: fetchSelfies(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(snapshot.error.toString()),
);
}
if (snapshot.hasData) {
return ListView.builder( **// List View Builder**
reverse: false,
cacheExtent: 10000.00,
itemCount: snapshot.data.length,
padding: EdgeInsets.all(8),
itemBuilder: (BuildContext context, int index) {
return Row(
children: [
Container(
height: 120,
alignment: Alignment.center,
child: Container(
height: 120,
width: 120,
child: Card(
child: Image.network(snapshot.data[index]['image']),
),
),
),
Expanded(
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 10,
),
Row(
children: [
Text(
"Time: ",
style: TextStyle(color: Colors.black),
),
Text(
snapshot.data[index]['time'],
style: TextStyle(color: Color(0xff868597)),
),
],
),
Container(
height: 50,
child: Text(
snapshot.data[index]['location'],
style: TextStyle(color: Color(0xff868597)),
),
),
],
),
),
),
],
);
},
);
}
return Center(
child: CircularProgressIndicator(),
);
})
);
}
}
If you just need to sort the API response backwards, you can use the reverse property of ListView.
ListView.builder(
reverse: true,
...
),
If the way you're populating the ListView is by appending new data, then it's better to store the data on a List then do sort/reversed. Though the sorting should be best done at the backend instead of passing the burden to the client app.

Why works Only one time?

I've implemented this simple listview to show a button-bar:
class _ProductInfoState extends State<ProductInfo> {
final Map<String, dynamic> product;
_ProductInfoState(this.product);
#override
Widget build(BuildContext context) {
List<ButtonBar> bdata = new List<ButtonBar>();
final Color kcolor2d = Color(int.parse(product['color']['second']));
final Color kcolor1t = Color(int.parse(product['color']['first']));
final Map<String, dynamic> types = product['types'];
types.forEach((k, v) {
bdata.add(new ButtonBar(false, v['title'], kcolor1t, kcolor2d));
});
bdata[0].isSelected = true;
return Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBar(
backgroundColor: kcolor2d,
title: Text(tr(product['name'])),
),
body: Stack(
children: [
SizedBox.expand(
child: Container(
color: kcolor2d,
)),
Padding(
padding: EdgeInsets.only(
left: 20,
top: 10,
bottom: 10,
),
child: SizedBox(
height: 35,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular((5.0)),
color: kcolor1t,
),
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: bdata.length,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () {
setState(() {
for (var i = 0; i < bdata.length; i++) {
bdata[i].isSelected = false;
}
bdata[index].isSelected = true;
print("Clicked " + bdata[index].buttonText);
});
},
child: ButtonBarItem(bdata[index]));
},
),
),
),
),
],
),
);
}
}
ButtonBarItem is implemented like:
final ButtonBar _item;
ButtonBarItem(this._item);
#override
_ButtonBarItem createState() => _ButtonBarItem(_item);
}
class _ButtonBarItem extends State<ButtonBarItem> {
final ButtonBar _item;
_ButtonBarItem(this._item);
#override
Widget build(BuildContext context) {
return SizedBox(
height: 30,
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: _item.isSelected ? Colors.white70 : _item.kcolor1t,
borderRadius: BorderRadius.all(Radius.circular(5))),
child: Text(_item.buttonText,
style: TextStyle(
color: _item.isSelected ? _item.kcolor2d : Colors.white,
))),
),
);
}
}
class ButtonBar {
bool isSelected;
final String buttonText;
final Color kcolor2d;
final Color kcolor1t;
ButtonBar(this.isSelected, this.buttonText, this.kcolor1t, this.kcolor2d);
}
and showes like that:
ButtonBar
At first click it works properly and changes the background color, but if I click again not working though the variable isSelected is correctly updated.
What's wrong with this code?
Please follow these steps to fix the problem:
You are initiating the array inside the build, move the code before the return to initState
Use for lop instead of forEach : This is because element is considered as local variable, updating element will not update the real item in the list,After the loop, element just get garbage collected. and the list will be the same before the forEach, but using for loop, you will access and change directly the real element not just a copy