add profile picture on on pressed flutter - flutter

i created a designed profile page for users i need a help to code a function to let the users select photo from their device when the click on my add button and i need to save that image data to my database
i just need to open up gallery and let the user select photo and it should save to my data base when she click on add button
this is the code of my profile page
class ProfileWidget extends StatefulWidget {
final GlobalKey<ScaffoldState> parentScaffoldKey;
ProfileWidget({Key key, this.parentScaffoldKey}) : super(key: key);
#override
_ProfileWidgetState createState() => _ProfileWidgetState();
}
class _ProfileWidgetState extends StateMVC<ProfileWidget> {
ProfileController _con;
_ProfileWidgetState() : super(ProfileController()) {
_con = controller;
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _con.scaffoldKey,
body: currentUser.value.apiToken == null
? PermissionDeniedWidget()
: SingleChildScrollView(
// padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 10),
child: Column(
children: <Widget>[
ProfileAvatarWidget(user: currentUser.value),
ListTile(
contentPadding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
leading: Icon(
Icons.shopping_basket,
color: Theme.of(context).hintColor,
),
title: Text(
S.of(context).recent_orders,
style: Theme.of(context).textTheme.headline4,
),
),
_con.recentOrders.isEmpty
? EmptyOrdersWidget()
: ListView.separated(
scrollDirection: Axis.vertical,
shrinkWrap: true,
primary: false,
itemCount: _con.recentOrders.length,
itemBuilder: (context, index) {
var _order = _con.recentOrders.elementAt(index);
return OrderItemWidget(expanded: index == 0 ? true : false, order: _order);
},
separatorBuilder: (context, index) {
return SizedBox(height: 20);
},
),
],
),
),
);
}
}
code of profile avatar widget
class ProfileAvatarWidget extends StatelessWidget {
final User user;
ProfileAvatarWidget({
Key key,
this.user,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(vertical: 30),
decoration: BoxDecoration(
color: Theme.of(context).accentColor,
borderRadius: BorderRadius.only(bottomLeft: Radius.circular(30), bottomRight: Radius.circular(30)),
),
child: Column(
children: <Widget>[
Container(
height: 160,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
SizedBox(
width: 50,
height: 50,
child: FlatButton(
padding: EdgeInsets.all(0),
onPressed: () {},
child: Icon(Icons.add, color: Theme.of(context).primaryColor),
color: Theme.of(context).accentColor,
shape: StadiumBorder(),
),
),
ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(300)),
child: CachedNetworkImage(
height: 135,
width: 135,
fit: BoxFit.cover,
imageUrl: user.image?.url,
placeholder: (context, url) => Image.asset(
'assets/img/loading.gif',
fit: BoxFit.cover,
height: 135,
width: 135,
),
errorWidget: (context, url, error) => Icon(Icons.error),
),
),
Users dart
import '../helpers/custom_trace.dart';
import '../models/media.dart';
enum UserState { available, away, busy }
class User {
String id;
String name;
String email;
String password;
String apiToken;
String deviceToken;
String phone;
String address;
String bio;
Media image;

Related

VideoPlayer working locally but is only playing audio in production

Im using the videoPlayer package and it has been working perfectly until i decided to change the format of the video to take height: MediaQuery.of(context).size.height and now it suddenly only plays the audio in production while working perfectly on my local device.
I have posten the full code below along with an image displaying what the error looks like enter image description here
class InspoDescription extends StatefulWidget {
String id;
String title;
String image;
String name;
String tag;
String description;
String video;
InspoDescription(
{required this.id,
required this.title,
required this.image,
required this.name,
required this.tag,
required this.description,
required this.video});
#override
State<InspoDescription> createState() => _InspoDescriptionState();
}
class _InspoDescriptionState extends State<InspoDescription> {
VideoPlayerController? controller;
#override
void initState() {
controller = VideoPlayerController.network(widget.video)
..addListener(() => setState(() {}))
..setLooping(true)
..initialize().then((value) => controller!.play());
super.initState();
}
#override
void dispose() {
controller!.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
),
body: SingleChildScrollView(
child: Column(
children: [
controller!.value.isBuffering
? SizedBox(
width: double.infinity,
height: MediaQuery.of(context).size.height,
child: const Center(
child: CircularProgressIndicator(),
),
)
: Positioned.fill(
child: GestureDetector(
onTap: () => controller!.value.isPlaying
? controller!.pause()
: controller!.play(),
child: SizedBox(
width: double.infinity,
height: MediaQuery.of(context).size.height,
child: Stack(
children: [
VideoPlayer(controller!),
controller!.value.isPlaying
? Container()
: const Align(
alignment: Alignment.center,
child: Icon(
Icons.play_arrow_rounded,
size: 100,
color: Color.fromRGBO(255, 255, 255, 0.6),
),
),
const Align(
alignment: Alignment.bottomCenter,
child: Icon(
Icons.arrow_drop_down_sharp,
size: 100,
color: Color.fromRGBO(255, 255, 255, 0.6),
),
)
],
),
),
),
),
ExploreHeadline(
name: widget.name,
tag: widget.tag,
title: widget.title,
description: widget.description,
),
StreamBuilder<InspoModel>(
stream: Inspo().getCurrentExplorePage(widget.id),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong ${snapshot.error}');
} else if (snapshot.hasData) {
final inspo = snapshot.data;
List<ProductModel> products = [];
inspo!.products.forEach(
(element) {
ProductModel product = ProductModel.fromJson(element);
products.add(product);
},
);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: GridView.builder(
itemCount: products.length,
shrinkWrap: true,
itemBuilder: (context, index) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Flexible(
child: GestureDetector(
onTap: () => Navigator.of(context).push(
CustomPageRoute(
child: ProductDescription(
sub_cat_id: products[index].id,
productId: products[index].id,
description: products[index]
.description,
details: products[index].details,
productImage: products[index].image,
productName: products[index].title,
productPrice: products[index].price,
cartQuantity:
products[index].cartQuantity,
categoryId:
products[index].category_id,
subTitle: products[index].subTitle,
inventory:
products[index].inventory))),
child: Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(16),
),
child: Stack(
children: [
Align(
alignment: Alignment.center,
child: CachedNetworkImage(
imageUrl: products[index].image,
),
),
],
),
),
),
),
Text(
products[index].title,
style: TextStyle(
color: Colors.grey[500],
fontWeight: FontWeight.w400),
),
Text(
products[index].subTitle,
),
Text(
'${products[index].price} kr',
)
],
),
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.75,
crossAxisSpacing: 20,
mainAxisSpacing: 20,
),
),
);
} else {
return const CircularProgressIndicator();
}
}),
],
),
),
);
}
}
Video on local device
Full page on local device

News pages doesn't show article or blogs after building apk

I'm creating a flutter project on which it consist of news feature sadly after building an apk and installing it to try in become an empty screen with grey shade, i also try to test it on my phone and this is what happen i dont know where the bugs came from.. please help me
here's the code
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'Article_View.dart';
import 'News_Categories.dart';
import 'helper/Data.dart';
import 'helper/News.dart';
import 'model/Article_Model.dart';
import 'model/CategoryModel.dart';
class NewsHomePage extends StatefulWidget {
#override
_NewsHomePageState createState() => _NewsHomePageState();
}
class _NewsHomePageState extends State<NewsHomePage> {
List<CategoryModel> categories = <CategoryModel>[];
List<ArticleModel> articles = <ArticleModel>[];
bool _loading = true;
//bannerads
late BannerAd _bannerads;
bool _isAdsLoaded = false ;
#override
void initState() {
// TODO: implement initState
super.initState();
categories = getCategories();
getNews();
_initBannerAds();
}
getNews() async {
News newsClass = News();
await newsClass.getNews();
articles = newsClass.news;
setState(() {
_loading = false;
});
}
_initBannerAds(){
_bannerads = BannerAd(
size: AdSize.banner,
// ignore: deprecated_member_use
adUnitId: "ca-app-pub-8634651641429291/4830511818",
listener: BannerAdListener(
onAdLoaded: (ad){
setState(() {
_isAdsLoaded =true;
});
},
onAdFailedToLoad: (ad,error){}
),
request: const AdRequest()
);
_bannerads.load();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.green,
elevation: 0.0,
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text('Stock '),
Text(
'News',
style: TextStyle(
color: Colors.black54,
),
),
],
),
centerTitle:true,
bottom: const PreferredSize(
preferredSize: Size.zero,
child: Text("Powered by news.org")),
),
body: _loading
? Container(
child: const Center(
child: CircularProgressIndicator(),
),
)
: SingleChildScrollView(
child: Container(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
///Categories
Container(
padding: const EdgeInsets.symmetric(horizontal: 22.0),
height: 90.0,
child: Expanded(
child: ListView.builder(
itemCount: categories.length,
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemBuilder: (context, index) {
return CategoryTile(
imageUrl: categories[index].imageAssetUrl,
categoryName: categories[index].categoryName,
);
}),
),
),
///Blogs
Container(
padding: const EdgeInsets.only(top: 16.0),
child: Expanded(
child: ListView.builder(
physics: const ClampingScrollPhysics(),
shrinkWrap: true,
itemCount: articles.length,
itemBuilder: (context, index) {
return BlogTile(
imageURL: articles[index].urlToImage,
title: articles[index].title,
desc: articles[index].description,
url: articles[index].url,
);
},
),
),
),
],
),
),
),
bottomNavigationBar: _isAdsLoaded?SizedBox(
height: _bannerads.size.height.toDouble(),
width: _bannerads.size.width.toDouble(),
child: AdWidget(ad: _bannerads),
)
:const SizedBox(),
);
}
}
class CategoryTile extends StatelessWidget {
final String imageUrl, categoryName;
const CategoryTile({required this.imageUrl, required this.categoryName});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CategoryNews(
category: categoryName.toLowerCase(),
),
),
);
},
child: Container(
margin: EdgeInsets.only(right: 10.0),
child: Stack(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(6),
child: imageUrl != null
? CachedNetworkImage(
imageUrl: imageUrl,
width: 120,
height: 60.0,
fit: BoxFit.cover,
)
: Image.network(
imageUrl,
width: 120.0,
height: 60.0,
fit: BoxFit.cover,
),
),
Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.black26,
borderRadius: BorderRadius.circular(6),
),
width: 120,
height: 60.0,
child: Text(
categoryName,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w500,
fontSize: 18.0,
),
),
),
],
),
),
);
}
}
class BlogTile extends StatelessWidget {
final String imageURL, title, desc, url;
BlogTile(
{required this.imageURL,
required this.title,
required this.desc,
required this.url});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ArticleView(
blogUrl: url,
)),
);
},
child: Container(
margin: const EdgeInsets.only(bottom: 16.0, left: 10.0, right: 10.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(6.0),
child: imageURL != null
? CachedNetworkImage(
imageUrl: imageURL,
)
: Image.network(imageURL),
),
const SizedBox(
height: 8.0,
),
Text(
title,
style: const TextStyle(
//color: Colors.black87,
fontSize: 17.0,
fontWeight: FontWeight.w500,
),
),
const SizedBox(
height: 8.0,
),
Text(
desc,
style: const TextStyle(
//color: Colors.black54,
),
),
],
),
),
);
}
}
and here's the screen shots of the app
[![debugging app][1]][1]
[![build app][2]][2]
[1]: https://i.stack.imgur.com/tvBsG.jpg
[2]: https://i.stack.imgur.com/wOuxS.jpg
Check if this line exists in android/app/src/main/AndroidManifest.xml file. If it doesn't add it right below the package name line. This will grant the app INTERNET permission so it can access it & display the data from the internet.
<uses-permission android:name="android.permission.INTERNET"/>
Flutter by default only adds the INTERNET permission in debug mode. When you build an APK in release mode, you have to explicitly add the permission by including the above line.
More info here.

Change Notifier Provider to add widget to Favourite Screen

I've made screen with details of movies and with favourite movies. Also I've got a list of movies. In Detail Screen, there is favourite icon. I want to make that when you tap on this Icon, I want to add this movie to Favourite Screen.
There is a list of movies.
class Movie {
String imgUrl;
String title;
String categories;
int year;
String country;
int length;
String description;
List<String> screenshots;
Movie({
required this.imgUrl,
required this.title,
required this.categories,
required this.year,
required this.country,
required this.length,
required this.description,
required this.screenshots,
});
}
final List<Movie> movies = [
Movie(
imgUrl:
'https://static.posters.cz/image/1300/plakaty/james-bond-no-time-to-die-profile-i114389.jpg',
title: 'No time to die',
categories: 'Adventure',
year: 2021,
country: 'USA/England',
length: 183,
description:
'James Bond has left active service. His peace is short-lived when Felix Leiter, an old friend from the CIA, turns up asking for help, leading Bond onto the trail of a mysterious villain armed with dangerous new technology.',
screenshots: [
'https://i.pinimg.com/originals/fd/5e/1d/fd5e1d8878c402aaba2fb6373e880b1f.webp',
'https://cdn.mos.cms.futurecdn.net/dNmCDjJT5G76aDKiYphTkF.jpg',
'https://i.imgur.com/Zm9X4lT.jpg',
'https://images.complex.com/complex/images/c_fill,f_auto,g_center,w_1200/fl_lossy,pg_1/knie3z7uwe3inyua5kft/no-time-to-die-04'
]),
]
There I've got Detail Screen.
class MovieScreen extends StatefulWidget {
final String photo, title, categories, country, description;
final int year, length;
final List<String> screenshots;
const MovieScreen(
{Key? key,
required this.photo,
required this.title,
required this.categories,
required this.year,
required this.country,
required this.description,
required this.length,
required this.screenshots})
: super(key: key);
#override
_MovieScreenState createState() => _MovieScreenState();
}
class _MovieScreenState extends State<MovieScreen> {
#override
Widget build(BuildContext context) {
final filmData = Provider.of<MovieProvider>(context);
final films = filmData.items;
return Scaffold(
backgroundColor: Colors.white,
body: ListView(
children: [
Stack(
children: [
Container(
transform: Matrix4.translationValues(0, -50, 0),
width: double.infinity,
child: Hero(
tag: widget.photo,
child: ClipShadowPath(
clipper: CircularClipper(),
shadow: Shadow(blurRadius: 20),
child: Image(
height: 400,
image: NetworkImage(widget.photo),
fit: BoxFit.cover,
),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
padding: EdgeInsets.only(left: 20),
onPressed: () => Navigator.pop(context),
icon: Icon(Icons.arrow_back),
iconSize: 40,
),
IconButton(
padding: EdgeInsets.only(right: 20),
onPressed: () {},
icon: Icon(Icons.favorite_outline),
iconSize: 30,
color: Colors.red,
),
],
),
],
),
],
),
);
}
}
There is Favourite Screen.
class MyList extends StatefulWidget {
#override
_MyListState createState() => _MyListState();
}
class _MyListState extends State<MyList> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Navbar1(),
Container(
width: MediaQuery.of(context).size.width - 60,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: ListView(
children: <Widget>[
SizedBox(
height: 50,
),
HeadMenuMylist(),
SizedBox(
height: 20,
),
GridView.count(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
mainAxisSpacing: 10,
crossAxisSpacing: 10,
crossAxisCount: 2,
childAspectRatio: 1 / 2,
children: [
Stack(
children: [
Positioned.fill(
child: Container(
height: 200,
foregroundDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.transparent, Colors.black],
),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(imgUrl
,
loadingBuilder: (BuildContext context,
Widget child,
ImageChunkEvent? loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: SizedBox(
height: 50,
width: 50,
child: CircularProgressIndicator(
strokeWidth: 4,
color: Colors.red,
),
),
);
},
fit: BoxFit.cover,
),
),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 15),
child: Align(
alignment: Alignment.bottomCenter,
child: Text(
'Peaky Blinders',
style: GoogleFonts.openSans(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.w700),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 10, right: 10),
child: Align(
alignment: Alignment.topRight,
child: GestureDetector(
onTap: () {},
child: Icon(
Icons.delete,
color: Colors.white,
),
)),
),
],
),
],
),
],
),
),
),
],
),
);
}
}
I tried with Change Notifier Provider but it doesn't work and I don't have clue why it didn't work. Is there something else I can use instead Change Notifier Provider?
Thanks for help.
if you want to save the favorite movie of a user permanently, then you have to save the JSON data in firestore database.
Create a function to store the favorite movie json data to firestore, i,e , store the json data to collection like;
saveFavrotiesMovies() async {
final User user = auth.currentUser;
final uid = user.uid;
try {
await FirebaseFirestore.instance
.collection('Favorite Movies')
.doc()
.collection(uid.toString())
.doc()
.set(
movies.toJson());
print('data adedd succesfullyyyyyy');
} catch (e, s) {
print("#DatabaseService Exception IN ADDNG FAVOTRITE DATA $e");
print(s);
}
}
This function store the favorite movie of a specific user in his/her collection
Retrive and the Favorite movie json data of a user from the Firestore database using a function in same manner as will do in storing the favorite data, and display the data in the Favorite Screen

Grivdview search not working properly flutter

I have a gridview,i have implemented search,search is working fine,but the viewing of search item is not shows properly,
Before search
This how my gridview show after searching a item
Code
SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200,
childAspectRatio: 6 / 5,
// crossAxisCount: 2,
crossAxisSpacing: 0,
mainAxisSpacing: 0),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
SubCategoryModel data = sub_category_model[index];
if (searchController.text.isEmpty) {
return GestureDetector(
child: Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
flex: 0,
child: Container(
width: 100,
height: 100.0,
child: ClipRRect(
borderRadius: BorderRadius.circular(10.0),
child: CachedNetworkImage(
fit: BoxFit.fill,
imageUrl: Urls.BASE_IMAGE_URL +
data.image.toString(),
placeholder: (context, url) => Center(
child: CircularProgressIndicator()),
errorWidget: (context, url, error) =>
Icon(Icons.error),
),
),
)),
Expanded(
flex: 0,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10, vertical: 10),
child: Text(
data.name,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 13),
),
),
)
],
),
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => OnlinecartSubitems(data.id.toString(),Category_Name),
),
);
},
);
} else if (data.name.contains(searchController.text) ||
data.name.toLowerCase().contains(searchController.text) ||
data.name.toUpperCase().contains(searchController.text)) {
return GestureDetector(
child: Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
flex: 0,
child: Container(
width: 100,
height: 100.0,
child: ClipRRect(
borderRadius: BorderRadius.circular(10.0),
child: CachedNetworkImage(
fit: BoxFit.fill,
imageUrl: Urls.BASE_IMAGE_URL +
data.image.toString(),
placeholder: (context, url) => Center(
child: CircularProgressIndicator()),
errorWidget: (context, url, error) =>
Icon(Icons.error),
),
),
)),
Expanded(
flex: 0,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10, vertical: 10),
child: Text(
data.name,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 13),
),
),
)
],
),
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => OnlinecartSubitems(data.id.toString(),Category_Name),
),
);
},
);
} else {
return Container();
}
},
childCount: sub_category_model.length,
),
)
Why not make a new list each time the search matches an item. Then, build a New GridView object based on the newly created list. Whenever your TextView is empty, you return the original list.
For Instance
//Create Search List
List<Object> searchList = [];
//Check if SearchTextView is empty or not with a ternary Operator
controller.text.isEmpty?
//Build your GridView based on the Original List
GridView.count(
...
itemCount: mainList.length,
...
) //Replace with you SliverGrid
//Build your GridView based on the Search List
: GridView.count(
...
itemCount: searchList.length
...
),//Replace with you SliverGrid
You can Replace my GridView with your SilverGrid widget.
The full Code (Spoiler alert: Very long):
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
MyHomePage({Key key, #required this.title}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
//Search TextField Controller
final _searchController = TextEditingController();
List<Fruit> mainList = [
Fruit(name: 'Apple', imageUrl: 'https://images.pexels.com/photos/102104/pexels-photo-102104.jpeg'),
Fruit(name: 'Banana', imageUrl: 'https://images.pexels.com/photos/5945848/pexels-photo-5945848.jpeg'),
Fruit(name: 'Pineapple', imageUrl: 'https://images.pexels.com/photos/1071878/pexels-photo-1071878.jpeg'),
Fruit(name: 'Mango', imageUrl: 'https://images.pexels.com/photos/918643/pexels-photo-918643.jpeg'),
];
List<Fruit> searchList = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
children: [
Container(
width: MediaQuery.of(context).size.width,
height: 60.0,
child: TextFormField(
controller: _searchController,
onChanged: (text){
final String queryString = _searchController.text;
setState((){
if(queryString.isNotEmpty){
for(final fruit in mainList){
if(fruit.name.contains(queryString)){
searchList.add(fruit);
} else{
searchList.remove(fruit);
}
}
}else{
searchList.clear();
}
});
}
),
),
Expanded(
child: _searchController.text.isEmpty
? GridView.count(
crossAxisCount: 2,
children: mainList.map((fruit)=> CardWidget(fruit: fruit)).toList(),
)
:GridView.count(
crossAxisCount: 2,
children: searchList.map((searchedFruit)=>CardWidget(fruit: searchedFruit)).toList()
),
),
],
),
);
}
}
Create a Class to hold Fruit
class Fruit{
final String imageUrl;
final String name;
Fruit({this.imageUrl, this.name});
}
Create widget to be built for each fruit object found in the mainList
//Card Widget
class CardWidget extends StatefulWidget{
final Fruit fruit;
CardWidget({this.fruit});
#override
_CardWidgetState createState()=> _CardWidgetState();
}
class _CardWidgetState extends State<CardWidget>{
#override
Widget build(BuildContext context){
return Container(
width: 100.0,
height: 140.0,
child: Column(
children:[
Image(image: NetworkImage(widget.fruit.imageUrl)),
SizedBox(height: 10.0),
Text(widget.fruit.name),
]
)
);
}
}
Try it and let see
I have fixed the issue with help of Benedict and Farhan Syah thanks for the idea and some codes
Initialize variables
//Search controller for textfield
TextEditingController searchController = TextEditingController();
//For show list data first
List<SubCategoryModel> sub_category_model = [];
//for searchresult list
List<SubCategoryModel> _searchResult = [];
View
_searchResult.length != 0 ||searchController.text.isNotEmpty?SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200,
childAspectRatio: 6 / 5,
// crossAxisCount: 2,
crossAxisSpacing: 0,
mainAxisSpacing: 0),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
SubCategoryModel data = _searchResult[index];
return GestureDetector(
child: Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
flex: 0,
child: Container(
width: 100,
height: 100.0,
child: ClipRRect(
borderRadius:
BorderRadius.circular(10.0),
child: CachedNetworkImage(
fit: BoxFit.fill,
imageUrl: Urls.BASE_IMAGE_URL +
data.image.toString(),
placeholder: (context, url) => Center(
child:
CircularProgressIndicator()),
errorWidget: (context, url, error) =>
Icon(Icons.error),
),
),
)),
Expanded(
flex: 0,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10, vertical: 10),
child: Text(
data.name,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 13),
),
),
)
],
),
),
onTap: () {
},
);
},
childCount: _searchResult.length,
),
):SliverGrid(//use same code above with **sub_category_model.length**)
Search widget
Widget _SearchText() {
return Container(
width: 360,
height: 65,
color: Colors.transparent,
child: new Padding(
padding: const EdgeInsets.only(top: 10, left: 10, right: 10),
child: new Card(
elevation: 8,
child: TextField(
decoration: new InputDecoration(
filled: true,
hintStyle: TextStyle(fontSize: 11.5),
hintText: 'Search by Name',
suffixIcon: GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
searchController.clear();
_searchResult.clear();
},
child: Icon(Icons.cancel_rounded,
color: Color.fromRGBO(34, 83, 148, 1))),
prefixIcon:
Icon(Icons.search, color: Color.fromRGBO(34, 83, 148, 1)),
border: InputBorder.none),
onChanged: onSearchTextChanged,
controller: searchController,
),
),
),
);
}
Onchanged function for searching through list
onSearchTextChanged(String text) async {
//clear search data before typing
_searchResult.clear();
if (text.isEmpty) {
setState(() {});
return;
}
//use searchcontroller text and loop through list of api data and add the result to _searchResult
sub_category_model.forEach((searchValue) {
if (searchValue.name.toLowerCase().contains(text))
_searchResult.add(searchValue);
});
setState(() {});
}
You are returning Container() when the search condition doesn't match. Container itself will take a place of a widget, hence, it will be an item of the grids.
To test this, you can try putting something inside the container, such as:
Container(
child: Text('This grid is not empty)
)
The problem with this, is if you have 12 items in the data, no matter your search result, it will still build 12 items (including the empty container)
To solve this, you need a better way to filter the data, such as using a list to filter, and then passing the list data to the grid builder.
The concept is like this:
Original list : 10 items
Newlist based on the search: 5 items
The grid builder will build the items based on the list provided.

How to update my ListView in Flutter and Solve problem with StateFull Widget?

My goal is to reach the updating of Listview. I have questions about my code. But I have to tell foreword about my problem. I used setState(), and I wasn't understanding, why this function didn't work and I realized that use Stateless widget.
I used this code
class _ListItem extends StatelessWidget {
_ListItem({this.bgName, this.name, this.detail});
// final int index;
final String bgName;
final String name;
final String detail;
#override
Widget build(BuildContext context) {
return Container(
height: 180.0,
margin: const EdgeInsets.symmetric(
vertical: 1.0,
),
child: new Stack(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(bgName),
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.45), BlendMode.darken),
fit: BoxFit.cover,
alignment: Alignment.center),
),
child: new SizedBox.expand(
child: Container(
alignment: Alignment.center,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text(
name,
style: new TextStyle(fontSize: 29.0, color: Colors.white),
),
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: new Text(
detail,
style:
new TextStyle(fontSize: 16.0, color: Colors.white),
),
)
],
),
),
),
),
],
),
);
}
}
Lately, I changed class _ListItem to Stateful Widget
I used this code
class ListItem extends StatefulWidget {
#override
_ListItem createState() => _ListItem();
}
class _ListItem extends State<ListItem> {
_ListItem({this.bgName, this.name, this.detail});
// final int index;
final String bgName;
final String name;
final String detail;
#override
Widget build(BuildContext context) {
return Container(
height: 180.0,
margin: const EdgeInsets.symmetric(
vertical: 1.0,
),
child: new Stack(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(bgName),
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.45), BlendMode.darken),
fit: BoxFit.cover,
alignment: Alignment.center),
),
child: new SizedBox.expand(
child: Container(
alignment: Alignment.center,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text(
name,
style: new TextStyle(fontSize: 29.0, color: Colors.white),
),
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: new Text(
detail,
style:
new TextStyle(fontSize: 16.0, color: Colors.white),
),
)
],
),
),
),
),
],
),
);
}
}
But in outside it gives empty listview.
At this moment I used this fragment of code.
body: ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: listItems.length,
itemBuilder: (BuildContext ctxt, int index){
return GestureDetector(
child: listItems[index].widget,
onTap: () {
//some code
}
);
},
)
All code
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'dart:ui';
import 'package:samuraigym/my_icons_icons.dart' as custicon;
import 'package:samuraigym/program_training_handler.dart';
class MeasurementsScreen extends StatefulWidget {
#override
_MeasurementsScreenState createState() => _MeasurementsScreenState();
}
class _MeasurementsScreenState extends State<MeasurementsScreen> {
List<_ListItem> listItems;
String lastSelectedValue;
var name = ["Рост", "Вес","Грудь","Плечи","Бицепс"];
var nameItem = ["Рост", "Вес","Грудь","Плечи","Бицепс"];
var indication = ["Введите ваш рост", "Введите ваш вес"];
var indicationItem = ["Введите ваш рост", "Введите ваш вес"];
TextEditingController customcintroller;
void navigationPageProgrammTrainingHandler() {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => ProgrammTrainingHandler()),
);
}
#override
void initState() {
super.initState();
initListItems();
}
Future<String> createAlertDialog(BuildContext context, int indexAl) async{
customcintroller = TextEditingController();
if(indexAl < 2){
String returnVal = await showDialog(context: context, builder: (context){
return AlertDialog(
title: Text(name[indexAl]),
content: TextField(
textDirection: TextDirection.ltr,
controller: customcintroller,
style: TextStyle(
color: Colors.lightGreen[400],
fontSize: 18.5),
decoration: InputDecoration(
contentPadding: EdgeInsets.only(bottom: 4.0),
labelText: indication[indexAl],
alignLabelWithHint: false,
),
keyboardType: TextInputType.phone,
textInputAction: TextInputAction.done,
),
actions: <Widget>[
FlatButton(
child: const Text('ОТМЕНА'),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: const Text('ОК'),
onPressed: () {
setState(() {
indicationItem[indexAl] = customcintroller.text.toString();
Navigator.of(context).pop();
});
},
),
],
);
});
} else if (indexAl > 1){
navigationPageProgrammTrainingHandler();
}
}
#override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Color(0xff2b2b2b),
appBar: AppBar(
title: Text(
'Замеры',
style: new TextStyle(
color: Colors.white,
),),
leading: IconButton(
icon:Icon(Icons.arrow_back),
color: Colors.white ,
onPressed:() => Navigator.of(context).pop(),
),
),
body: ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: listItems.length,
itemBuilder: (BuildContext ctxt, int index){
return GestureDetector(
child: listItems[index].widget,
onTap: () {
createAlertDialog(context, index).then((onValue){
indicationItem[index] = onValue.toString();
});
}
);
},
),
);
}
void initListItems() {
listItems = [
new _ListItem(
bgName: 'assets/images/soso_growth.jpg',
name: nameItem[0],
detail: "Нажми, чтобы добавить свой рост"),
new _ListItem(
bgName: 'assets/images/soso_weight.jpg',
name: nameItem[1],
detail: "Нажми, чтобы добавить свой вес"),
new _ListItem(
bgName: 'assets/images/soso_chest.jpg',
name: nameItem[2],
detail: "PRO-версия"),
new _ListItem(
bgName: 'assets/images/soso_shoulder.jpg',
name: nameItem[3],
detail: "PRO-версия"),
new _ListItem(
bgName: 'assets/images/soso_biceps.jpg',
name: nameItem[4],
detail: "PRO-версия")
];
}
}
class ListItem extends StatefulWidget {
#override
_ListItem createState() => _ListItem();
}
class _ListItem extends State<ListItem> {
_ListItem({this.bgName, this.name, this.detail});
// final int index;
final String bgName;
final String name;
final String detail;
#override
Widget build(BuildContext context) {
return Container(
height: 180.0,
margin: const EdgeInsets.symmetric(
vertical: 1.0,
),
child: new Stack(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(bgName),
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.45), BlendMode.darken),
fit: BoxFit.cover,
alignment: Alignment.center),
),
child: new SizedBox.expand(
child: Container(
alignment: Alignment.center,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text(
name,
style: new TextStyle(fontSize: 29.0, color: Colors.white),
),
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: new Text(
detail,
style:
new TextStyle(fontSize: 16.0, color: Colors.white),
),
)
],
),
),
),
),
],
),
);
}
}
Help me, please. I can't solve the problem some days))
If you want to send data in the stateful widget you have to do this in the stateful class itself, not in the state
class ListItem extends StatefulWidget {
String bgName;
String name;
String detail;
ListItem({Key key, this.bgName, this.name, this.detail}) : super(key: key);
#override
_ListItem createState() => _ListItem();
}
to access it in the state class do it like this :
//somecode
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(widget.bgName),
//some code
to change the state in the stateful widget call the setState method when you tap on the widget for example , add gesture detector or InkWell to add on tap functionality
and call set state in it.
make a List of ListItem to use it in list view builder ,
List<ListItem> items = [ ListItem(bgName: ' the bgName' ,name :'the
name',detail:'details'),
//add another Items here
];
ListView.builder(
itemCount:items.length,
itemBuilder: (context,index)=>items[index];
);
Complete Example
class ListItem extends StatefulWidget {
String bgName;
String name;
String detail;
ListItem({Key key, this.bgName, this.name, this.detail}) : super(key: key);
#override
_ListItem createState() => _ListItem();
}
class _ListItem extends State<ListItem> {
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
print(widget.bgName);
//call setState here;
setState(() {
widget.bgName = 'this item is tapped';
});
},
child: Container(
height: 180.0,
margin: const EdgeInsets.symmetric(
vertical: 1.0,
),
child: new Stack(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(widget.bgName),
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.45), BlendMode.darken),
fit: BoxFit.cover,
alignment: Alignment.center),
),
child: new SizedBox.expand(
child: Container(
alignment: Alignment.center,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text(
widget.name,
style:
new TextStyle(fontSize: 29.0, color: Colors.white),
),
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: new Text(
widget.detail,
style: new TextStyle(
fontSize: 16.0, color: Colors.white),
),
)
],
),
),
),
),
],
),
),
);
}
}
List<ListItem> items = [ ListItem(bgName: ' the bgName' ,name :'the
name',detail:'details'),
//add another Items here
];
body: ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: listItems.length,
itemBuilder: (BuildContext ctxt, int index){
return
listItems[index]
;
},
)
I hope that can help.
what solved the problem for me is to wrap your widget (the one that your builder return) in a container with a unique key .
In my case i was returning a stateless widget in the builder so here is the code that worked for me.
this is the return statement from my listView Builer
return new Container(child: CouponWidget(coupons[position],true),
key:UniqueKey()
);