Key in listView is causing rebuild in Flutter - flutter

class SupportScreen extends StatefulWidget {
const SupportScreen({Key? key}) : super(key: key);
#override
State<SupportScreen> createState() => _SupportScreenState();
}
class _SupportScreenState extends State<SupportScreen> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
final ScrollController _scrollController = ScrollController();
int? selected;
int page = 1;
#override
void initState() {
super.initState();
updateState();
}
updateState() {
_scrollController.addListener(() {
if (_scrollController.position.pixels >=
_scrollController.position.maxScrollExtent) {
setState(() {
page = page + 1;
});
BlocProvider.of<SupportBloc>(_scaffoldKey.currentState!.context)
.add(SupportGetFaqsWithPagination(page));
}
});
}
#override
void dispose() {
super.dispose();
_scrollController.dispose();
}
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => SupportBloc(
SupportService(),
)..add(
SupportGetFaqsWithPagination(1),
),
child: Scaffold(
key: _scaffoldKey,
body: SafeArea(
child: Padding(
padding: const EdgeInsets.only(
top: 16, bottom: 0, left: 16, right: 16),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
title(),
const SizedBox(height: 20),
BlocConsumer<SupportBloc, SupportState>(
listener: (context, state) {
if (state is SupportError) {
if (state.message.toString() == "401") {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(Constants
.sessionExpiredPleaseLoginAgain)));
Navigator.pushReplacementNamed(
context, AppRouter.loginPath);
}
}
},
builder: (context, state) {
return BlocBuilder<SupportBloc, SupportState>(
builder: (context, state) {
if (state is SupportLoaded) {
return cardView(state.faqs);
} else if (state is SupportLoading) {
return const Expanded(
child: Center(
child: CircularProgressIndicator(),
),
);
} else if (state is SupportInitial) {
return const SizedBox.shrink();
} else {
return Container();
}
});
},
),
],
),
),
)),
);
}
Widget cardView(results) {
return Expanded(
child: Container(
margin: const EdgeInsets.only(bottom: 20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: CommonFunctions.getThemeColor(context,
lightColor: ColorCode.colorWhite,
darkColor: ColorCode.textFieldDark)),
child: cardContainer(results),
),
);
}
Widget cardContainer(results) {
return ListView.builder(
controller: _scrollController,
key: Key('${selected.toString()}'),//here becuase of key it is causing rebuild
itemCount: results.length,
itemBuilder: (context, i) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
lists(i, results),
if (i != results.length - 1)
Padding(
padding: EdgeInsets.symmetric(horizontal: 15.0),
child: Divider(
color: CommonFunctions.getThemeColor(context,
lightColor: Color.fromRGBO(0, 0, 0, 0.4),
darkColor: Color.fromRGBO(229, 229, 229, 0.4))),
),
],
);
},
);
}
Text title() {
return const Text(
Constants.support,
style: TextStyle(
fontFamily: 'PublicSans-Medium',
fontWeight: FontWeight.w700,
fontSize: 20),
);
}
Theme lists(int i, results) {
return Theme(
data: ThemeData().copyWith(
dividerColor: Colors.transparent,
cardColor: Colors.white,
shadowColor: Colors.transparent,
primaryColor: ColorCode.secondaryColor),
child: ExpansionTile(
iconColor: ColorCode.secondaryColor,
collapsedIconColor: ColorCode.secondaryColor,
key: Key(i.toString()),
initiallyExpanded: i == selected,
title: Text(
results[i].question as String,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
fontFamily: 'PublicSans-Light',
color: CommonFunctions.getThemeColor(context,
lightColor: ColorCode.black,
darkColor: ColorCode.colorWhite)),
),
children: [
Padding(
padding: const EdgeInsets.only(left: 15.0, bottom: 15, right: 15),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
results[i].answer as String,
style: const TextStyle(
color: ColorCode.grey_600,
fontSize: 14,
fontFamily: 'PublicSans-Thin',
height: 1.5),
textAlign: TextAlign.start,
),
),
),
],
tilePadding: const EdgeInsets.symmetric(vertical: 5, horizontal: 15),
onExpansionChanged: ((newState) {
if (newState) {
setState(() {
selected = i;
});
} else {
setState(() {
selected = -1;
});
}
})),
);
}
}
As soon I expand the Expansion tile the other expansion tile should collapse. It is happening because of the key given to ListView.builder. But as soon as selected value changes it rebuilds the page and the ListView jumps to top as soon as I expand the tiles in the bottom . I want only one Expansion tile to be open at a time and the listView should not jump to top. Here as I scroll I'm fetching the data from server and adding it end of the list. If I remove 'key' in ListView.builder i can open any number of expansion tiles but that is not the desirable output..How to solve this ?

Related

Infinite Scrolling in GridView.builder

I am Building a flutter e-commerce application. And in the Categories section. There are so much data so I want to implement pagination through infinite scrolling.
This is what I am trying to do, CatHome object is the category either men or women etc.
the code is resulting in pagination, but everytime it is building another page, not infinite scroll. so i cannot access previosly loaded data
class CategoryDetail extends StatefulWidget {
CatHome catHome;
CategoryDetail(this.catHome);
#override
_CategoryDetailstate createState() => _CategoryDetailstate(catHome);
}
class _CategoryDetailstate extends State<CategoryDetail> {
List<FutureOr> _items = [];
CatHome catHome;
_CategoryDetailstate(this.catHome);
var _currentPage = 1;
ScrollController scroll = ScrollController();
var _hasMore = true;
#override
void initState() {
super.initState();
scroll.addListener(() {
if (scroll.position.pixels == scroll.position.maxScrollExtent) {
_fetchMore();
}
});
}
#override
void dispose() {
scroll.dispose();
super.dispose();
}
void _fetchMore() async {
if (_hasMore) {
setState(() {
_currentPage++;
});
var newItems =
await new catitems_api().fetchdeails(catHome, _currentPage);
if (newItems.isEmpty) {
setState(() {
_hasMore = false;
});
} else {
setState(() {
this._items.addAll(newItems);
});
}
}
}
/// Component widget in flashSale layout
Widget build(BuildContext context) {
var data = EasyLocalizationProvider.of(context).data;
return EasyLocalizationProvider(
data: data,
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
title: Text(
AppLocalizations.of(context).tr('Category'),
style: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 17.0,
color: Colors.black54,
fontFamily: "Gotik"),
),
centerTitle: true,
iconTheme: IconThemeData(color: Color(0xFF6991C7)),
elevation: 0.0,
),
body: SingleChildScrollView(
child: Container(
child: Column(
children: <Widget>[
Container(
key: Key(UniqueKey().toString()),
height: MediaQuery.of(context).size.height * 0.8,
child: FutureBuilder<List<dynamic>>(
future: catitems_api().fetchdeails(catHome, _currentPage),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
return GridView.builder(
controller: scroll,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.7,
mainAxisSpacing: 8.0,
crossAxisSpacing: 8.0,
),
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
CategoryItems items = snapshot.data[index];
return InkWell(
onTap: () {
new productDet_api()
.fetchdeails(items.id)
.then((itemList) {
Navigator.of(context).push(PageRouteBuilder(
pageBuilder: (_, __, ___) =>
new detailProduk(itemList.first),
transitionDuration:
Duration(milliseconds: 950),
transitionsBuilder: (_flashSaleState,
Animation<double> animation,
__,
Widget child) {
return Opacity(
opacity: animation.value,
child: child,
);
}));
});
},
child: Container(
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black12.withOpacity(0.1),
spreadRadius: 0.2,
blurRadius: 5.0,
offset: Offset(0.0, 2.0))
]),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.network(
items.image,
width: 150.0,
height: 150.0,
fit: BoxFit.cover,
),
SizedBox(
height: 10.0,
),
Text(
items.name,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 14.0,
color: Colors.black),
),
SizedBox(
height: 5.0,
),
Text(
"\$" + items.price.toString(),
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 14.0,
color: Colors.black),
),
],
),
),
);
},
);
},
),
),
],
),
),
),
),
);
}
}

Flutter how to get list of selected FilterChips

i have created a Widget which displays chips to select your interests. The data is loaded from firestore. Now i want to check which ones are selected after i clicked the button. The problem is that i'm really new and i have no idea how to do this. Here is the code of my chip widget:
class _filterChipWidgetState extends State<filterChipWidget> {
var _isSelected = false;
#override
Widget build(BuildContext context) {
return FilterChip(
label: Text(widget.chipName),
labelStyle: TextStyle(color: Color.fromRGBO(254, 60, 110, 1),
fontSize: 16.0, fontWeight: FontWeight.bold),
selected: _isSelected,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
30.0),),
backgroundColor: Color(0xffededed),
checkmarkColor:Color.fromRGBO(254, 60, 110, 1),
onSelected: (isSelected) {
setState(() {
_isSelected = isSelected;
});
},
selectedColor: const Color.fromRGBO(255, 109, 147, 0.23137254901960785));
}
}
And here is how i implement it in my page:
class _SelectInterestState extends State<SelectInterest> {
#override
Widget build(BuildContext context) {
// TODO: implement build
CollectionReference interest =
FirebaseFirestore.instance.collection('interests');
return FutureBuilder<DocumentSnapshot>(
future: interest.doc('interests').get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return Text("Something went wrong");
}
if (snapshot.hasData && !snapshot.data!.exists) {
return Text("Document does not exist");
}
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data =
snapshot.data!.data() as Map<String, dynamic>;
return Column(
children: [
generateChipList(data),
Padding(
padding: const EdgeInsets.all(30.0),
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
gradient: const LinearGradient(colors: [
Color.fromRGBO(254, 60, 110, 1),
Color.fromRGBO(226, 132, 78, 1.0),
]),
),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0, primary: Colors.transparent),
onPressed: () {
// HERE I WANT TO SEE THE SELECTED CHIPS Array
},
child: SizedBox(
width: double.infinity,
child: Center(
child: Text("NEXT"),
)))),
)
],
);
return Text("${data.values} ");
}
return const Text("loading");
},
);
}
Widget generateChipList(Map<String, dynamic> data) {
return Padding(
padding: const EdgeInsets.only(top: 30.0),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Wähle deine Interessen",
style: TextStyle(color: Colors.black87, fontSize: 30)),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
child: Wrap(
spacing: 5.0,
runSpacing: 5.0,
children: List.generate(data['values'].length, (index) {
return filterChipWidget(
chipName: data['values'][index]['label'],
);
})),
),
)
],
),
);
}
}
Dominik Hartl try to edit filterChipWidget class:
Add new function
class filterChipWidget extends StatefulWidget {
filterChipWidget ({Key? key, required this.onSelected}) : super(key: key);
// Other declarations
// ....................
// End
Function(bool, String) onSelected;
#override
State<filterChipWidget> createState() => _filterChipWidgetState();
}
Update _filterChipWidgetState class
class _filterChipWidgetState extends State<filterChipWidget> {
var _isSelected = false;
#override
Widget build(BuildContext context) {
return FilterChip(
label: Text(widget.chipName),
labelStyle: TextStyle(color: Color.fromRGBO(254, 60, 110, 1),
fontSize: 16.0, fontWeight: FontWeight.bold),
selected: _isSelected,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
30.0),),
backgroundColor: Color(0xffededed),
checkmarkColor:Color.fromRGBO(254, 60, 110, 1),
onSelected: (isSelected) {
setState(() {
_isSelected = isSelected;
widget.onSelected(isChecked, widget.chipName);
});
},
selectedColor: const Color.fromRGBO(255, 109, 147, 0.23137254901960785));
}
}
Add new variable LIST, for selected values
class _SelectInterestState extends State<SelectInterest> {
late List<String> selectedItems = [];
#override
Widget build(BuildContext context) {
// TODO: implement build
CollectionReference interest =
FirebaseFirestore.instance.collection('interests');
return FutureBuilder<DocumentSnapshot>(
future: interest.doc('interests').get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return Text("Something went wrong");
}
if (snapshot.hasData && !snapshot.data!.exists) {
return Text("Document does not exist");
}
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data =
snapshot.data!.data() as Map<String, dynamic>;
return Column(
children: [
generateChipList(data),
Padding(
padding: const EdgeInsets.all(30.0),
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
gradient: const LinearGradient(colors: [
Color.fromRGBO(254, 60, 110, 1),
Color.fromRGBO(226, 132, 78, 1.0),
]),
),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0, primary: Colors.transparent),
onPressed: () {
// HERE I WANT TO SEE THE SELECTED CHIPS Array
// Now you can get selected values
print(selectedItems);
},
child: SizedBox(
width: double.infinity,
child: Center(
child: Text("NEXT"),
)))),
)
],
);
return Text("${data.values} ");
}
return const Text("loading");
},
);
Finally add or remove values to/from the selectedItems LIST
Widget generateChipList(Map<String, dynamic> data) {
return Padding(
padding: const EdgeInsets.only(top: 30.0),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Wähle deine Interessen",
style: TextStyle(color: Colors.black87, fontSize: 30)),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
child: Wrap(
spacing: 5.0,
runSpacing: 5.0,
children: List.generate(data['values'].length, (index) {
return filterChipWidget(
chipName: data['values'][index]['label'],
onSelected: (isChecked, item) {
if (isChecked) {
// Check the value exists in the list: add if NOT EXISTS
if (!selectedItems.contains(item)) {
selectedItems.add(item);
}
} else {
// Check the value exists in the list: remove if EXISTS
if (selectedItems.contains(item)) {
selectedItems.remove(item);
}
}
Not that generateChipList is _SelectInterestState class member.

how to store the name of the container in an array

hi i am new to flutter can anyone tell me how to save the preferences in an array
what are the methods used in storing the value
class PrefPage extends StatefulWidget {
#override
_PrefPageState createState() => _PrefPageState();
}
class _PrefPageState extends State<PrefPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: Container(
color: Theme.of(context).backgroundColor,
padding: EdgeInsets.fromLTRB(10, 10, 30, 10),
height: 80,
child: Spring.bubbleButton(
onTap: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => Home()));
},
child: Text(
"👉",
style: TextStyle(fontSize: 30),
textAlign: TextAlign.end,
),
),
),
backgroundColor: Theme.of(context).backgroundColor,
appBar: AppBar(
centerTitle: false,
leadingWidth: 0,
elevation: 0,
backgroundColor: Theme.of(context).backgroundColor,
title: Text(
"Swoken",
style: GoogleFonts.niconne(
textStyle: TextStyle(
fontSize: 30,
color: Theme.of(context).primaryColor,
),
),
),
),
body: SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
" What are your",
style: TextStyle(fontSize: 40, fontWeight: FontWeight.w100),
),
Text(
" Interests ?",
style: TextStyle(fontSize: 40, fontWeight: FontWeight.bold),
),
SizedBox(
height: 20,
),
GridView.count(
scrollDirection: Axis.vertical,
physics: ScrollPhysics(),
childAspectRatio: 2.3,
crossAxisCount: 2,
padding: EdgeInsets.all(5),
shrinkWrap: true,
children: List.generate(
intr.length,
(index) {
return PrefCont(
child: AutoSizeText(
intr[index]["icon"] + " " + intr[index]["title"],
minFontSize: 16,
maxLines: 1,
style: TextStyle(fontSize: 40),
),
);
},
),
),
],
),
),
),
);
}
}
class PrefCont extends StatefulWidget {
PrefCont({this.child});
final child;
#override
_PrefContState createState() => _PrefContState();
}
class _PrefContState extends State<PrefCont> {
List<String> sel = [];
bool isSelected = false;
#override
Widget build(BuildContext context) {
var themeId = DynamicTheme.of(context)!.themeId;
var kContColor = Color(0Xfff6f6f6);
themeId == 0
? kContColor = Color(0Xfff6f6f6)
: kContColor = Color(0xff272727);
return InkWell(
onTap: () {
setState(() {
isSelected = !isSelected;
});
},
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: isSelected ? kContInactColor : kContColor,
borderRadius: BorderRadius.circular(10),
),
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(10),
child: widget.child,
),
);
}
}
...........................................................................................................................................................................................................................................................................
First you need to modelize your elements as objects then, you need to create a data set containing all of your tiles:
class PreferencesData {
final String name;
final String assetName;
PreferencesData({required this.name, required this.assetName});
}
list _dataSet = [
PreferencesData(name: "Football", assetName: "/assets/icons/football.png"),
PreferencesData(name: "Food", assetName: "/assets/icons/food.png"),
...
];
Now that you have all your objects in a dataset you can use it in your grid to display them correctly:
children: [for (PreferencesData pref in _dataSet)
PrefCont(...) // access your data with pref.name
]

How can I display items in the list based on the category?

I am trying to display the items in my list based on the categories that I have. I am fetching them from the Cloud Firestore and divid them based on categories, but I do not know how to display the items on the screen based on the categories that I am selecting. So, I was wondering if someone can help.
Please find my code below:
import 'package:flutter/material.dart';
import 'package:uploadvideo/addNewVideo.dart';
import 'package:uploadvideo/info.dart';
class MyHomePage extends StatefulWidget {
MyHomePage({
Key key,
this.title,
}) : super(key: key);
final String title;
List<String> items = [
"All",
"Research",
"Technology",
"Math and Science",
"Design"
];
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String category = "";
String selectedValue = "All";
List list = [];
final firestoreInstance = FirebaseFirestore.instance;
void _onPressed() {
setState(
() {
FirebaseFirestore.instance.collection('Record').get().then(
(QuerySnapshot querySnapshot) {
querySnapshot.docs.forEach(
(doc) {
if (selectedValue == "All") {
list.add(doc["category"]);
print(list);
} else if (selectedValue == "Research") {
if (doc["category"] == "Research") {
list.add(doc["category"]);
print(list);
}
} else if (selectedValue == "Technology") {
if (doc["category"] == "Technology") {
list.add(doc["category"]);
print(list);
}
} else if (selectedValue == "Math and Science") {
if (doc["category"] == "Math and Science") {
list.add(doc["category"]);
print(list);
}
} else if (selectedValue == "Design") {
if (doc["category"] == "Design") {
list.add(doc["category"]);
print(list);
}
}
},
);
},
);
},
);
}
_downloadImage(context) {
return StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection('Record').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return LinearProgressIndicator();
return snapshot.data.docs.isEmpty == false
? _buildList(context, snapshot.data.docs)
: Center(
child: Text(
"No tutorials record",
style: TextStyle(
fontSize: 30,
color: Color(0xFF002545),
),
),
);
},
);
}
Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot) {
return ListView(
padding: const EdgeInsets.only(top: 15.0),
children:
snapshot.map((data) => _buildListItem(context, data)).toList());
}
Widget _buildListItem(BuildContext context, DocumentSnapshot data) {
final record = Record.fromSnapshot(data);
return Padding(
key: ValueKey(record.category),
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: Card(
child: Column(
children: [
// Image.network(record.url),
Padding(
padding:
const EdgeInsets.only(left: 8.0, right: 8, top: 8, bottom: 3),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
record.title,
style: TextStyle(
color: Colors.orange,
fontSize: 14,
fontWeight: FontWeight.bold),
),
),
),
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8, bottom: 8),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
record.category,
style: TextStyle(
color: Color(0xFF002545),
fontWeight: FontWeight.bold,
fontSize: 18),
),
),
),
],
),
),
);
}
#override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
return Scaffold(
appBar: AppBar(
backgroundColor: Color(0xFF1A5993),
title: Text(widget.title),
actions: [
DropdownButton(
value: selectedValue,
items: widget.items.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(
value,
style: TextStyle(color: Colors.black),
),
);
}).toList(),
icon: Icon(
Icons.arrow_downward,
color: Colors.white,
),
elevation: 16,
style: TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.white,
),
onChanged: (String value) {
setState(
() {
selectedValue = value;
_onPressed();
},
);
},
)
],
),
body: Container(
width: size.width,
height: size.height,
child: _downloadImage(context),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.amber,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddNewVideo(),
),
);
},
child: Icon(Icons.add),
),
);
}
}
You can add a flag on your list items saying if item is or not a category, then with a ListView.builder you can return different widgets for each kind of item:
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
var item = items[index];
if(item.isCat){
return CatWidget();
}else{
return ItemWidget();
}
},
);

Getting error while searching documents from cloud firestore

I have stored all articles in cloud firestore and now im searching a article from cloud firestore.
Search is working fine but when i tap on a article to go on detail screen to read more. i m getting this error : type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'DocumentSnapshot'
this is my search screen :
class SearchService {
searchByName(String searchField) {
return FirebaseFirestore.instance
.collection('articles')
.where('searchKey',
isEqualTo: searchField.substring(0, 1).toUpperCase())
.get();
}
}
class SearchScreen extends StatefulWidget {
#override
_SearchScreenState createState() => new _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
var queryResultSet = [];
var tempSearchStore = [];
initiateSearch(value) {
if (value.length == 0) {
setState(() {
queryResultSet = [];
tempSearchStore = [];
});
}
if (queryResultSet.length == 0 && value.length == 1) {
SearchService().searchByName(value).then((QuerySnapshot docs) {
for (int i = 0; i < docs.docs.length; ++i) {
queryResultSet.add(docs.docs[i].data());
setState(() {
tempSearchStore.add(queryResultSet[i]);
});
}
});
} else {
queryResultSet.forEach((element) {
if (element['title'].toLowerCase().contains(value.toLowerCase()) ==
true) {
if (element['title'].toLowerCase().atIndex(value.toLowerCase()) ==
0) {
setState(() {
tempSearchStore.add(element);
});
}
}
});
}
if (tempSearchStore.length == 0 && value.length > 1) {
setState(() {});
}
}
#override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.white,
appBar: new AppBar(
iconTheme: IconThemeData(color: CustomColors.blackColor),
title: TextField(
onChanged: (val) {
initiateSearch(val);
},
decoration: InputDecoration(
hintText: 'Search here',
hintStyle: TextStyle(
color: CustomColors.greyColor,
fontWeight: FontWeight.bold,
),
border: InputBorder.none,
),
),
),
body: ListView(
padding: EdgeInsets.only(left: 10.0, right: 10.0),
shrinkWrap: true,
children: tempSearchStore.map((element) {
return SearchResults(
data: element,
);
}).toList(),
),
);
}
}
this my search item:
class SearchResults extends StatelessWidget {
final data;
const SearchResults({this.data});
#override
Widget build(BuildContext context) {
var readTime = readingTime(data['desc']);
return InkWell(
onTap: () {
Get.to(
DetailScreen(
articles: data,
),
);
},
child: Container(
height: Get.mediaQuery.size.height * 0.24,
width: Get.mediaQuery.size.width * 0.8,
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 20),
decoration: BoxDecoration(
color: Colors.grey.withOpacity(0.1),
borderRadius: BorderRadius.circular(20),
),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
constraints: BoxConstraints(
maxWidth: Get.mediaQuery.size.width * 0.65,
),
child: Text(
data['title'],
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 22,
color: CustomColors.blackColor,
fontWeight: FontWeight.w600,
),
),
),
Image.network(
data['imageUrl'],
height: 100,
width: 100,
fit: BoxFit.cover,
),
],
),
],
),
),
);
}
}
this is my detail screen to view full article:
class DetailScreen extends StatelessWidget {
final DocumentSnapshot articles;
final ArticlesController articlesController = Get.find<ArticlesController>();
DetailScreen({#required this.articles});
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.white,
elevation: 0,
iconTheme: IconThemeData(color: CustomColors.blackColor),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(top: 40),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
toBeginningOfSentenceCase(
articles.data()['title'],
),
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: CustomColors.blackColor,
),
),
SizedBox(
height: 10,
),
Padding(
padding: const EdgeInsets.only(
top: 15, right: 30, left: 30, bottom: 15),
child: SelectableText(
articles.data()['desc'],
toolbarOptions: ToolbarOptions(copy: true, selectAll: true),
style: TextStyle(
fontSize: 20,
letterSpacing: 1,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
),
],
),
),
),
);
}
}
docs.docs[i] is a DocumentSnapshot
But docs.docs[i].data() is a Map<String, dynamic>
You have add lists (queryResultList and other) as Map but detailscreen field is DocumentSnapshot.