Flutter: How to create a simple custom bar chart / slider - flutter

I have a JSON like this:
[
{
"column": "Column 1",
"slider1": 86,
"slider2": 43,
"slider3": 25
},
{
"column": "Column 2",
"slider1": 64,
"slider2": 72,
"slider3": 39
}
]
I want to make a Bar chart or Slider like this:
Max length of bar chart = 100
The length of the bar chart = its value (Ex slider1 = 86)
I thought of using Stack but I don't know how to do. So pls help me, this is the main file:
import 'dart:convert';
import 'package:ask/model/data_model.dart';
import 'package:flutter/material.dart';
class Page4 extends StatefulWidget {
#override
_Page4State createState() => _Page4State();
}
class _Page4State extends State<Page4> {
List<Data> _data = [];
Future<List<Data>> getDataFromJson(BuildContext context) async {
String jsonString = await DefaultAssetBundle.of(context).loadString('assets/data.json');
List<dynamic> raw = jsonDecode(jsonString);
return raw.map((e) => Data.fromJson(e)).toList();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Simple Slider')),
body: FutureBuilder(
future: getDataFromJson(context),
builder: (context, snapshot) {
List<Data> _data = snapshot.data;
return ListView.separated(
separatorBuilder: (context, index) => Divider(),
itemCount: _data.length,
itemBuilder: (context, index) {
Data data = _data[index];
return Column(children: [
Row(children: [
Expanded(child: Text(data.column)),
Expanded(
child: Column(children: [
SizedBox(height: 5),
Container(
width: double.infinity,
color: Colors.grey[300],
child: Text(data.slider1.toString(), style: TextStyle(color: Colors.blue[(data.slider1 / 10).round() * 100])), //How to put a bar chart here
),
SizedBox(height: 5),
Container(
width: double.infinity,
color: Colors.grey[300],
child: Text(data.slider2.toString(), style: TextStyle(color: Colors.blue[(data.slider2 / 10).round() * 100])), //How to put a bar chart here
),
SizedBox(height: 5),
Container(
width: double.infinity,
color: Colors.grey[300],
child: Text(data.slider3.toString(), style: TextStyle(color: Colors.blue[(data.slider3 / 10).round() * 100])), //How to put a bar chart here
),
]),
)
])
]);
});
}));
}
}
.......................................................................................

here is a solution which can help you but these are static bars, in case you want to have an interaction with your ui , you should use slider widgetmore info.
code sample
#override
Widget build(BuildContext context) {
final double sliderWidth = MediaQuery.of(context).size.width;
return Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CustomSlider(
percentage: 12 / 100,
width: sliderWidth,
),
CustomSlider(
percentage: 90 / 100,
width: sliderWidth,
),
CustomSlider(
percentage: 50 / 100,
width: sliderWidth,
),
],
),
),
);
}
}
class CustomSlider extends StatelessWidget {
final double percentage;
final double width;
CustomSlider({
this.percentage,
this.width,
});
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Stack(
children: [
Container(
width: double.infinity,
height: 20,
color: Colors.grey,
),
Container(
color: Colors.blue,
width: percentage == null ? 0 : width * percentage,
height: 20,
child: Align(
alignment: Alignment.centerLeft,
child: Text(
percentage == null ? "0" : (percentage * 100).toString(),
),
),
),
],
),
);
}
}
good luck.

Related

infinite_scroll_pagination loading all the pages altogether: Flutter

I am making a Flutter Application where I am using Lazy Loading to load the data from server.
Now, the page I have made consists of following widgets in order-
Stack (with a button and a container)
SizedBox (for spacing)
SliverPagedList (to show lazy-loaded data).
Now, since the SliverPagedList is a Sliver widget I am using a CustomScrollView for the preceding widgets (Stack and SizedBox). I referred- https://pub.dev/packages/infinite_scroll_pagination/example#:~:text=Preceding/Following%20Items
The problem-
All the pages are fetched all together even when I have not reached the end of the page.
My code is-
class CategoryArticlePage extends StatefulWidget {
CategoryArticlePage({required this.category});
Category category;
#override
State<CategoryArticlePage> createState() => _CategoryArticlePageState();
}
class _CategoryArticlePageState extends State<CategoryArticlePage> {
SharedPreferences? _sharedPreferences;
final PostService _postService = PostService();
// List<posts.Post2>? _posts;
Future<void>? _loadData;
final PagingController<int, posts.Post2> _pageController =
PagingController(firstPageKey: 0);
#override
void initState() {
// _loadData = _loadArticles(); //without paging
_pageController.addPageRequestListener((pageKey) {
_loadArticles(pageKey);
});
super.initState();
}
Future<void> _loadArticles(int pageKey) async {
try {
_sharedPreferences ??= await SharedPreferences.getInstance();
final _posts = await _postService.getAllPostsForCategory(
token: _sharedPreferences!.getString(BEARER_TOKEN)!,
categoryid: widget.category.categoryId,
pageKey: pageKey,
pageSize: PAGE_SIZE);
final isLastPage = _posts.length < PAGE_SIZE;
if (isLastPage) {
_pageController.appendLastPage(_posts);
} else {
final nextPageKey = pageKey + 1;
_pageController.appendPage(_posts, nextPageKey);
}
} catch (error) {
_pageController.error = error;
}
}
#override
Widget build(BuildContext context) {
final height = MediaQuery.of(context).size.height -
// _appBar.preferredSize.height -
MediaQuery.of(context).padding.top -
MediaQuery.of(context).padding.bottom;
final width = MediaQuery.of(context).size.width;
return Scaffold(
body: SafeArea(
child: Consumer<CategoryProvider>(
builder: ((context, categoryProvider, child) {
return RefreshIndicator(
onRefresh: () {
return Future.sync(
() => _pageController.refresh(),
);
},
child: CustomScrollView(
slivers: <Widget>[
SliverToBoxAdapter(
child: Column(
children: [
Stack(
children: [
Container(
decoration: categoryTopDecoration,
padding: EdgeInsets.only(
left: 2,
right: 2,
bottom: 2,
),
alignment: Alignment.bottomLeft,
height: height * 0.4,
child: ListTile(
title: Text(
'${widget.category.categoryName}',
style: TextStyle(
fontSize: 40.sp,
fontWeight: FontWeight.bold,
),
),
subtitle: Text(
'${widget.category.categoryDescription}',
style: TextStyle(
fontSize: 20.sp,
fontWeight: FontWeight.w700,
),
),
),
),
Positioned(
right: 10,
top: 10,
child: Padding(
padding: EdgeInsets.only(
right: 4,
),
child: OutlinedButton(
onPressed: () async {
if (categoryProvider.subscribedCategoriesIDs
.contains(widget.category.categoryId)) {
bool result = await categoryProvider
.unsubscribeFromCategory(
token: _sharedPreferences!
.getString(BEARER_TOKEN)!,
userid: _sharedPreferences!
.getInt(USER_ID)!,
categoryid:
widget.category.categoryId);
} else {
bool result = await categoryProvider
.subscribeToCategory(
token: _sharedPreferences!
.getString(BEARER_TOKEN)!,
userid: _sharedPreferences!
.getInt(USER_ID)!,
categoryid:
widget.category.categoryId);
}
},
child: (categoryProvider
.subscribedCategoriesIDs
.contains(widget.category.categoryId)
? Text('Subscribed')
: Text('Subscribe')),
),
),
),
],
),
SizedBox(
height: height * 0.02,
),
],
),
),
PagedSliverList<int, posts.Post2>.separated(
pagingController: _pageController,
builderDelegate: PagedChildBuilderDelegate<posts.Post2>(
animateTransitions: true,
// [transitionDuration] has a default value of 250 milliseconds.
transitionDuration: const Duration(milliseconds: 500),
itemBuilder: (context, item, index) {
return Padding(
padding: EdgeInsets.only(
bottom: 2,
top: 2,
),
child: GestureDetector(
onTap: () {
Get.to(() => ExploreViewArticle(
post: item,
sharedPreferences: _sharedPreferences!));
},
child: ListTile(
leading: SizedBox(
child: SizedBox(
height: 100,
width: 100,
child: CachedNetworkImage(
imageUrl:
'https://<blobstorage>/imagecontainer/${item.image}',
placeholder: (context, url) => Center(
child: Container(
height: 50,
width: 50,
child: DataLoadingIndicator(),
),
),
errorWidget: (context, url, error) =>
Image.asset(
'images/category_default.jpg'),
fit: BoxFit.cover,
),
),
),
title: Text('${item.title}'),
),
),
);
},
),
separatorBuilder: (context, index) {
return Container(
height: 2,
color: Colors.black,
);
},
),
],
),
);
}),
),
),
);
}
#override
void dispose() {
log('CategoryArticlePage dispose called');
_pageController.dispose();
super.dispose();
}
}

CupertinoSliverRefreshControl with horizontal ListView

I have horizontal ListView.builder and CupertinoSliverRefreshControl, so when it reaches the end, I want to display Loading indicator, but for some reason I am getting error
Null check operator used on a null value
The relevant error-causing widget was
CustomScrollView
lib/sliver_loading.dart:19
The most unclear part is that CupertinoSliverRefreshControl works fine with Vertical ListView.builder, but when I change Axis on horizontal it rises this above error.
Here is a code :
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(15),
child: CustomScrollView(
scrollDirection: Axis.horizontal, // Here is when Error rise
slivers: [
SliverToBoxAdapter(
child: SizedBox(
height: 200,
child: ListView.builder(
scrollDirection: Axis.horizontal,
primary: false,
shrinkWrap: true,
itemCount: 4,
itemBuilder: (context, index) {
return Container(
width: 100,
height: 200,
color: colors[index],
);
},
),
),
),
CupertinoSliverRefreshControl(
onRefresh: () async {
await Future.delayed(Duration(seconds: 3));
print('loaded');
},
),
],
),
),
);
}
Can anyone explain me, why is this happening and what are the solutions?
There is a workaround with current snippet instead of using CupertinoSliverRefreshControl return row with loading widget for last item. Also wrap Container with Center.
itemBuilder: (context, index) {
return index == 13 // items length-1
? Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
margin: EdgeInsets.all(20),
width: 100,
height: 200,
color: Colors.cyanAccent,
),
CircularProgressIndicator(),
],
)
:Center( child: Container(
margin: EdgeInsets.all(20),
width: 100,
height: 200,
color: Colors.amber,
));
},
If you do use ListView, you can use ScrollController with listener and get position to load data using controller.position.maxScrollExtent* .9 ;load more on 90% scroll.
Also, using the same directional multi-scrollabe widgets is not necessary. We can skip using ListView and use SliverList. While the width is fixed, we can compare the items' length and current scroll position to using the controller.
final ScrollController controller = ScrollController();
#override
void initState() {
super.initState();
controller.addListener(() {
print(controller.offset);
//14 total item , I am using 90%
if (controller.offset > 100 * 14 * .9) {
// you may encounter multiple call use another flag or null to handle this
print("load more");
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(15),
child: CustomScrollView(
scrollDirection: Axis.horizontal,
controller: controller,
slivers: [
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => index == 13 // items length-1
? Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
margin: EdgeInsets.all(20),
width: 100,
height: 200,
color: Colors.cyanAccent,
),
CircularProgressIndicator(),
],
)
: Center(
child: Container(
margin: EdgeInsets.all(20),
width: 100,
height: 200,
color: Colors.amber,
)),
childCount: 14,
),
),
],
),
),
);
}
}
Okay, so here is a way how I solved this problem. Since CupertinoSliverRefreshControl does not work with horizontal ListView.builder, I decided to use CupertinoActivityIndicator and CupertinoActivityIndicator.partiallyRevealed.
When ListView reaches to the end, I am calculating distance between ListView.builder() and int distance and updating double progress for CupertinoActivityIndicator.partiallyRevealed, next when progress reaches 1.0 I just replace CupertinoActivityIndicator.partiallyRevealed with CupertinoActivityIndicator changing bool isActive value to true.
Finally it works like CupertinoSliverRefreshControl, just without slivers :).
Code Example
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class HorizontalLoader extends StatefulWidget {
const HorizontalLoader({Key? key}) : super(key: key);
static final colors = [
Colors.red,
Colors.indigoAccent,
Colors.purple,
Colors.amberAccent,
Colors.orange,
Colors.purple,
Colors.cyanAccent,
Colors.red,
Colors.indigoAccent,
Colors.purple,
];
#override
State<HorizontalLoader> createState() => _HorizontalLoaderState();
}
class _HorizontalLoaderState extends State<HorizontalLoader> {
int distance = 70; // offset
bool isActive = false;
double progress = 0.0;
// Base logic. you can also use this logic with ScrollController()
bool _handleNotification(ScrollNotification notify) {
double outRangeLoading = distance + notify.metrics.maxScrollExtent;
double currentPixel = notify.metrics.pixels;
if (notify.metrics.extentAfter <= 0.0) {
if (currentPixel >= outRangeLoading) {
networkLoader();
}
calculateProgress(outRangeLoading, currentPixel);
}
return true;
}
// Some math
void calculateProgress(outRangeLoading, currentPixel) {
double current, currentAsPrecent;
current = outRangeLoading - currentPixel;
currentAsPrecent = (100 * current) / distance;
setState(() {
progress = (100 - currentAsPrecent) * 0.01;
});
}
// To simulate loading data from Network
void networkLoader() async {
isActive = true;
await Future.delayed(Duration(seconds: 3));
isActive = false;
setState(() {
progress = 0.0;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.only(top: 200, bottom: 200),
child: Stack(
children: [
Positioned(
right: 15,
top: 210,
child: isActive
? CupertinoActivityIndicator()
: CupertinoActivityIndicator.partiallyRevealed(
progress: progress,
),
),
NotificationListener<ScrollNotification>(
onNotification: _handleNotification,
child: ListView.builder(
scrollDirection: Axis.horizontal,
physics: const BouncingScrollPhysics(),
itemCount: HorizontalLoader.colors.length + 1,
itemBuilder: (context, index) {
if (index == HorizontalLoader.colors.length) {
return isActive ? SizedBox(width: 50) : SizedBox();
}
return Container(
width: 100,
height: 100,
color: HorizontalLoader.colors[index],
);
},
),
),
],
),
),
);
}
}

flutter Infinite Scrolling for ListView.builder

I've to use graphql query and I've got data page by page.
so I need to Infinite Scrolling in my list view builder but I don't know how to add num in page.
can anyone help me, please?
this is my query:
query homeview(\$moreId: ID!, \$page: Int! ){
homeview(HM_ID: \$moreId, page: \$page){
HM_ID
HM_Type_ID
HM_Type_Name
}
}
""";
and this is my variable to pass int number in page:
dynamic pageNum = 0;
here is the controller :
ScrollController _scrollController = new ScrollController( initialScrollOffset: 10,
and this is my list view builder:
class MoreEpd extends StatefulWidget {
final String moreId;
const MoreEpd({Key? key, required this.moreId}) : super(key: key);
#override
_MoreEpdState createState() => _MoreEpdState();
}
class _MoreEpdState extends State<MoreEpd> {
double pageWidth = 0;
double pageHeigh = 0;
dynamic pageNum = 0;
final String leftArrow = 'assets/icons/left-arrow.svg';
String getSearchResult = """
query homeview(\$moreId: ID!, \$page: Int! ){
homeview(HM_ID: \$moreId, page: \$page){
HM_ID
Priority
Details{
Ep_ID
Image
title
Pod_title
}
}
}
""";
#override
Widget build(BuildContext context) {
pageWidth = MediaQuery.of(context).size.width;
pageHeigh = MediaQuery.of(context).size.height;
return Container(
child: Query(
options: QueryOptions(
document: gql(getSearchResult),
variables: {'moreId': widget.moreId, 'page': pageNum},
),
builder: (
QueryResult result, {
Refetch? refetch,
FetchMore? fetchMore,
}) {
return handleResult(result);
},
),
);
}
Widget handleResult(QueryResult result) {
var data = result.data!['homeview']['Details'] ?? [];
return Container(
child: ListView.builder(
padding: EdgeInsets.only(top: 15),
shrinkWrap: true,
itemCount: data.length ,
itemBuilder: (context, index) {
return InkWell(
onTap: () {},
child: Padding(
padding: EdgeInsets.only(
top: pageWidth * 0.0,
right: pageWidth * 0.08,
left: pageWidth * 0.08,
bottom: pageWidth * 0.0),
child: Container(
child: Stack(
children: [
Column(
children: [
Padding(
padding:
EdgeInsets.only(bottom: pageWidth * 0.060),
child: Row(
children: [
Padding(
padding:
EdgeInsets.only(left: pageWidth * 0.01),
child: Container(
// alignment: Alignment.centerRight,
width: pageWidth * 0.128,
height: pageWidth * 0.128,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: CachedNetworkImageProvider(
data[index]['Image'],
)),
borderRadius: BorderRadius.all(
Radius.circular(15)),
// color: Colors.redAccent,
border: Border.all(
color: MyColors.lightGrey,
width: 1,
)),
),
),
Expanded(
child: Row(
children: [
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Container(
width: pageWidth * 0.5,
alignment: Alignment.centerRight,
child: Text(
data[index]['title'],
textAlign: TextAlign.right,
overflow: TextOverflow.ellipsis,
maxLines: 1,
// softWrap: true,
style: TextStyle(
// fontWeight: FontWeight.bold,
fontSize: 14,
),
),
),
],
),
],
),
)
],
),
),
],
),
],
),
),
),
);
}));
}}
can anyone help me please how can I use infinite scrolling to load other pages in my query?
The easiest way is to use a ListView.builder without specifying the itemCount parameter.
Here is the simplest example:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Infinite List"),
),
body: ListView.builder(
itemBuilder: (context, index) {
return Text("$index");
},
),
);
}
}
Later, you can enhance this by fetching real data. You could show a 'CircularProgressIndicator' in the last item of the list while waiting for the new data.
body: ListView.builder(
itemBuilder: (context, index) {
if (index < data.length) {
// Show your info
return Text("$index");
} else {
getMoreData();
return Center(child: CircularProgressIndicator());
}
},
itemCount: data.length + 1,
),
You can see that we trick the list by adding an index, and calling for more data when displaying that final index.
getMoreData() would include a call to setState() to force a rebuild and to take into account the new data.
Here I've created a flat_list widget which has a similar specification as in React Native. Hope the below works.
FlatList(
+ loading: loading.value,
+ onEndReached: () async {
+ loading.value = true;
+ await Future.delayed(const Duration(seconds: 2));
+ if (context.mounted) {
+ items.value += getMoreData();
+ loading.value = false;
+ }
+ },
data: items.value,
buildItem: (item, index) {
var person = items.value[index];
return ListItemView(person: person);
},
),

unable to update single item background color in Listview.builder in flutter

Im working on flutter listview.builder I just want to change background colour of 3 items in Row widget at where user clicks but its changing colours of all the items in listview. just want to change color at specific index based on user click. here is my code...
import 'dart:convert';
import 'package:dotted_border/dotted_border.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:fluttergyancare/ColorLoader3.dart';
import 'package:fluttergyancare/Models/AddAttendanceModel.dart';
import 'package:fluttergyancare/Models/serializers.dart';
import 'package:gradient_app_bar/gradient_app_bar.dart';
import 'package:http/http.dart' as http;
class AddAttendance extends StatelessWidget {
final String id;
final String section;
final String school;
final String Class;
AddAttendance({this.id, this.section, this.school, this.Class});
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFFEEEEEE),
appBar: GradientAppBar(
title: Text('Normal'),
centerTitle: true,
backgroundColorStart: Color(0xFFFF9844),
backgroundColorEnd: Color(0xFFFD7267),
),
body: FutureBuilderUI(
id: id,
section: section,
school: section,
Class: Class,
),
);
}
}
Future<AddAttendanceModel> call(http.Client client, String id, String section,
String school, String Class) async {
var send =
await http.post("http://localhost/app/api/get_students", body: {
"teacher_id": "1",
"class_id": id,
"section": section,
"school_name": school,
"Class": Class,
});
return compute(parseJson, (send.body));
}
AddAttendanceModel parseJson(String json) {
final jsonStr = jsonDecode(json);
AddAttendanceModel article = standardSerializers.deserializeWith(
AddAttendanceModel.serializer, jsonStr);
return article;
}
class FutureBuilderUI extends StatelessWidget {
final String id;
final String section;
final String school;
final String Class;
FutureBuilderUI({this.id, this.section, this.school, this.Class});
#override
Widget build(BuildContext context) {
return FutureBuilder<AddAttendanceModel>(
future: call(http.Client(), id, section, school, Class),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.active:
case ConnectionState.waiting:
return Center(
child: ColorLoader3(
radius: 25.0,
dotRadius: 10.0,
),
);
case ConnectionState.done:
if (snapshot.hasError) print(snapshot.error);
print(snapshot.data.studentsInfo.length.toString() +
" StudentsInfo Length");
if (snapshot.data.studentsInfo.length != 0) {
return snapshot.hasData
? AddAttendanceUI(students: snapshot.data)
: Container();
} else {
return Container(
padding: EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Align(alignment: Alignment.center, child: Text("No..")),
],
),
);
}
}
return null;
// return ListView.builder(
// itemBuilder: (context, index) {
// return ListTile(
// title: Text(snapshot.data[index].status),
// );
// },
// );
},
);
}
}
class AddAttendanceUI extends StatefulWidget {
final AddAttendanceModel students;
AddAttendanceUI({this.students});
#override
_AddAttendanceUIState createState() => _AddAttendanceUIState();
}
class _AddAttendanceUIState extends State<AddAttendanceUI> {
var pColor = Colors.green;
var aColor = Colors.grey;
var nColor = Colors.grey;
int _onSelectedindex = 0;
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: widget.students.studentsInfo.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(width: 10),
Spacer(),
Padding(
padding: const EdgeInsets.only(right: 10.0),
child: Row(
children: <Widget>[
GestureDetector(
child: pSelector(),
onTap: () {
print(index);
setState(() {
// final a = widget.students.studentsInfo
// .where((l) =>
// l.id ==
// widget.students.studentsInfo[index].id)
// .toList();
_onSelectedindex = index;
aColor = Colors.grey;
pColor = Colors.green;
nColor = Colors.grey;
});
},
),
SizedBox(width: 12),
GestureDetector(
onTap: () {
setState(() {
print(widget.students.studentsInfo[index].id);
aColor = Colors.red;
pColor = Colors.grey;
nColor = Colors.grey;
});
},
child: aSelector()),
SizedBox(width: 12),
GestureDetector(
child: nSelector(),
onTap: () {
setState(() {
print(widget.students.studentsInfo[index].id);
aColor = Colors.grey;
pColor = Colors.grey;
nColor = Colors.orange;
});
},
),
],
),
)
],
),
);
});
}
hello() {}
Widget pSelector() {
return Padding(
padding: const EdgeInsets.only(top: 5.0),
child: ClipOval(
child: Container(
color: pColor,
height: 30,
width: 30,
child: DottedBorder(
strokeWidth: 2.5,
borderType: BorderType.Circle,
color: Colors.white,
child: Center(
child: Text(
"A",
style: TextStyle(color: Colors.white),
),
),
),
),
),
);
}
Widget aSelector() {
return Padding(
padding: const EdgeInsets.only(top: 5.0),
child: ClipOval(
child: Container(
color: aColor,
height: 30,
width: 30,
child: DottedBorder(
strokeWidth: 2.5,
borderType: BorderType.Circle,
color: Colors.white,
child: Center(
child: Text(
"B",
style: TextStyle(color: Colors.white),
),
),
),
),
),
);
}
Widget nSelector() {
return Padding(
padding: const EdgeInsets.only(top: 5.0),
child: ClipOval(
child: Container(
color: nColor,
height: 30,
width: 30,
child: DottedBorder(
strokeWidth: 2.5,
borderType: BorderType.Circle,
color: Colors.white,
child: Center(
child: Text(
"C",
style: TextStyle(color: Colors.white),
),
),
),
),
),
);
}
}
see Images below image1 image2 image3
I tried to attach streamBuilder with each single item in listview but not working.
I expect when user taps on A/B/C only at that index colours should be change but its changing colours of all the items
You are using the same 3 variables pColor, aColor, nColor for all the items. You should have a list or a map of these variables, one for each item. Or create a separate widget to handle these variables internally on that widget.

How to navigate to another page within a stack in flutter?

I am currently trying to manage the navigation logic within the flutter stack I have created.
I would like to add separate page navigation to each of the list items listed:
List<String> images = [
"assets/berries-chocolates-delicious-918327.jpg",
"assets/adult-beauty-cosmetic-1029896.jpg",
"assets/aerial-shot-architecture-beach-1488515.jpg",
"assets/brush-brushes-cosmetics-212236.jpg",
];
List<String> title = [
"Cadbury",
"Biotherme",
"Trip Advisor",
"L'Oreal Paris",
];
> This is the associated stack logic code in another file:
Stack(
children: <Widget>[
CardScrollWidget(currentPage),
Positioned.fill(
child: PageView.builder(
itemCount: images.length,
controller: controller,
reverse: true,
itemBuilder: (context, index) {
return Container();
},
),
)
],
),
// SizedBox(
// height: 10.0,
// ),
This is the associated widget file code:
import 'package:flutter/material.dart';
import '../screens/introductory_screen.dart';
import 'data.dart';
import 'dart:math';
import '../constants/constants.dart';
class CardScrollWidget extends StatefulWidget {
var currentPage;
CardScrollWidget(this.currentPage);
#override
_CardScrollWidgetState createState() => _CardScrollWidgetState();
}
class _CardScrollWidgetState extends State<CardScrollWidget> {
var padding = 20.0;
var verticalInset = 20.0;
#override
Widget build(BuildContext context) {
return new AspectRatio(
aspectRatio: widgetAspectRatio,
child: LayoutBuilder(builder: (context, contraints) {
var width = contraints.maxWidth;
var height = contraints.maxHeight;
var safeWidth = width - 2 * padding;
var safeHeight = height - 2 * padding;
var heightOfPrimaryCard = safeHeight;
var widthOfPrimaryCard = heightOfPrimaryCard * cardAspectRatio;
var primaryCardLeft = safeWidth - widthOfPrimaryCard;
var horizontalInset = primaryCardLeft / 2;
List<Widget> cardList = List();
for (var i = 0; i < images.length; i++) {
var delta = i - widget.currentPage;
bool isOnRight = delta > 0;
var start = padding +
max(
primaryCardLeft -
horizontalInset * -delta * (isOnRight ? 15 : 1),
0.0);
var cardItem = Positioned.directional(
top: padding + verticalInset * max(-delta, 0.0),
bottom: padding + verticalInset * max(-delta, 0.0),
start: start,
textDirection: TextDirection.rtl,
child: ClipRRect(
borderRadius: BorderRadius.circular(16.0),
child: Container(
decoration: BoxDecoration(
color: Colors.deepPurpleAccent,
boxShadow: [
BoxShadow(
color: Colors.black12,
offset: Offset(3.0, 6.0),
blurRadius: 10.0)
]),
child: AspectRatio(
aspectRatio: cardAspectRatio,
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Image.asset(
images[i],
fit: BoxFit.cover,
),
Align(
alignment: Alignment.bottomLeft,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(
horizontal: 16.0, vertical: 8.0),
child: Container(
decoration: BoxDecoration(
color: Colors.deepPurpleAccent,
borderRadius: BorderRadius.circular(10.0),
),
child: Padding(
padding: const EdgeInsets.all(6.0),
This is where a gesture detector will be added to create a navigation link
child: Text(
title[i],
style: kCampaignLabelStyle,
),
),
),
),
This is where a gesture detector will be added to create a navigation link
// SizedBox(
// height: 10.0,
// ),
// Padding(
// padding: const EdgeInsets.only(
// left: 12.0, bottom: 12.0),
// child: Container(
// padding: EdgeInsets.symmetric(
// horizontal: 22.0, vertical: 6.0),
// decoration: BoxDecoration(
// color: Colors.deepPurpleAccent,
// borderRadius: BorderRadius.circular(20.0)),
// child: Text(
// "Read More",
// style: TextStyle(color: Colors.white),
// ),
// ),
// )
],
),
)
],
),
),
),
),
);
cardList.add(cardItem);
}
return Stack(
children: cardList,
);
}),
);
}
}
If anyone can help with the navigation logic, I would appreciate it.
create seperate files
Cadbury.dart
class Cadbury extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return CadburyState();
}
}
class CadburyState extends State<DashboardApp> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("Cadbury Screen"),
backgroundColor: MyColor.colorRed,
),
backgroundColor: MyColor.colorRed,
body: new Center());
}
}
Biotherme.dart
class Biotherme extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return BiothermeState();
}
}
class BiothermeState extends State<Biotherme> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("Biotherme Screen"),
backgroundColor: MyColor.colorRed,
),
backgroundColor: MyColor.colorRed,
body: new Center());
}
}
and make the redirections like this
// common function to create button and redirects the page which is in callback name
Widget buttonBuilder(
String buttonText, BuildContext context, Widget callbackName) {
return new RaisedButton(
child: Text(buttonText),
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => callbackName));
});
}
// home redirection screen which redirects to the cadbury and Biotherme screen
class RedirectionScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(title: Text("Home Screen")),
body: Center(
child: new Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
buttonBuilder('Cadbury Screen', context, Cadbury()),
buttonBuilder('Biotherme Screen', context, Biotherme()),
],
),
));
}
}
try this below code for Navigation, it works for me
If you want to navigate the page on the button's click event then write code
return new RaisedButton(
child: Text(buttonText),
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => redirection_page_name));
});
Note: Here redirection_page_name is the page or widget name which you want to be load on the button's click event.
The original syntax is
Navigator.push(context, MaterialPageRoute(builder: (context) => redirection_page_name));
here context is the current screen widget context which is built, and redirection_page_name is the new page/widget which is being loaded.