Passing down data between widgets - flutter

I have a parent widget _CalendarPageState and two child widgets nameColumnContainer2 and nameColumn2. I have a data under int listLoc = list.indexOf(time); inside nameColumnContainer2 that I want to pass down to nameColumn2
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'update_green_page.dart';
import '../data/repository_service_addcash.dart';
import '../models/addcash.dart';
import 'widget_ui/choice_chip.dart';
class CalendarPage extends StatefulWidget {
#override
_CalendarPageState createState() => _CalendarPageState();
}
class _CalendarPageState extends State<CalendarPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
child: Row(
children: nameColumnContainer2(),
),
),
],
),
),
);
}
List<Widget> nameColumnContainer2() {
var list = <DateTime>[];
DateTime start = DateTime(2019, 12, 01);
final end = DateTime(2021, 12, 31);
while (start.isBefore(end)) {
list.add(start);
start = start.add(const Duration(days: 1));
}
var listDates = list.map((DateTime time) {
return DateFormat("MM-dd-yyyy").format(time);
}).toList();
return list.map((DateTime time) {
int listLoc = list.indexOf(time); //NEED TO PASS THIS DOWN TO nameColumn2
return Container(
decoration: BoxDecoration(border: Border.all(color: Colors.blue)),
width: 120,
child: ListView(
shrinkWrap: true,
children: <Widget>[
FutureBuilder<List<AddCash>>(
future: future,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
children:
snapshot.data.map((todo) => nameColumn2(todo)).toList(),
);
} else {
return SizedBox();
}
},
),
],
),
);
}).toList();
}
Widget nameColumn2(AddCash addCash) {
return Container(
alignment: Alignment.center,
width: 120.0,
height: 60.0,
color: Colors.green,
margin: EdgeInsets.all(4.0),
child: Row(
children: <Widget>[
Text('${addCash.amount}'),
listLoc % 6 == 0
? Text('${addCash.amount}')
: listLoc % 2 == 0 ? Text('no') : Text('d')
],
),
);
}
}
How can I pass the data up to the parent widget so it's available in both widgets?

You should use the BlocProvider widget in your parent widget or directly in your main.dart.
Here is an exemple:
First declare your BlocProvider
final MainBloc mainBloc = MainBloc();
return BlocProvider(
bloc: mainBloc,
child: MaterialApp(
initialRoute: '/CalendarPage',
onGenerateRoute: router.generator,
),
);
BlocProvider content
class BlocProvider extends InheritedWidget {
final MainBloc bloc;
final Widget child;
BlocProvider({Key key, #required this.child, #required this.bloc}) : super(key: key);
static BlocProvider of(BuildContext context) {
return context.inheritFromWidgetOfExactType(BlocProvider);
}
#override
bool updateShouldNotify(InheritedWidget oldWidget) {
return null;
}
}
Create a bloc (so you can separate your logic from your ui) and fill in the data you need
class MainBloc {
//Declare the data you need in your tree
}
And finally to recover your data in your parent/children
your_data = BlocProvider.of(context).bloc.your_data;

I just had to pass listLoc down to nameColumn2

Related

Variable value (indicator) referenced among different widgets

I have a call that call this carousel and based on the widget clicked, it shows different content (through the contentUrls argument). The content shows up fine but I tried including the DotsIndicator widget and the position (activePage) variable is not updating. It takes its value from the ref. For instance, if on a widget I moved to image 5, when I go to a different carousel, it starts on image 5 rather than on image 0. I am not understanding how the activePage variable works through the setState.
import 'package:activo/widgets/video_player.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:dots_indicator/dots_indicator.dart';
class Carousel extends StatefulWidget {
const Carousel({super.key, required this.contentUrls});
final String contentUrls;
#override
State<Carousel> createState() => _CarouselState();
}
class _CarouselState extends State<Carousel> {
double activePage = 0.0;
final GlobalKey _key = GlobalKey();
#override
Widget build(BuildContext context) {
List<String> contentUrls = widget.contentUrls.split(' , ');
return Column(
children: [
CarouselSlider(
key: _key,
options: CarouselOptions(
height: 300.0,
onPageChanged: (val, _) {
setState(() {
activePage = val * 1.0;
});
},
),
items: contentUrls.map(
(currentContent) {
return Builder(
builder: (BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: Colors.white,
),
),
width: MediaQuery.of(context).size.width,
margin: const EdgeInsets.symmetric(horizontal: 5.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(15),
child: currentContent.contains('mp4')
? VideoPlayerWidget(
videoUrl: currentContent,
)
: Image.network(
currentContent,
// will need to change it based on pictures for events
fit: BoxFit.fill,
),
),
);
},
);
},
).toList(),
),
Text('$activePage'),
DotsIndicator(
dotsCount: contentUrls.length,
position: activePage,
),
],
);
}
}
Thanks!
I am expecting that when I load this widget, the activePage's value is 0 or at least the last value for that specific carousel (as I have multiple) rather than the last values from some other widget.
Here is your basic code adjusted to work with an index using setState((){}).
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
class Carousel extends StatefulWidget {
const Carousel({super.key, required this.contentUrls});
final List<String> contentUrls;
#override
State<Carousel> createState() => _CarouselState();
}
class _CarouselState extends State<Carousel> {
int activePage = 1;
final GlobalKey _key = GlobalKey();
_onPageChanged(int index) {
activePage = index;
setState(() {});
}
#override
Widget build(BuildContext context) {
return Column(
children: [
CarouselSlider(
key: _key,
options: CarouselOptions(
height: 300.0,
onPageChanged: (index, _) {
_onPageChanged(index);
},
),
items: widget.contentUrls
.map((e) => Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
color: Colors.blue,
child: Center(child: Text(e)),
),
))
.toList()),
],
);
}
}
Also, as you mentioned at the end, you may want the last carousel card to show up when you load the page again. For that you can save the page index using a package to manage the app state like Provider.
Here is the example using Provider (also with GIF images fetched from online).
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => CarouselNotifier()),
],
child: const MaterialApp(
home:
Material(child: Carousel(contentUrls: ['https://media.giphy.com/media/wW95fEq09hOI8/giphy.gif',
'https://media.giphy.com/media/SggILpMXO7Xt6/giphy.gif','https://media.giphy.com/media/KHJw9NRFDMom487qyo/giphy.gif'
])),
),
),
);
}
class Carousel extends StatelessWidget {
const Carousel({super.key, required this.contentUrls});
final List<String> contentUrls;
#override
Widget build(BuildContext context) {
return Consumer(
builder: (_, notifier, __) =>
CarouselSlider(
key: key,
options: CarouselOptions(
height: 300.0,
onPageChanged: (index, _) {
Provider.of<CarouselNotifier>(context, listen: false)
.setIndex(index);
},
),
items: contentUrls
.map((e) =>
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
color: Colors.blue,
// display images from urls etc
child: Column(
children: [
Expanded(
flex: 3,
child: Center(child: Image.network(e))),
Expanded(child: Text('Page index ${contentUrls.indexOf(e)}'))
],
),
),
))
.toList()),
);
}
}
class CarouselNotifier extends ChangeNotifier {
int activePage = 0;
setIndex(int index) {
activePage = index;
notifyListeners();
}
}

How to find out where the click was in a dynamic list?

I have a list and I need to set the container's background when clicking on it. However, what I have now does not work. When clicked, the color of the entire list changes, not the selected one. It seems to me that I need to add an index somewhere. I can't put it in a separate widget, because I'm attached to the list. Tell me how to do it?
setState -
Color? _textColor;
Color? _bgColor;
void initState() {
_bgColor = configColors.orange;
_textColor = Colors.white;
super.initState();
}
List
ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: HomeStore.storage.length,
itemBuilder: (BuildContext ctx, index) {
return Row (
// mainAxisAlignment: MainAxisAlignment.start,
children: <Widget> [
InkWell(
onTap: () {
setState(() {
if (_bgColor ==
configColors
.orange) {
_bgColor =
Colors.white;
_textColor =
configColors
.textStorage;
} else {
_bgColor =
configColors.orange;
_textColor =
Colors.white;
}
}
);
},
child: Container(
width: 71.4,
height: 30.3,
decoration: BoxDecoration(
color: _bgColor,
borderRadius: BorderRadius.circular(10)
),
child: Align(
alignment: Alignment.center,
child: Text(HomeStore.storage[index], style: TextStyle(color: _textColor,),),
)
),
),
SizedBox(
width: 18,
),
],
);
}),
For single item selection, you can use a int variable, this snippet will help you to understand the concept.
int? selectedIndex;
onTap: () {
setState(() {
selectedIndex = index;
});
},
And to select color
color:selectedIndex == index ? Colors.red : Colors.blue
Test snippet
class Sg extends StatefulWidget {
Sg({Key? key}) : super(key: key);
#override
State<Sg> createState() => _SgState();
}
class _SgState extends State<Sg> {
int? selectedIndex;
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: 4,
itemBuilder: (BuildContext ctx, index) {
return Row(
// mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
InkWell(
onTap: () {
setState(() {
selectedIndex = index;
});
},
child: Container(
width: 71.4,
height: 30.3,
decoration: BoxDecoration(
color:
selectedIndex == index ? Colors.red : Colors.blue,
borderRadius: BorderRadius.circular(10)),
child: Align(
alignment: Alignment.center,
child: Text(
"HomeStore.storage[index]",
),
)),
),
],
);
}),
);
}
}
sharing one of my code demo
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: MyWidget(),
);
}
}
class MyWidget extends StatefulWidget {
#override
MyWidgetState createState() => MyWidgetState();
}
class MyWidgetState extends State<MyWidget> {
late int tappedIndex;
#override
void initState() {
super.initState();
tappedIndex = 0;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ListView.builder(
shrinkWrap: true,
itemCount: 4,
itemBuilder: (context, index) {
return Container(
color: tappedIndex == index ? Colors.blue : Colors.grey,
child: ListTile(
title: Center(
child: Text('${index + 1}'),
),onTap:(){
setState((){
tappedIndex=index;
});
}));
})
]));
}
}
taped index will solve problem

How to create load more listview in flutter

I want to create load more scrollview in listview. My app flow is storing youtube link in csv file and fetch this link from my app and display in my listview. But the problem is I don't want to wait too much load time when app is open.If I have a lot of youtube link in my csv.I will take a lot of time.So,for example I want to display only 5 video in initial state and when load more, display more 5 video in my list view.How can I do that.My code is below.
import 'package:flutter/material.dart';
import 'package:youtube_player_flutter/youtube_player_flutter.dart';
import 'videolist.dart';
import './models/models.dart';
import 'package:csv/csv.dart' as csv;
import 'package:http/http.dart' as http;
class DisplayVideo extends StatefulWidget {
String id;
#override
DisplayVideo(this.id);
_DisplayVideoState createState() => _DisplayVideoState();
}
class _DisplayVideoState extends State<DisplayVideo> {
late YoutubePlayerController _controller ;
Future<List<YoutubeDetail>> _loadCSV() async {
Map<String, String> allData = {
'login': '',
'password': '',
};
final Uri url = Uri.parse(
'https://raw.githubusercontent.com/JornaldRem/bedtime_story/main/videoId.csv');
final response = await http.get(url);
csv.CsvToListConverter converter =
new csv.CsvToListConverter(eol: '\r\n', fieldDelimiter: ',');
List<List> listCreated = converter.convert(response.body);
// the csv file is converted to a 2-Dimensional list
List<YoutubeDetail> youtubeDetailList = [];
for (int i = 0; i < listCreated.length; i++) {
YoutubeDetail temp = YoutubeDetail(
listCreated[i][0],
listCreated[i][1],
);
youtubeDetailList.add(temp);
}
return youtubeDetailList;
}
#override
void initState() {
// TODO: implement initState
super.initState();
_controller = YoutubePlayerController(
initialVideoId: widget.id,
flags: YoutubePlayerFlags(
autoPlay: true,
mute: false,
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
title: Text('Title'),
toolbarHeight: 60,
backgroundColor: const Color(0xFF006666),
),
body: Column(
children: [
Container(
child: YoutubePlayer(
controller: _controller,
liveUIColor: Colors.amber,
),
),
Expanded(
child: Container(
child: FutureBuilder(
future: _loadCSV(),
builder: (BuildContext context,
AsyncSnapshot<List<YoutubeDetail>> snapshot) {
if (snapshot.hasData) {
List<YoutubeDetail> videoDetail = snapshot.data!;
return ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: videoDetail.length,
itemBuilder: (_, int index) {
if (index > 0) {
return GestureDetector(
child: Container(
height: 80,
child: DisplayVideoView(
videoDetail[index].url,
videoDetail[index].title),
),
onTap: (){
String url = videoDetail[index].url;
String id = url.substring(url.length - 11);
print("HEllo");
_controller.load(id);
// DisplayVideo(id);
}
);
} else {
return Container();
}
});
} else {
return Container();
}
}),
),
),
],
));
}
}
class DisplayVideoView extends StatelessWidget {
String videopath;
String title;
DisplayVideoView(this.videopath, this.title);
#override
Widget build(BuildContext context) {
String url = videopath;
String id = url.substring(url.length - 11);
// TODO: implement build
return Card(
clipBehavior: Clip.antiAlias,
child: Container(
height: 150,
padding: const EdgeInsets.all(0),
child: Row(children: [
Expanded(
flex: 6,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
'https://img.youtube.com/vi/$id/mqdefault.jpg'),
fit: BoxFit.fill)),
),
),
Spacer(
flex: 1,
),
Expanded(
flex: 14,
child: Container(
padding: const EdgeInsets.only(top: 2),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(title,
style: TextStyle(
fontSize: 16.0, fontWeight: FontWeight.bold)),
],
),
),
),
]),
),
);
}
}
What do you think about this approach:
import 'package:flutter/material.dart';
class ExampleWidget extends StatefulWidget {
const ExampleWidget({Key? key}) : super(key: key);
#override
_ExampleWidgetState createState() => _ExampleWidgetState();
}
class _ExampleWidgetState extends State<ExampleWidget> {
List<Widget> _myList = [];
void _loadFiveMore() {
_myList = <Widget>[
..._myList,
for (int i = _myList.length; i < _myList.length + 5; i++)
ListTile(title: Text('item $i')),
];
}
#override
void initState() {
_loadFiveMore();
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: ListView(children: [
..._myList,
OutlinedButton(
onPressed: () {
setState(() => _loadFiveMore());
},
child: const Text('get 5 more'))
]),
),
);
}
}
void main() {
runApp(const ExampleWidget());
}
You can use this package.
have loadmore callback, refresh call back
https://pub.dev/packages/loadmore_listview

Flutter - how to do i forward mapped data to another page

I have three files - companies.dart, Company_Card_Style.dart and Company_Details.
I'm mapping company parameters to company_card_Style from companies.dart, now i need to send the same data to companyDetails.dart, what should i pass in MaterialPageroute and how to receive in companyDetails
Companies file - in itembuilder, im passing a company detail to companycardstyle
import 'package:flutter/material.dart';
import './Object.dart';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'UI_Styles/Company_Card_Style.dart';
import 'dart:convert';
class Companies extends StatefulWidget {
#override
_CompaniesState createState() => _CompaniesState();
}
class _CompaniesState extends State<Companies> {
Future<List<Company>> _getCompanies() async {
var data = await http.get("http://localhost/crm_demo/getData.php");
var jsonData = json.decode(data.body);
List<Company> companies = [];
for (var c in jsonData) {
Company company = Company(
c["name"],
c["address"],
c["opportunities"],
c["pipelineRevenue"],
c["revenueAchieved"],
c["city"],
c["state"],
c["country"],
c["zipcode"],
c["phone"],
c["timezone"],
c["tags"]);
companies.add(company);
}
return companies;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Companies",
style: TextStyle(fontWeight: FontWeight.w600),
)),
body: FutureBuilder(
future: _getCompanies(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return CompanyCardStyle(company: snapshot.data[index]);
});
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}));
}
}
CompanyCardStyle.dart - Here on click of company name i want to redirect to detail page.
import 'package:flutter/material.dart';
import '../Object.dart';
import '../Detail_Pages/Company_details.dart';
class CompanyCardStyle extends StatelessWidget {
final Company company;
CompanyCardStyle({this.company});
#override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.fromLTRB(5.0, 5.0, 5.0, 0.0),
child: ExpansionTile(
tilePadding: EdgeInsets.only(left: 10.0, right: 10.0),
leading: CircleAvatar(radius: 20.0, child: Text(company.name[0])),
subtitle: Flexible(
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CompanyDetails(company: company)),
);
},
child: Text(
company.address,
overflow: TextOverflow.ellipsis,
),
)),
title:
Text(company.name, style: TextStyle(fontWeight: FontWeight.w600)),
children: <Widget>[
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
companyLabels('Phone Number'),
companyLabels('Opportunities'),
companyLabels('Pipeline Revenue'),
companyLabels('Revenue Achieved'),
],
),
Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
companyValues(company.phone.toString()),
companyValues(company.opportunities),
companyValues(company.pipelineRevenue.toString()),
companyValues(company.revenueAchieved.toString())
],
),
)
]))
],
));
}
Widget companyLabels(String values) {...}
Widget companyValues(String values) {...}
}
CompanyDetails.dart - Let me know how should i get data here.
import 'package:flutter/material.dart';
class CompanyDetails extends StatefulWidget {
#override
_CompanyDetailsState createState() => _CompanyDetailsState();
}
class _CompanyDetailsState extends State<CompanyDetails> {
#override
Widget build(BuildContext context) {
return Container(
child: Text("I have to display rest of the company data here"),
);
}
}
You could try this on CompanyDetails.dart
class CompanyDetails extends StatefulWidget {
CompanyDetails ({Key key, this.company})
: super(key: key);
final Company company;
#override
_CompanyDetailsState createState() => _CompanyDetailsState();
}
class _CompanyDetailsState extends State<CompanyDetails> {
Company company;
#override
void initState() {
company= widget.company;
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
child: Text("My company name is ${company.name}"),
);
}
}

Flutter : problem re-rendering ListView using Stream Builder in bottom Navbar

I have a problem when displaying data to list view using the stream builder, my list view is always re-reload, when the tab is active.
i am implementing AutomaticKeepAliveClientMixin, but that is still not working.
here my code:
Home Bottom Nav :
https://pastebin.com/B9qf0zZR
List View index:
import 'package:eservice_f/src/blocs/listDataBloc.dart';
import 'package:eservice_f/src/models/listModel.dart';
import 'package:eservice_f/utils/layout.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class ServiceIndex extends StatefulWidget {
ServiceIndex({Key key}) : super(key: key);
_ServiceIndexState createState() => _ServiceIndexState();
}
class _ServiceIndexState extends State<ServiceIndex> with AutomaticKeepAliveClientMixin<ServiceIndex>{
ListDataBloc _bloc;
#override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
#override
void initState() {
// TODO: implement initState
super.initState();
_bloc = ListDataBloc();
_bloc.showAllData();
}
#override
void dispose() {
// TODO: implement dispose
super.dispose();
//bloclist.dispose();
}
#override
Widget build(BuildContext context) {
super.build(context);
return Container(
child: StreamBuilder(
stream: _bloc.allData,
builder: (context, AsyncSnapshot<ListData> snapshot) {
print(snapshot.data);
if (snapshot.hasData) {
return Container(
color: Colors.white,
child: Center(
child: getServiceList(context, snapshot),
),
);
} else if (snapshot.hasError) {
return Text(snapshot.error.toString());
}
return Container(
color: Colors.white,
child: Center(child: CupertinoActivityIndicator()));
}),
);
}
Widget getServiceList(
BuildContext context, AsyncSnapshot<ListData> snapshot) {
SizeConfig().init(context);
var _list_data = snapshot.data.data;
return ListView.builder(
itemCount: _list_data.length,
itemBuilder: (BuildContext contex, int index) {
return Column(
children: <Widget>[
ListTile(
onTap: () {
print("List Tapped");
},
leading: Column(
children: <Widget>[
Icon(
Icons.check_circle_outline,
size: SizeConfig.blocHorizontal * 10,
),
],
),
title: Text("SBG/LK/20180814"),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('SusSystem Update Training MEX',
overflow: TextOverflow.ellipsis),
Text(
'So basically you building a Facebook/Instagram like application, where user logs in, scrolls through their feed, stalks through different profiles, and when done, wants to log out of the app',
overflow: TextOverflow.ellipsis),
],
),
trailing: (_list_data[index].activityStatus == "1")
? Text("Draft")
: Text("Confirm"),
),
Divider(
height: 1.0,
),
],
);
});
}
}
Bloc:
import 'package:eservice_f/src/models/listModel.dart';
import 'package:eservice_f/src/resources/repository.dart';
import 'package:rxdart/rxdart.dart';
class ListDataBloc{
final _repository = Repository();
final _fetcher = PublishSubject<ListData>();
Observable<ListData> get allData => _fetcher.stream;
showAllData() async{
ListData datas = await _repository.fetchAll();
_fetcher.sink.add(datas);
}
dispose(){
_fetcher.close();
}
}
//initial Bloc
//final bloclist = ListDataBloc();