Trigger function on swipe - flutter

I am trying to implement a way of triggering a function on a swipe in Flutter. I am building a UI with a stacked card layout using Flutter_Swiper (https://pub.dev/packages/flutter_swiper)
I have tried using both GestureDetector and SwipeDetector (https://pub.dev/packages/swipedetector) but both of these result in Flutter_Swiper breaking.
Does anyone know of a way of using Flutter_Swiper to trigger a function?

You can copy paste run full code below
You can call function in onIndexChanged
code snippet
return Swiper(
onTap: (int index) {
...
customLayoutOption: customLayoutOption,
fade: _fade,
index: _currentIndex,
onIndexChanged: (int index) {
setState(() {
_currentIndex = index;
print(_currentIndex);
});
},
working demo
output
I/flutter ( 4664): 1
I/flutter ( 4664): 2
full code
import 'package:flutter/material.dart';
import 'package:flutter_page_indicator/flutter_page_indicator.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
import 'package:flutter/cupertino.dart';
class FormWidget extends StatelessWidget {
final String label;
final Widget child;
FormWidget({this.label, this.child});
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(5.0),
child: Row(
children: <Widget>[
Text(label, style: TextStyle(fontSize: 14.0)),
Expanded(
child: Align(alignment: Alignment.centerRight, child: child))
],
));
}
}
class FormSelect<T> extends StatefulWidget {
final String placeholder;
final ValueChanged<T> valueChanged;
final List<dynamic> values;
final dynamic value;
FormSelect({this.placeholder, this.valueChanged, this.value, this.values});
#override
State<StatefulWidget> createState() {
return _FormSelectState();
}
}
class _FormSelectState extends State<FormSelect> {
int _selectedIndex = 0;
#override
void initState() {
for (int i = 0, c = widget.values.length; i < c; ++i) {
if (widget.values[i] == widget.value) {
_selectedIndex = i;
break;
}
}
super.initState();
}
#override
Widget build(BuildContext context) {
String placeholder = widget.placeholder;
List<dynamic> values = widget.values;
return Container(
child: InkWell(
child: Text(_selectedIndex < 0
? placeholder
: values[_selectedIndex].toString()),
onTap: () {
_selectedIndex = 0;
showBottomSheet(
context: context,
builder: (BuildContext context) {
return SizedBox(
height: values.length * 30.0 + 200.0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(
height: values.length * 30.0 + 70.0,
child: CupertinoPicker(
itemExtent: 30.0,
children: values.map((dynamic value) {
return Text(value.toString());
}).toList(),
onSelectedItemChanged: (int index) {
_selectedIndex = index;
},
),
),
Center(
child: RaisedButton(
onPressed: () {
if (_selectedIndex >= 0) {
widget
.valueChanged(widget.values[_selectedIndex]);
}
setState(() {});
Navigator.of(context).pop();
},
child: Text("ok"),
),
)
],
),
);
});
},
),
);
}
}
class NumberPad extends StatelessWidget {
final num number;
final num step;
final num max;
final num min;
final ValueChanged<num> onChangeValue;
NumberPad({this.number, this.step, this.onChangeValue, this.max, this.min});
void onAdd() {
onChangeValue(number + step > max ? max : number + step);
}
void onSub() {
onChangeValue(number - step < min ? min : number - step);
}
#override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
IconButton(icon: Icon(Icons.exposure_neg_1), onPressed: onSub),
Text(
number is int ? number.toString() : number.toStringAsFixed(1),
style: TextStyle(fontSize: 14.0),
),
IconButton(icon: Icon(Icons.exposure_plus_1), onPressed: onAdd)
],
);
}
}
const List<String> images = [
"https://picsum.photos/250?image=9",
"https://picsum.photos/250?image=10",
"https://picsum.photos/250?image=11",
];
class ExampleCustom extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _ExampleCustomState();
}
}
class _ExampleCustomState extends State<ExampleCustom> {
//properties want to custom
int _itemCount;
bool _loop;
bool _autoplay;
int _autoplayDely;
double _padding;
bool _outer;
double _radius;
double _viewportFraction;
SwiperLayout _layout;
int _currentIndex;
double _scale;
Axis _scrollDirection;
Curve _curve;
double _fade;
bool _autoplayDisableOnInteraction;
CustomLayoutOption customLayoutOption;
Widget _buildItem(BuildContext context, int index) {
return ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(_radius)),
child: Image.network(
images[index % images.length],
fit: BoxFit.fill,
),
);
}
#override
void didUpdateWidget(ExampleCustom oldWidget) {
customLayoutOption = CustomLayoutOption(startIndex: -1, stateCount: 3)
.addRotate([-45.0 / 180, 0.0, 45.0 / 180]).addTranslate(
[Offset(-370.0, -40.0), Offset(0.0, 0.0), Offset(370.0, -40.0)]);
super.didUpdateWidget(oldWidget);
}
#override
void initState() {
customLayoutOption = CustomLayoutOption(startIndex: -1, stateCount: 3)
.addRotate([-25.0 / 180, 0.0, 25.0 / 180]).addTranslate(
[Offset(-350.0, 0.0), Offset(0.0, 0.0), Offset(350.0, 0.0)]);
_fade = 1.0;
_currentIndex = 0;
_curve = Curves.ease;
_scale = 0.8;
_controller = SwiperController();
_layout = SwiperLayout.TINDER;
_radius = 10.0;
_padding = 0.0;
_loop = true;
_itemCount = 3;
_autoplay = false;
_autoplayDely = 3000;
_viewportFraction = 0.8;
_outer = false;
_scrollDirection = Axis.horizontal;
_autoplayDisableOnInteraction = false;
super.initState();
}
// maintain the index
Widget buildSwiper() {
return Swiper(
onTap: (int index) {
Navigator.of(context)
.push(MaterialPageRoute(builder: (BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(" page"),
),
body: Container(),
);
}));
},
customLayoutOption: customLayoutOption,
fade: _fade,
index: _currentIndex,
onIndexChanged: (int index) {
setState(() {
_currentIndex = index;
print(_currentIndex);
});
},
curve: _curve,
scale: _scale,
itemWidth: 300.0,
controller: _controller,
layout: _layout,
outer: _outer,
itemHeight: 200.0,
viewportFraction: _viewportFraction,
autoplayDelay: _autoplayDely,
loop: _loop,
autoplay: _autoplay,
itemBuilder: _buildItem,
itemCount: _itemCount,
scrollDirection: _scrollDirection,
indicatorLayout: PageIndicatorLayout.COLOR,
autoplayDisableOnInteraction: _autoplayDisableOnInteraction,
pagination: SwiperPagination(
builder: const DotSwiperPaginationBuilder(
size: 20.0, activeSize: 20.0, space: 10.0)),
);
}
SwiperController _controller;
TextEditingController numberController = TextEditingController();
#override
Widget build(BuildContext context) {
return Column(children: <Widget>[
Container(
color: Colors.black87,
child: SizedBox(
height: 300.0, width: double.infinity, child: buildSwiper()),
),
Expanded(
child: ListView(
children: <Widget>[
Text("Index:$_currentIndex"),
Row(
children: <Widget>[
RaisedButton(
onPressed: () {
_controller.previous(animation: true);
},
child: Text("Prev"),
),
RaisedButton(
onPressed: () {
_controller.next(animation: true);
},
child: Text("Next"),
),
Expanded(
child: TextField(
controller: numberController,
)),
RaisedButton(
onPressed: () {
var text = numberController.text;
setState(() {
_currentIndex = int.parse(text);
});
},
child: Text("Update"),
),
],
),
FormWidget(
label: "layout",
child: FormSelect(
placeholder: "Select layout",
value: _layout,
values: [
SwiperLayout.DEFAULT,
SwiperLayout.STACK,
SwiperLayout.TINDER,
SwiperLayout.CUSTOM
],
valueChanged: (value) {
_layout = value;
setState(() {});
})),
FormWidget(
label: "scrollDirection",
child: Switch(
value: _scrollDirection == Axis.horizontal,
onChanged: (bool value) => setState(() => _scrollDirection =
value ? Axis.horizontal : Axis.vertical)),
),
FormWidget(
label: "autoplayDisableOnInteractio",
child: Switch(
value: _autoplayDisableOnInteraction,
onChanged: (bool value) =>
setState(() => _autoplayDisableOnInteraction = value)),
),
//Pannel Begin
FormWidget(
label: "loop",
child: Switch(
value: _loop,
onChanged: (bool value) => setState(() => _loop = value)),
),
FormWidget(
label: "outer",
child: Switch(
value: _outer,
onChanged: (bool value) => setState(() => _outer = value)),
),
//Pannel Begin
FormWidget(
label: "autoplay",
child: Switch(
value: _autoplay,
onChanged: (bool value) => setState(() => _autoplay = value)),
),
FormWidget(
label: "padding",
child: NumberPad(
number: _padding,
step: 5.0,
min: 0.0,
max: 30.0,
onChangeValue: (num value) {
_padding = value.toDouble();
setState(() {});
},
),
),
FormWidget(
label: "scale",
child: NumberPad(
number: _scale,
step: 0.1,
min: 0.0,
max: 1.0,
onChangeValue: (num value) {
_scale = value.toDouble();
setState(() {});
},
),
),
FormWidget(
label: "fade",
child: NumberPad(
number: _fade,
step: 0.1,
min: 0.0,
max: 1.0,
onChangeValue: (num value) {
_fade = value.toDouble();
setState(() {});
},
),
),
FormWidget(
label: "itemCount",
child: NumberPad(
number: _itemCount,
step: 1,
min: 0,
max: 100,
onChangeValue: (num value) {
_itemCount = value.toInt();
setState(() {});
},
),
),
FormWidget(
label: "radius",
child: NumberPad(
number: _radius,
step: 1.0,
min: 0.0,
max: 30.0,
onChangeValue: (num value) {
this._radius = value.toDouble();
setState(() {});
},
),
),
FormWidget(
label: "viewportFraction",
child: NumberPad(
number: _viewportFraction,
step: 0.1,
max: 1.0,
min: 0.5,
onChangeValue: (num value) {
_viewportFraction = value.toDouble();
setState(() {});
},
),
),
FormWidget(
label: "curve",
child: FormSelect(
placeholder: "Select curve",
value: _layout,
values: [
Curves.easeInOut,
Curves.ease,
Curves.bounceInOut,
Curves.bounceOut,
Curves.bounceIn,
Curves.fastOutSlowIn
],
valueChanged: (value) {
_curve = value;
setState(() {});
})),
],
))
]);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(child: ExampleCustom()),
],
),
),
);
}
}

Related

Unsupported operation: Nan or infinity toInt for Tween Animation

I have found a code that i tried to replicate. It has an app itself and it is working. However when i tried to write the code down it shows the problem Unsupported operation NaN or infinity toInt for a function named TweenAnimation. I am still trying to learn how to use tween animation so any pros have any idea on this problem?
below is the code for the animation
import 'package:flutter/material.dart';
class AnimatedFlipCounter extends StatelessWidget {
final int value;
final Duration duration;
final double size;
final Color color;
const AnimatedFlipCounter({
Key? key,
required this.value,
required this.duration,
this.size = 72,
this.color = Colors.black,
}) : super(key: key);
#override
Widget build(BuildContext context) {
List<int> digits = value == 0 ? [0] : [];
int v = value;
if (v < 0) {
v *= -1;
}
while (v > 0) {
digits.add(v);
v = v ~/ 10;
}
return Row(
mainAxisSize: MainAxisSize.min,
children: List.generate(digits.length, (int i) {
return _SingleDigitFlipCounter(
key: ValueKey(digits.length - i),
value: digits[digits.length - i - 1].toDouble(),
duration: duration,
height: size,
width: size / 1.8,
color: color,
);
}),
);
}
}
class _SingleDigitFlipCounter extends StatelessWidget {
final double value;
final Duration duration;
final double height;
final double width;
final Color color;
const _SingleDigitFlipCounter({
required Key key,
required this.value,
required this.duration,
required this.height,
required this.width,
required this.color,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return TweenAnimationBuilder(
tween: Tween(begin: value, end: value),
duration: duration,
builder: (context,double value, child) {
final whole = 1.0 ~/ value ;
final decimal = value - whole;
return SizedBox(
height: height,
width: width,
child: Stack(
fit: StackFit.expand,
children: <Widget>[
_buildSingleDigit(
digit: whole % 10,
offset: height * decimal,
opacity: 1.0 - decimal,
),
_buildSingleDigit(
digit: (whole + 1) % 10,
offset: height * decimal - height,
opacity: decimal,
),
],
),
);
},
);
}
Widget _buildSingleDigit({required int digit, required double offset, required double opacity}) {
return Positioned(
child: SizedBox(
width: width,
child: Opacity(
opacity: opacity,
child: Text(
"$digit",
style: TextStyle(
fontSize: height, color: color, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
),
bottom: offset,
);
}
below is the main page that calls this widget
import 'package:carousel_slider/carousel_slider.dart';
import 'package:daily5/helpers/constants_tasbih.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/material.dart';
import 'package:get_storage/get_storage.dart';
import 'package:vibration/vibration.dart';
import '../../helpers/animated_flip_counter.dart';
class Tasbih extends StatefulWidget {
const Tasbih({Key? key}) : super(key: key);
#override
_TasbihState createState() => _TasbihState();
}
class _TasbihState extends State<Tasbih> {
final PageController _controller =
PageController(viewportFraction: 0.1, initialPage: 5);
final int _numberOfCountsToCompleteRound = 33;
int _imageIndex = 1;
int _beadCounter = 0;
int _roundCounter = 0;
int _accumulatedCounter = 0;
bool _canVibrate = true;
bool _isDisposed = false;
final List<Color> _bgColour = [
Colors.teal.shade50,
Colors.lime.shade50,
Colors.lightBlue.shade50,
Colors.pink.shade50,
Colors.black12
];
final CarouselController _buttonCarouselController = CarouselController();
#override
void initState() {
super.initState();
_loadSettings();
}
#override
void dispose() {
_isDisposed = true;
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onTap: _clicked,
onVerticalDragStart: (_) => _clicked(),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Expanded(
flex: 2,
child: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
children: [
const SizedBox(width: 45),
IconButton(
tooltip: 'Change colour',
icon: const Icon(Icons.palette),
onPressed: () {
setState(() {
_imageIndex < 5
? _imageIndex++
: _imageIndex = 1;
});
}),
IconButton(
tooltip: 'Reset counter',
icon: const Icon(Icons.refresh),
onPressed: () {
confirmReset(context, _resetEverything);
}),
],
),
const Spacer(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
textDirection: TextDirection.ltr,
children: <Widget>[
_Counter(
counter: _roundCounter, counterName: 'Round'),
_Counter(counter: _beadCounter, counterName: 'Beads'),
],
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 32),
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Text('Accumulated'),
const SizedBox(width: 10),
AnimatedFlipCounter(
value: _accumulatedCounter,
duration: const Duration(milliseconds: 730),
size: 14),
],
),
),
CarouselSlider(
carouselController: _buttonCarouselController,
options: CarouselOptions(
height: 100.0,
enlargeCenterPage: true,
),
items: [1, 2, 3, 4].map((i) {
return Builder(
builder: (BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
margin: const EdgeInsets.symmetric(
horizontal: 5.0),
decoration: BoxDecoration(
color: _bgColour[_imageIndex - 1],
borderRadius: BorderRadius.circular(12)),
child: Image.asset('assets/images/zikr/$i.png'));
},
);
}).toList(),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
onPressed: () {
_buttonCarouselController.previousPage();
},
icon: const Icon(Icons.navigate_before)),
IconButton(
onPressed: () {
_buttonCarouselController.nextPage();
},
icon: const Icon(Icons.navigate_next)),
],
),
const Spacer()
],
),
)),
Expanded(
flex: 1,
child: PageView.builder(
reverse: true,
physics: const NeverScrollableScrollPhysics(),
controller: _controller,
scrollDirection: Axis.vertical,
itemBuilder: (_, __) {
return Image.asset(
'assets/images/beads/bead-$_imageIndex.png',
);
},
itemCount: null,
),
),
],
),
),
);
}
void _loadSettings() async {
bool? canVibrate = await Vibration.hasVibrator();
if (!_isDisposed) {
setState(() {
_canVibrate = canVibrate!;
_loadData();
});
}
}
void _loadData() {
if (!_isDisposed) {
setState(() {
_beadCounter = GetStorage().read(kBeadsCount) ?? 0;
_roundCounter = GetStorage().read(kRoundCount) ?? 0;
_accumulatedCounter =
_roundCounter * _numberOfCountsToCompleteRound + _beadCounter;
});
}
}
void _resetEverything() {
GetStorage().write(kBeadsCount, 0);
GetStorage().write(kRoundCount, 0);
_loadData();
}
void _clicked() {
if (!_isDisposed) {
setState(() {
_beadCounter++;
_accumulatedCounter++;
if (_beadCounter > _numberOfCountsToCompleteRound) {
_beadCounter = 1;
_roundCounter++;
if (_canVibrate) Vibration.vibrate(duration: 100, amplitude: 100);
}
});
}
GetStorage().write(kBeadsCount, _beadCounter);
GetStorage().write(kRoundCount, _roundCounter);
int nextPage = _controller.page!.round() + 1;
_controller.animateToPage(nextPage,
duration: const Duration(milliseconds: 200), curve: Curves.easeIn);
}
}
class _Counter extends StatelessWidget {
const _Counter(
{Key? key,
required this.counter,
this.tsCounter =
const TextStyle(fontSize: 50, fontWeight: FontWeight.bold),
required this.counterName,
this.tsCounterName = const TextStyle(
fontSize: 20,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w300)})
: super(key: key);
final int counter;
final TextStyle tsCounter;
final String counterName;
final TextStyle tsCounterName;
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
AnimatedFlipCounter(
duration: const Duration(milliseconds: 300),
value: counter,
),
Text(counterName, style: tsCounterName)
],
);
}
}
void confirmReset(BuildContext context, VoidCallback callback) {
const _confirmText = Text('Confirm', style: TextStyle(color: Colors.red));
const _cancelText = Text('Cancel');
const _dialogTitle = Text("Reset Counter?");
const _dialogContent = Text("This action can't be undone");
void _confirmResetAction() {
callback();
showSnackBar(
context: context,
label: 'Cleared',
icon: CupertinoIcons.check_mark_circled);
Navigator.of(context).pop();
}
showDialog(
context: context,
builder: (_) {
return kIsWeb
? AlertDialog(
title: _dialogTitle,
content: _dialogContent,
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: _cancelText,
),
TextButton(
onPressed: _confirmResetAction,
child: _confirmText,
),
],
)
: CupertinoAlertDialog(
title: _dialogTitle,
content: _dialogContent,
actions: [
CupertinoDialogAction(
child: _cancelText,
onPressed: () => Navigator.of(context).pop(),
),
CupertinoDialogAction(
child: _confirmText,
onPressed: _confirmResetAction,
),
],
);
},
);
}
void showSnackBar({required BuildContext context, required String label, required IconData icon}) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
behavior: SnackBarBehavior.floating,
content: Row(
children: [
Icon(
icon,
color: Colors.white60,
),
const SizedBox(width: 5),
Text(label)
],
),
),
);
}
Supposedly it should beads that can be counted down but the animation cant load.

FLUTTER : How to only rebuild the top page in stack flutter

I have an issue with rebuilding pages in the stack with Flutter
This is all my users and have added the search to the top appBar.
But it works with conditions to see if it is widgets there then get height of the widgets that is being fixed underneath the appBar...But that happens asynchronously.
So when firstLoad it works but when I call setState it then rebuilds all the pages in the stack and with that it looks like this
This is how it looks after a set state. The problem i saw is that the previous pages have an influence. I couldn't find a good viable solution to this. Will explain my architecture.
I have a page Layout that is a container wrapper for all my pages that has it's appBar styles and just sends through the children. But that is the page Layout wrapper that is being rebuild every time the a set States happen
HOW I GET MY WIDGET SIZE
HOW I IMPLEMENTED IT
It goes in the else with the other pages in the stack.. I tried putting it in the initState but it never goes inside because it is used in the other pages in the stack
I only need an implementation to rebuild the TOP page in the stack.
PAGE LAYOUT
// ignore_for_file: prefer_const_constructors
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart';
import 'package:flutterweb/constants.dart';
import 'package:flutterweb/controllers/channel_controller.dart';
import 'package:flutterweb/controllers/user_controller.dart';
import 'package:flutterweb/main.dart';
import 'package:flutterweb/models/channels_model.dart';
import 'package:flutterweb/utils/functions.dart';
import 'package:flutterweb/views/channels/func.dart';
import 'package:flutterweb/views/home/home.dart';
import 'package:flutterweb/views/menu/permissions/choose_assign_group.dart';
import 'package:flutterweb/widgets/builders/KNetworkFadeImage.dart';
import 'package:flutterweb/widgets/builders/kPopups.dart';
import 'package:flutterweb/widgets/drawerDara.dart';
import 'package:get/get.dart';
class CustomAppBar extends StatefulWidget {
final String title;
final List<Map<String, dynamic>>? topTabs;
final TabController? topTabController;
final List<Widget>? children;
final List<Widget>? childrenFixed;
final Function? leftActionFunction;
final Icon? leftActionIcon;
final Drawer? drawer;
final Function? logOutPressed;
final bool showOptionsMenu;
final Widget? optionMenu;
final Widget? bottomNavigationBar;
final String? backGroundImage;
final ScrollController? scrollController;
CustomAppBar({
required this.title,
this.topTabs,
this.topTabController,
this.leftActionFunction,
this.leftActionIcon,
this.children,
this.childrenFixed,
this.drawer,
this.logOutPressed,
this.showOptionsMenu = false,
this.optionMenu,
this.bottomNavigationBar,
this.backGroundImage,
this.scrollController,
});
#override
_CustomAppBarState createState() => _CustomAppBarState();
}
double app_content_height = 0;
double fixedWidgetSize = 0;
String prevTitle = "";
class _CustomAppBarState extends State<CustomAppBar>
with SingleTickerProviderStateMixin {
final GlobalKey<ScaffoldState> scaffoldkey = GlobalKey<ScaffoldState>();
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
}
_toggleAnimation() {
scaffoldkey.currentState!.openDrawer();
}
double _getAppBarSize() {
double fixedHeightInclude = fixedWidgetSize;
if (widget.topTabs != null) {
fixedHeightInclude += 100;
} else if (widget.title == "") {
fixedHeightInclude += 0;
} else {
fixedHeightInclude += 60;
}
return fixedHeightInclude;
}
#override
Widget build(BuildContext context) {
// if (widget.title != global_title) return SizedBox();
List<Widget> arr = [];
Widget arrView = SizedBox();
double statusBar = 0;
double _width = MediaQuery.of(context).size.width;
Widget? fixedChild = SizedBox();
if ((widget.childrenFixed?.length ?? 0) > 1) {
fixedChild = WidgetSize(
child: Column(children: widget.childrenFixed!),
onChange: (Size size) {
fixedWidgetSize = 0;
setState(() {
fixedWidgetSize = size.height;
});
kPrint("fixedWidgetSize ${size.height}");
},
);
} else {
fixedWidgetSize = 0;
}
// Widget? fixedChild = (widget.childrenFixed?.length ?? 0) > 1
// ? WidgetSize(
// child: Column(children: widget.childrenFixed!),
// onChange: (Size size) {
// fixedWidgetSize = 0;
// setState(() {
// fixedWidgetSize = size.height;
// });
// kPrint("fixedWidgetSize ${size.height}");
// },
// )
// : SizedBox();
app_content_height =
MediaQuery.of(context).size.height - _getAppBarSize() - statusBar;
if (widget.title != "") {
arr.add(
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 2,
child: widget.showOptionsMenu == true
? IconButton(
icon: const Icon(Icons.menu, color: Colors.white),
onPressed: () => _toggleAnimation(),
)
: IconButton(
icon: widget.leftActionIcon ??
const Icon(Icons.arrow_back, color: Colors.white),
onPressed: () {
if (widget.leftActionFunction != null) {
widget.leftActionFunction!();
} else {
if (Navigator.canPop(context)) {
Get.back();
}
}
},
),
),
Expanded(flex: 2, child: SizedBox()),
Expanded(
flex: 10,
child: Center(
child: Text(
widget.title,
style: const TextStyle(color: Colors.white, fontSize: 24.0),
),
),
),
Expanded(
flex: 4,
child: widget.logOutPressed != null
? IconButton(
icon: const Icon(Icons.power_settings_new_outlined,
color: Colors.white),
onPressed: () {
widget.logOutPressed!();
},
)
: widget.optionMenu ?? Container(),
),
],
),
);
}
if (widget.topTabs != null) {
List<Widget> tempTopBar = [];
List<Widget> tempTopView = [];
for (var i = 0; i < widget.topTabs!.length; i++) {
String key = widget.topTabs![i].keys
.toString()
.replaceAll("(", "")
.replaceAll(")", "");
Widget value = widget.topTabs![i][key];
tempTopBar.add(Tab(text: key));
tempTopView.add(SingleChildScrollView(child: value));
}
arr.add(
Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Center(
child: Container(
height: 30,
child: DefaultTabController(
length: widget.topTabs!.length,
child: TabBar(
labelPadding: widget.topTabs!.length == 2
? const EdgeInsets.symmetric(horizontal: 40.0)
: const EdgeInsets.symmetric(horizontal: 16.0),
controller: widget.topTabController,
indicatorSize: TabBarIndicatorSize.tab,
indicator: CircleTabIndicator(color: Colors.white, radius: 4),
isScrollable: true,
labelColor: Colors.white,
tabs: tempTopBar,
),
),
),
),
),
);
// arr.add(child);
arrView = Container(
width: _width,
height: app_content_height,
child: TabBarView(
controller: widget.topTabController,
children: tempTopView,
),
);
}
if (widget.children != null) {
arrView = Container(
width: _width,
height: app_content_height,
child: ListView(
// controller: widget.scrollController ?? ScrollController(),
children: widget.children!,
),
);
}
_getStatus() {
if (statusBar > 0) {
Color color = AppColors.kBlue;
return Container(
height: Get.height * 0.03,
width: Get.width,
color: color,
child: const Center(
child: Text(
"",
style: const TextStyle(color: Colors.black),
),
),
);
} else {
return const SizedBox();
}
}
return SafeArea(
child: Material(
child: Stack(
children: [
Scaffold(
resizeToAvoidBottomInset:
true, //That the keyboard shows correctly
extendBodyBehindAppBar: true,
key: scaffoldkey,
appBar: PreferredSize(
preferredSize: Size.fromHeight(
_getAppBarSize()), // here the desired height
child: Container(
decoration: kAppBarBoxDecorations,
child: Column(
children: [
Column(
children: arr,
),
fixedChild,
],
),
),
),
drawer: Drawer(
child: ListView(
children: <Widget>[
UserAccountsDrawerHeader(
accountName: InkWell(
onTap: () {
Channels element =
ChannelController.to.gSelectedChannel.value;
getChannelRoles(element);
},
child: Text(
"${ChannelController.to.gSelectedChannel.value.rolDesc} >",
),
),
accountEmail: Text(
UserController.to.gUserModel.value.email.toString()),
currentAccountPicture: GestureDetector(
child: const CircleAvatar(
backgroundImage: NetworkImage(
"https://images.pexels.com/photos/220453/pexels-photo-220453.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"),
),
onTap: () => print("Current User")),
decoration: const BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill,
image: NetworkImage(
"${URLS.keyBaseUrl}/assets/images/background/background7.jpg")),
),
),
ListTile(
title: const Text("Home"),
trailing: const Icon(Icons.home),
onTap: () =>
Get.toNamed(Home.router, preventDuplicates: false),
),
ListTile(
title: const Text("Menu Permissions"),
trailing: const Icon(Icons.home),
onTap: () => Get.toNamed(ChooseAssignGroup.router,
preventDuplicates: false),
),
const Divider(
thickness: 1.0,
),
drawerData(),
const Divider(
thickness: 1.0,
),
ListTile(
title: const Text("Close"),
trailing: const Icon(Icons.cancel),
onTap: () => Navigator.of(context).pop(),
),
ListTile(
title: const Text("Log Out"),
trailing: const Icon(Icons.logout),
onTap: () => UserController.to.logOutUser(),
),
],
),
),
body: Container(
decoration: widget.backGroundImage != null
? BoxDecoration(
color: Colors.black.withOpacity(0.9),
image: DecorationImage(
fit: BoxFit.cover,
colorFilter: ColorFilter.mode(
Colors.black.withOpacity(0.2), BlendMode.dstATop),
image: NetworkImage(widget.backGroundImage!),
),
)
: BoxDecoration(color: Colors.grey.shade400),
child: Center(
child: Container(
constraints: BoxConstraints(maxWidth: 800),
padding: EdgeInsets.only(
left: 15.0, right: 15.0, top: _getAppBarSize()),
child: MediaQuery.removePadding(
context: context,
removeTop: true,
child: arrView,
),
),
),
),
bottomNavigationBar: widget.bottomNavigationBar,
),
],
),
),
);
}
}
class CircleTabIndicator extends Decoration {
final BoxPainter _painter;
CircleTabIndicator({required Color color, required double radius})
: _painter = _CirclePainter(color, radius);
#override
BoxPainter createBoxPainter([onChanged()?]) => _painter;
}
class _CirclePainter extends BoxPainter {
final Paint _paint;
final double radius;
_CirclePainter(Color color, this.radius)
: _paint = Paint()
..color = color
..isAntiAlias = true;
#override
void paint(Canvas canvas, Offset offset, ImageConfiguration cfg) {
final Offset circleOffset =
offset + Offset(cfg.size!.width / 2, cfg.size!.height - radius);
canvas.drawCircle(circleOffset, radius, _paint);
}
}
class WidgetSize extends StatefulWidget {
final Widget child;
final Function onChange;
const WidgetSize({
required this.onChange,
required this.child,
});
#override
_WidgetSizeState createState() => _WidgetSizeState();
}
class _WidgetSizeState extends State<WidgetSize> {
#override
Widget build(BuildContext context) {
SchedulerBinding.instance.addPostFrameCallback(postFrameCallback);
return Container(
key: widgetKey,
child: widget.child,
);
}
var widgetKey = GlobalKey();
var oldSize;
void postFrameCallback(_) {
var context = widgetKey.currentContext;
if (context == null) return;
var newSize = context.size;
if (oldSize == newSize) return;
oldSize = newSize;
widget.onChange(newSize);
}
}
ALL VERIFIED USERS
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutterweb/controllers/channel_controller.dart';
import 'package:flutterweb/controllers/user_controller.dart';
import 'package:flutterweb/main.dart';
import 'package:flutterweb/models/user_model.dart';
import 'package:flutterweb/thirdParty/googleSignin.dart';
import 'package:flutterweb/utils/functions.dart';
import 'package:flutterweb/views/menu/permissions/menu_assign.dart';
import 'package:flutterweb/widgets/builders/kPopups.dart';
import 'package:flutterweb/widgets/buttons/KIconOnlyButton.dart';
import 'package:flutterweb/widgets/builders/KNetworkFadeImage.dart';
import 'package:flutterweb/widgets/builders/customAppBar.dart';
import 'package:flutterweb/widgets/buttons/KButton.dart';
import 'package:flutterweb/constants.dart';
import 'package:flutterweb/widgets/cards/KStudentInfoCard.dart';
import 'package:flutterweb/widgets/cards/kStudentCard.dart';
import 'package:flutterweb/widgets/input/KInputBar.dart';
import 'package:flutterweb/widgets/input/KTextField.dart';
import 'package:flutterweb/widgets/static/kLabel.dart';
import 'package:flutterweb/widgets/text/kInfo.dart';
import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
class AllVerifiedUsers extends StatefulWidget {
static const String router = "/allVerifiedUsers";
AllVerifiedUsers({Key? key}) : super(key: key);
#override
_MyPageState createState() => _MyPageState();
}
// The controller for the ListView
late ScrollController _controller;
class _MyPageState extends State<AllVerifiedUsers> {
// The controller for the ListView
late ScrollController _controllerTest;
int _page = 1;
final int _limit = 20;
bool _hasNextPage = true;
bool _isFirstLoadRunning = false;
bool _isLoadMoreRunning = false;
List<UserModel> _posts = [];
String searchVal = "";
void _firstLoad() async {
setState(() {
_isFirstLoadRunning = true;
});
try {
List<UserModel> lUserMode = await ChannelController.to
.fetchUsersChannels(_limit, _page, searchVal);
setState(() {
_posts = lUserMode;
});
} catch (err) {
kPrint('Something went wrong');
}
setState(() {
_isFirstLoadRunning = false;
});
}
void _loadMore() async {
if (_isFirstLoadRunning == false &&
_isLoadMoreRunning == false &&
_controller.position.extentAfter < 300) {
setState(() {
_isLoadMoreRunning = true; // Display a progress indicator at the bottom
});
_page += 1; // Increase _page by 1
try {
List<UserModel> lUserMode = await ChannelController.to
.fetchUsersChannels(_limit, _page, searchVal);
if (lUserMode.isNotEmpty) {
setState(() {
_hasNextPage = true;
_posts.addAll(lUserMode);
});
} else {
// This means there is no more data
// and therefore, we will not send another GET request
setState(() {
_hasNextPage = false;
});
}
} catch (err) {
print('Something went wrong!');
}
setState(() {
_isLoadMoreRunning = false;
});
}
}
#override
void initState() {
super.initState();
_firstLoad();
_controller = ScrollController()..addListener(_loadMore);
_controllerTest = ScrollController()
..addListener(() => {kPrint("CustomView Scroll")});
}
#override
void dispose() {
super.dispose();
_controller.removeListener(_loadMore);
}
#override
Widget build(BuildContext context) {
global_title = "All Verified Users";
return CustomAppBar(
title: "All Verified Users",
scrollController: _controllerTest,
childrenFixed: [
kAddSpace(2),
CustomInputBar(
inverse: true,
title: "Search",
onChanged: (String value) {
if (value == "") {
_firstLoad();
return;
}
setState(() {
searchVal = value;
_posts = [];
});
_loadMore();
},
),
],
children: [
kAddSpace(2),
KLabel(
label: "Choose Verified User",
),
kAddSpace(2),
_isFirstLoadRunning
? const Center(
child: CircularProgressIndicator(),
)
: Column(
children: [
SizedBox(
height: app_content_height,
// width: Get.width,
child: ListView.builder(
shrinkWrap: true,
controller: _controller,
itemCount: _posts.length,
itemBuilder: (_, index) {
UserModel item = _posts[index];
return KStudentCard(
imgUrl: "",
onPressed: () {
ChannelController.to.gSelectedMenuUserModel.value =
item;
Get.toNamed(MenuAssign.router);
},
name: "${item.name} ${item.surname}",
);
},
),
),
// when the _loadMore function is running
if (_isLoadMoreRunning == true)
const Padding(
padding: EdgeInsets.only(top: 10, bottom: 40),
child: Center(
child: CircularProgressIndicator(),
),
),
// When nothing else to load
if (_hasNextPage == false)
Container(
padding: const EdgeInsets.only(top: 30, bottom: 40),
color: Colors.amber,
child: const Center(
child: Text('You have fetched all of the content'),
),
),
],
),
kAddSpace(2),
],
);
}
}
Thank you
As I understand it, the idea is a fixed TextArea and a scrollable List beneath. A solution that works without computing any height would be:
final items = List<String>.generate(1000, (i) => 'Item $i');
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: [
//
// TEXTBOX
//
Container(
color: Colors.red,
child: Padding(
padding: const EdgeInsets.all(16),
child: TextFormField(
// controller: controller,
))),
const SizedBox(height: 16),
//
// LIST
//
Expanded(
child: ListView.builder(
shrinkWrap: true, // IMPORTANT
itemCount: items.length,
itemBuilder: (context, index) {
return Text(items[index]);
})),
]),
);
}

tcard is not resetting, getting null in tcardController.state Flutter

I am tcard pkg in my project. i want reset the card in every 5 seconds automatically the length of the list is changing but the UI is not resetting, getting null in tcardController.state
Is there any other pkg, so we can achieve same functionality of this tcard pkg.
Refer to below code:-
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:tcard/tcard.dart';
List<Color> colors = [
Colors.blue,
Colors.yellow,
Colors.red,
Colors.orange,
Colors.pink,
Colors.amber,
Colors.cyan,
Colors.purple,
Colors.brown,
Colors.teal,
];
class TCardPage extends StatefulWidget {
const TCardPage({Key? key}) : super(key: key);
#override
_TCardPageState createState() => _TCardPageState();
}
class _TCardPageState extends State<TCardPage> {
final TCardController _controller = TCardController();
int _index = 0;
Timer? timer;
bool changeColor = false;
#override
void initState() {
super.initState();
timer = Timer.periodic(
const Duration(seconds: 5), (Timer t) => sequenceApiCall());
print(_controller.state.toString());
// _controller.reset;
}
void sequenceApiCall() {
changeColor = !changeColor;
Future.delayed(const Duration(seconds: 10), () {
print('sequenceApiCall');
if (changeColor) {
print('changeColor');
colors.removeAt(0);
print('color count = ${colors.length}'); //9
} else {
colors.insert(0, Colors.black);
print('black');
print('color count = ${colors.length}'); //10
}
print(_controller.state.toString());
_controller.reset();
setState(() {});
});
}
#override
void dispose() {
super.dispose();
timer?.cancel();
_controller.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: <Widget>[
const SizedBox(height: 200),
TCard(
cards: cardsColor,
controller: _controller,
onForward: (index, info) {
_index = index;
print(info.direction);
setState(() {});
},
onBack: (index, info) {
_index = index;
setState(() {});
},
onEnd: () {
print('end');
},
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
OutlineButton(
onPressed: () {
_controller.back();
},
child: const Text('Back'),
),
OutlineButton(
onPressed: () {
_controller.forward();
},
child: const Text('Forward'),
),
OutlineButton(
onPressed: () {
_controller.reset();
},
child: const Text('Reset'),
),
],
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Text(_index.toString()),
),
);
}
List<Widget> cardsColor = List.generate(
colors.length,
(int index) {
return Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: colors[index],
),
child: Text(
'${index + 1}',
style: const TextStyle(fontSize: 100.0, color: Colors.white),
),
);
},
);
}
Thanks in advance.!!!

flutter:: RangeError (index): Invalid value: Not in inclusive range 0..14: 15

I made a function to delete saved recording files.
The delete function works fine.
However, if it is deleted, an error
'RangeError (index): Invalid value: Not in inclusive range 0..14: 15'
will occur and it will look like the picture above.
How can I solve this?
This is the delete function.
_delete() {
widget.file[widget.index].delete(recursive: true);
setState(() {
position = new Duration();
widget.file.removeAt(widget.index);
});
}
This is my listview code.
class _AudioViewerState extends State<AudioViewer> {
var audioPath;
var directory;
List file = [];
#override
void initState() {
super.initState();
getFiles();
}
void getFiles() async {
directory = (await getExternalStorageDirectory())!.path;
setState(() {
file = Directory("$directory").listSync();
});
}
#override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(
elevation: 0,
title: Text(
"Audio List",
),
),
body: Container(
child: CustomPaint(
child: ListView.builder(
reverse: true,
itemCount: file.length,
itemBuilder: (BuildContext context, int index) {
return AudioViewerCustomTile(
text: file[index].path.split('/').last,
path: file[index].path.toString(),
height: height,
width: width,
file: file,
index: index,
);
},
),
),
),
);
}
}
This is the file with the delete function.
class DialogBuilder extends StatefulWidget {
final String path;
final int index;
final List file;
DialogBuilder({required this.path,required this.index,required this.file});
#override
_DialogBuilderState createState() => _DialogBuilderState();
}
class _DialogBuilderState extends State<DialogBuilder> {
late AudioPlayer audioPlayer;
bool _isplaying = false;
var _icon = Icons.play_arrow;
var _deleteicon = Icons.delete;
Color _color = Colors.deepOrangeAccent;
Duration position = Duration();
Duration duration = Duration(seconds: 1);
#override
Widget build(BuildContext context) {
return Container(
height: 200,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
),
child: Column(
children: <Widget>[
Container(
child: Row(
children: <Widget>[
Container(
child: IconButton(
iconSize: 100,
onPressed: () {
if (!_isplaying) {
_play();
} else {
_stop();
}
},
icon: Icon(_icon),
color: _color,
),
),
Container(
child: IconButton(
iconSize: 50,
onPressed: () {
_delete();
},
icon: Icon(_deleteicon),
),
),
]
)
),
Padding(
padding: const EdgeInsets.all(8.0),
child: LinearProgressIndicator(
backgroundColor: Colors.grey[300],
valueColor: AlwaysStoppedAnimation(Colors.deepOrangeAccent),
value: (position.inMilliseconds / duration.inMilliseconds) * 1.0,
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
_getDuration(position),
style: TextStyle(color: Colors.black),
),
Text(
_getDuration(duration),
style: TextStyle(color: Colors.black),
)
],
),
)
],
),
);
}
String _getDuration(Duration duration) {
String twoDigits(int n) {
if (n >= 10) return "$n";
return "0$n";
}
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return "${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds";
}
_play() {
audioPlayer.resume();
setState(() {
_isplaying = true;
_icon = Icons.pause;
_color = Colors.blueGrey;
});
}
_stop() {
audioPlayer.release();
setState(() {
position = new Duration();
_isplaying = false;
_icon = Icons.play_arrow;
_color = Colors.deepOrangeAccent;
});
}
_delete() {
widget.file[widget.index].delete(recursive: true);
setState(() {
position = new Duration();
widget.file.removeAt(widget.index);
});
}
_stateListener(PlayerState state) {
print(" In _stateListener the state of AudioPlayer :- " +
state.toString() +
"\n");
if (state == PlayerState.COMPLETED) {
Navigator.pop(context);
_stop();
}
}
The List file = []; is an empty list, so when you try to do itemCount = file.length, it displays an error, try giving the List file; a value instead of a an empty list and im sure it will work

How can i get value from child to parent on button click when button is in parent?

I have been using Stepper view by flutter.And I am having an issue on getting value from child to parent on button click as the button is in parent widget.
Here is my Parent class and my child class.
Parent Class
This is my parent class which has a Stepper view with next and back button.I want to get value from my child class to parent class when next button is clicked.
class DeliveryTimeline extends StatefulWidget {
DeliveryTimeline({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<DeliveryTimeline> {
int _currentStep = 0;
String shippingtype;
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
centerTitle: true,
iconTheme: new IconThemeData(color: Colors.black),
elevation: 0,
title: Text(
"Checkout",
style: TextStyle(color: Colors.black),
),
),
body: Stepper(
type: StepperType.horizontal,
steps: _mySteps(),
currentStep: this._currentStep,
onStepTapped: (step) {
setState(() {
this._currentStep = step;
});
},
onStepContinue: () {
setState(() {
if (this._currentStep == 0) {
this._currentStep = this._currentStep + 1;
**//need to get value here on first next click**
} else if (this._currentStep == 1) {
this._currentStep = this._currentStep + 1;
} else {
print('Completed, check fields.');
}
});
},
onStepCancel: () {
setState(() {
if (this._currentStep > 0) {
this._currentStep = this._currentStep - 1;
} else {
this._currentStep = 0;
}
});
},
controlsBuilder: (BuildContext context,
{VoidCallback onStepContinue,
VoidCallback onStepCancel,
Function onShippingNextClick}) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
OutlineButton(
child: new Text("Back"),
onPressed: onStepCancel,
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(4.0))),
MaterialButton(
child: Text("Next"),
color: AppColors.primarycolor,
textColor: Colors.white,
onPressed: onStepContinue,
),
],
);
}));
}
List<Step> _mySteps() {
List<Step> _steps = [
Step(
title: Text('Delivery'),
content: Center(
child: Container(
height: MediaQuery.of(context).size.height / 1.5,
child: Delivery(onShipingTypeClicked: (shippingtype){
shippingtype = shippingtype;
print("myvalue${shippingtype}");
},),
),
),
isActive: _currentStep >= 0,
),
Step(
title: Text('Address'),
content: Address(),
isActive: _currentStep >= 1,
),
Step(
title: Text('Payment'),
content: Payment(),
isActive: _currentStep >= 2,
)
];
return _steps;
}
}
Child Class
This is my child class i have a Listview which act like a radio button.I want the selected item and its value to the parent class when button is clicked..
class Delivery extends StatefulWidget {
final ValueChanged<String> onShipingTypeClicked;
Delivery({this.onShipingTypeClicked});
#override
_DeliveryState createState() => _DeliveryState();
}
class _DeliveryState extends State<Delivery> {
List<RadioModel> sampleData = new List<RadioModel>();
#override
void initState() {
// TODO: implement initState
super.initState();
sampleData.add(new RadioModel(false, 'A', 0xffe6194B, "Standard Delivery",
"Order will be delivered between 3 - 5 business days", 1));
sampleData.add(new RadioModel(
true,
'A',
0xffe6194B,
"Next Day Delivery",
"Place your order before 6pm and your items will be delivered the next day",
2));
sampleData.add(new RadioModel(
false,
'A',
0xffe6194B,
"Nominated Delivery",
"Pick a particular date from the calendar and order will be delivered on selected date",
3));
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new ListView.builder(
itemCount: sampleData.length,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return new InkWell(
onTap: () {
setState(() {
sampleData.forEach((element) => element.isSelected = false);
sampleData[index].isSelected = true;
widget.onShipingTypeClicked(sampleData[index].buttonText);
});
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextSmallTitleSize(
title: sampleData[index].title,
),
Padding(
padding: const EdgeInsets.only(bottom: 20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Flexible(
child: TextSmallDimText(sampleData[index].label),
),
RadioItem(sampleData[index]),
],
),
)
],
));
},
),
);
}
}
class RadioItem extends StatelessWidget {
final RadioModel _item;
RadioItem(this._item);
#override
Widget build(BuildContext context) {
return new Container(
margin: new EdgeInsets.all(15.0),
child: new Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
new Container(
height: 25.0,
width: 25.0,
alignment: Alignment.center,
child: Container(
height: 15.0,
width: 15.0,
decoration: new BoxDecoration(
color: AppColors.primarycolor,
borderRadius:
const BorderRadius.all(const Radius.circular(15)),
)),
decoration: new BoxDecoration(
color: Colors.transparent,
border: new Border.all(
width: 3.0,
color: _item.isSelected
? AppColors.primarycolor
: Colors.transparent),
borderRadius: const BorderRadius.all(const Radius.circular(25)),
),
),
new Container(margin: new EdgeInsets.only(left: 10.0))
],
),
);
}
}
class RadioModel {
bool isSelected;
final String buttonText;
final int colorCode;
final String title, label;
final int buttonid;
RadioModel(this.isSelected, this.buttonText, this.colorCode, this.title,
this.label, this.buttonid);
}
You can copy paste run full code below
You can use GlobalKey to get deliveryState of Delivery, and use deliveryState to get attribute of Delivery, attribute here is RadioModel selected
Step 1: Use GlobalKey _key = GlobalKey();
class _MyHomePageState extends State<DeliveryTimeline> {
...
GlobalKey _key = GlobalKey();
Step 2: Use deliveryState to get seleted item
onStepContinue: () {
setState(() {
if (this._currentStep == 0) {
this._currentStep = this._currentStep + 1;
final _DeliveryState deliveryState =
_key.currentState;
print("hi ${deliveryState.selected.title} ${deliveryState.selected.label} ");
Step 3: Delivery need key
child: Delivery(
key: _key,
onShipingTypeClicked: (shippingtype) {
...
Delivery({Key key, this.onShipingTypeClicked}) : super(key:key);
Step 4: Set variable selected
RadioModel selected = null;
...
return InkWell(
onTap: () {
setState(() {
...
selected = sampleData[index];
working demo
output of working demo
I/flutter ( 6246): hi Standard Delivery Order will be delivered between 3 - 5 business days
full code
import 'package:flutter/material.dart';
class DeliveryTimeline extends StatefulWidget {
DeliveryTimeline({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<DeliveryTimeline> {
int _currentStep = 0;
String shippingtype;
GlobalKey _key = GlobalKey();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
centerTitle: true,
iconTheme: IconThemeData(color: Colors.black),
elevation: 0,
title: Text(
"Checkout",
style: TextStyle(color: Colors.black),
),
),
body: Stepper(
type: StepperType.horizontal,
steps: _mySteps(),
currentStep: this._currentStep,
onStepTapped: (step) {
setState(() {
this._currentStep = step;
});
},
onStepContinue: () {
setState(() {
if (this._currentStep == 0) {
this._currentStep = this._currentStep + 1;
final _DeliveryState deliveryState =
_key.currentState;
print("hi ${deliveryState.selected.title} ${deliveryState.selected.label} ");
} else if (this._currentStep == 1) {
this._currentStep = this._currentStep + 1;
} else {
print('Completed, check fields.');
}
});
},
onStepCancel: () {
setState(() {
if (this._currentStep > 0) {
this._currentStep = this._currentStep - 1;
} else {
this._currentStep = 0;
}
});
},
controlsBuilder: (BuildContext context,
{VoidCallback onStepContinue,
VoidCallback onStepCancel,
Function onShippingNextClick}) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
OutlineButton(
child: Text("Back"),
onPressed: onStepCancel,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4.0))),
MaterialButton(
child: Text("Next"),
color: Colors.blue,
textColor: Colors.white,
onPressed: onStepContinue,
),
],
);
}));
}
List<Step> _mySteps() {
List<Step> _steps = [
Step(
title: Text('Delivery'),
content: Center(
child: Container(
height: MediaQuery.of(context).size.height / 1.5,
child: Delivery(
key: _key,
onShipingTypeClicked: (shippingtype) {
shippingtype = shippingtype;
print("myvalue${shippingtype}");
},
),
),
),
isActive: _currentStep >= 0,
),
Step(
title: Text('Address'),
content: Text("Address()"),
isActive: _currentStep >= 1,
),
Step(
title: Text('Payment'),
content: Text("Payment()"),
isActive: _currentStep >= 2,
)
];
return _steps;
}
}
class Delivery extends StatefulWidget {
final ValueChanged<String> onShipingTypeClicked;
Delivery({Key key, this.onShipingTypeClicked}) : super(key:key);
#override
_DeliveryState createState() => _DeliveryState();
}
class _DeliveryState extends State<Delivery> {
List<RadioModel> sampleData = List<RadioModel>();
#override
void initState() {
// TODO: implement initState
super.initState();
sampleData.add(RadioModel(false, 'A', 0xffe6194B, "Standard Delivery",
"Order will be delivered between 3 - 5 business days", 1));
sampleData.add(RadioModel(
true,
'A',
0xffe6194B,
"Next Day Delivery",
"Place your order before 6pm and your items will be delivered the next day",
2));
sampleData.add(RadioModel(
false,
'A',
0xffe6194B,
"Nominated Delivery",
"Pick a particular date from the calendar and order will be delivered on selected date",
3));
}
RadioModel selected = null;
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: sampleData.length,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
setState(() {
sampleData.forEach((element) => element.isSelected = false);
sampleData[index].isSelected = true;
selected = sampleData[index];
widget.onShipingTypeClicked(sampleData[index].buttonText);
});
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
ListTile(
title: Text(sampleData[index].title),
),
Padding(
padding: const EdgeInsets.only(bottom: 20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Flexible(
child: Text(sampleData[index].label),
),
RadioItem(sampleData[index]),
],
),
)
],
));
},
),
);
}
}
class RadioItem extends StatelessWidget {
final RadioModel _item;
RadioItem(this._item);
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(15.0),
child: Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
height: 25.0,
width: 25.0,
alignment: Alignment.center,
child: Container(
height: 15.0,
width: 15.0,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius:
const BorderRadius.all(const Radius.circular(15)),
)),
decoration: BoxDecoration(
color: Colors.transparent,
border: Border.all(
width: 3.0,
color: _item.isSelected ? Colors.blue : Colors.transparent),
borderRadius: const BorderRadius.all(const Radius.circular(25)),
),
),
Container(margin: EdgeInsets.only(left: 10.0))
],
),
);
}
}
class RadioModel {
bool isSelected;
final String buttonText;
final int colorCode;
final String title, label;
final int buttonid;
RadioModel(this.isSelected, this.buttonText, this.colorCode, this.title,
this.label, this.buttonid);
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: DeliveryTimeline(),
);
}
}