How to change opacity of text and angle of icon while using slider button in flutter - flutter

I want that as I move my slider button towards right, the opacity of text decreases and arrow icon rotates exactly oppposite, i.e. it strts rotating and at last last it should point backwards. I want to use opacity and Transform.rotate widgets, but how do I keep updating the value of dx ,so I can divide it with total width of container and use the fraction for calculation.
If there is another way, please do tell me.
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:passenger_flutter_app/utils/colors.dart';
import 'package:passenger_flutter_app/widgets/custom_sliding_button.dart';
class CommonSwipeButton extends StatelessWidget {
final String? buttonText1;
final String buttonText2;
final VoidCallback buttonCallBack2;
final bool isInfo;
final VoidCallback? buttonCallBack1;
final Widget itemWidget;
CommonSwipeButton(
{this.buttonCallBack1,
required this.buttonCallBack2,
this.isInfo = false,
this.buttonText1,
required this.buttonText2,
required this.itemWidget});
#override
Widget build(BuildContext context) {
return Container(
child: Column(
//crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Padding(padding: const EdgeInsets.only(left: 16.0, right: 16.0, bottom: 16.0, top: 16), child: itemWidget),
Padding(
padding:
const EdgeInsets.only(bottom: 16.0, left: 16.0, right: 16.0),
child: Align(
alignment: Alignment.center,
child: SizedBox(
width: MediaQuery.of(context).size.width,
height: 44,
child: CustomSlidingButton(
//text: buttonText2,
),
),
),
)
],
),
);
}
}
/*
class SwipeButton extends StatefulWidget {
final ValueChanged<double>? valueChanged;
final String? text;
final Function? callBack;
SwipeButton({this.valueChanged, this.text, this.callBack});
#override
SwipeButtonState createState() {
return new SwipeButtonState();
}
}
class SwipeButtonState extends State<SwipeButton> {
ValueNotifier<double> valueListener = ValueNotifier(.0);
GlobalKey swipeKey = GlobalKey();
ValueNotifier<double> x=ValueNotifier<double>(0);
ValueNotifier<bool> isVisible = ValueNotifier<bool>(true);
#override
void initState() {
valueListener.addListener(notifyParent);
super.initState();
}
void notifyParent() {
if (widget.valueChanged != null) {
widget.valueChanged!(valueListener.value);
}
}
void getPos(double totalSize) {
RenderBox box = swipeKey.currentContext?.findRenderObject() as RenderBox;
Offset position = box.localToGlobal(Offset.zero); //this is global position
x.value = position.dx;
print(x);
if(x.value>355) {
print("Reached");
isVisible.value=false;
}
}
#override
Widget build(BuildContext context) {
return Container(
color: colorPrimary,
height: 40.0,
padding: EdgeInsets.symmetric(horizontal: 10.0),
child: Stack(
children: [
Center(
child: Padding(
padding: const EdgeInsets.only(left: 10.0),
child: Text(
"${widget.text}",
style: TextStyle(
color: Colors.white,
fontSize: 17,
),
),
),
),
Builder(
builder: (context) {
final handle = GestureDetector(
onHorizontalDragUpdate: (details) {
valueListener.value = (valueListener.value +
details.delta.dx / context.size!.width)
.clamp(.0, 1.0);
getPos(context.size!.width-5);
print(context.size?.width);
},
child: ValueListenableBuilder(
valueListenable: isVisible,
builder: (BuildContext context, bool val, Widget? child) {
return Container(
key: swipeKey,
height: 25.0,
width: 25.0,
color: val ? Colors.white : colorPrimary,
child: Center(
child: ValueListenableBuilder(
valueListenable: x,
builder: (BuildContext context, double d, Widget? child) {
return Transform.rotate(
angle: -pi*(d/350),
child: Icon(
Icons.arrow_forward,
color: Colors.orange,
size: 12,
),
);
},
),
),
);
},
),
);
return AnimatedBuilder(
animation: valueListener,
builder: (context, child) {
return Align(
alignment: Alignment(valueListener.value * 2 - 1, 0),
child: child,
);
},
child: handle,
);
},
),
],
),
);
}
}*/

You can use Slider widget from Flutter framework and update a local variable in the onChange function:
Slider(
value: _currentSliderValue,
max: 100, //or any max value you need
onChanged: (double value) {
setState(() {
_value = value;
});
},
);
And the _value variable you will use in Opacity and Transform widgets.

Related

Flutter replace widget with SlideTransition

I want to slide out my first widget from right and slide in second from left of screen.
I'm trying to use AnimatedSwitcher with SlideTransition
my current code bug is that first widget doesn't slide out and just vanishes
here is my complete code snippet.
Any help would be appriciated
class LoginPage extends StatefulWidget {
LoginPage({Key? key}) : super(key: key);
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage>
with SingleTickerProviderStateMixin {
static const int PIN_CODE_LENGTH = 4;
final TextEditingController _mobileController = TextEditingController();
final TextEditingController _pinController = TextEditingController();
final UniqueKey _mobileKey = UniqueKey();
final UniqueKey _pinKey = UniqueKey();
bool _submittable = false;
bool _isLoginStepOne = true;
String _buttonText = Strings.next;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Directionality(
textDirection: TextDirection.rtl,
child: SingleChildScrollView(
child: SizedBox(
height: SizePercentConfig.screenHeight,
child: Column(
children: [
_buildHeader(),
Expanded(
child: _buildForm(),
),
],
),
),
),
),
);
}
Widget _buildHeader() {
return Container(
height: SizePercentConfig.safeBlockVertical * 60,
child: Stack(
children: [
Positioned(
bottom: 0,
right: SizePercentConfig.blockSizeHorizontal * 30,
left: SizePercentConfig.blockSizeHorizontal * 30,
child: Image.asset(
Assets.logo,
fit: BoxFit.fitWidth,
),
),
Container(
height: SizePercentConfig.safeBlockVertical * 50,
child: Stack(
children: [
Positioned(
bottom: 0,
child: Image.asset(
Assets.loginHeader,
width: SizePercentConfig.screenWidth,
fit: BoxFit.fitWidth,
),
),
],
),
),
],
),
);
}
Widget _buildForm() {
return Form(
onChanged: _validate,
child: Padding(
padding: const EdgeInsets.all(Dimens.unitX2),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
AnimatedSwitcher(
duration: const Duration(seconds: 1),
transitionBuilder: (Widget child, Animation<double> animation) {
final inAnimation = Tween<Offset>(
begin: Offset(1.0, 0.0), end: Offset(0.0, 0.0))
.animate(animation);
final outAnimation = Tween<Offset>(
begin: Offset(-1.0, 0.0), end: Offset(0.0, 0.0))
.animate(animation);
print('** child key: ${child.key}');
print('** mobile key: $_mobileKey');
print('** pin key: $_pinKey');
if (child.key == _mobileKey) {
// in animation
print('>>>>>>> first statement');
return ClipRect(
child: SlideTransition(
position: inAnimation,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: child,
),
),
);
} else {
// out animation
print('>>>>>>> second statement');
return ClipRect(
child: SlideTransition(
position: outAnimation,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: child,
),
),
);
}
},
layoutBuilder:
(Widget? currentChild, List<Widget> previousChildren) {
return currentChild!;
},
child: _isLoginStepOne
? AppTextField(
key: _mobileKey,
controller: _mobileController,
hint: Strings.mobileNumber,
textInputType: TextInputType.phone,
)
: _buildPinCode()),
SizedBox(height: Dimens.unitX2),
AppSolidButton(
onPressed: _buttonAction,
text: _buttonText,
width: SizePercentConfig.screenWidth,
enabled: _submittable,
),
SizedBox(height: Dimens.unitX2),
],
),
),
);
}
void _validate() {
if (_isLoginStepOne) {
if (Regex.mobileRegex.hasMatch(_mobileController.value.text) !=
_submittable)
setState(() {
print('--> setState called in _validate');
_submittable = !_submittable;
});
} else {
if ((_pinController.value.text.length == 4) != _submittable)
setState(() {
print('--> setState called in _validate');
_submittable = !_submittable;
});
}
}
void _buttonAction() {
if (_submittable) {
setState(() {
print('--> setState called in _buttonPressed');
_isLoginStepOne = false;
_submittable = false;
_buttonText = Strings.login;
});
} else {}
}
Widget _buildPinCode() {
return Directionality(
textDirection: TextDirection.ltr,
child: PinCodeTextField(
key: _pinKey,
controller: _pinController,
appContext: context,
length: PIN_CODE_LENGTH,
onChanged: (_) {},
enablePinAutofill: true,
enableActiveFill: true,
textStyle: TextStyle(color: Palette.scorpion),
pinTheme: PinTheme(
shape: PinCodeFieldShape.circle,
fieldHeight: SizePercentConfig.safeBlockHorizontal * 20,
fieldWidth: SizePercentConfig.safeBlockHorizontal * 20,
activeFillColor: Palette.concrete,
inactiveFillColor: Palette.concrete,
selectedFillColor: Palette.roseBud,
activeColor: Palette.concrete,
disabledColor: Palette.concrete,
inactiveColor: Palette.concrete,
selectedColor: Palette.roseBud,
),
cursorColor: Palette.transparent,
keyboardType: TextInputType.number,
),
);
}
}
Give your ClipRect widgets unique keys:
If the "new" child is the same widget type and key as the "old" child, but with different parameters, then AnimatedSwitcher will not do a transition between them, since as far as the framework is concerned, they are the same widget and the existing widget can be updated with the new parameters. To force the transition to occur, set a Key on each child widget that you wish to be considered unique (typically a ValueKey on the widget data that distinguishes this child from the others).

Flutter resolve multiple heroes that share the same tag within a subtree

In my simple part of mobile application i used Hero without any problem and that works fine, now when i try to add a class as Widget which named AnimatedFab in part of this class i get this error:
There are multiple heroes that share the same tag within a subtree.
i don't use any Hero in this class and i'm wondering why i get the error
i used Hero in Stack and implementation code is:
Positioned(
top: 259.0,
left: 6.0,
child: SizedBox(
key: _imageKey,
width: 43.0,
height: 43.0,
child: InkWell(onTap: () {
//...
},child: MyHero(hiveFeed: widget.hiveFeeds)),
)),
and in parent of Stack which above code is one child of that, i have this code:
Positioned(top: 140.0, right: -40.0, child: const AnimatedFab().pl(8.0)),
full Stack children:
return Stack(
children: [
Card(
child: Stack(
children: [
Positioned(top: 140.0, right: -40.0, child: const AnimatedFab().pl(8.0)),
],
),
),
Positioned(
top: 259.0,
left: 6.0,
child: SizedBox(
key: _imageKey,
width: 43.0,
height: 43.0,
child: InkWell(onTap: () {
//...
},child: MyHero(hiveFeed: widget.hiveFeeds)),
)),
],
);
UPDATED
i consider heroTag as a value into below class:
AnimatedFab class which i have problem with that is below code:
Positioned(top: 140.0, right: -40.0, child: AnimatedFab(key:_imageKey).pl(8.0)),
class AnimatedFab extends StatefulWidget {
final VoidCallback onPressed;
final Key _key;
const AnimatedFab({Key key, this.onPressed}) : _key = key;
#override
_AnimatedFabState createState() => _AnimatedFabState();
}
class _AnimatedFabState extends State<AnimatedFab> with SingleTickerProviderStateMixin {
AnimationController _animationController;
Animation<Color> _colorAnimation;
final double expandedSize = 160.0;
final double hiddenSize = 50.0;
#override
void initState() {
super.initState();
_animationController = AnimationController(vsync: this, duration: const Duration(milliseconds: 200));
_colorAnimation = ColorTween(begin: Colors.transparent, end: Colors.pink[800]).animate(_animationController);
}
#override
void dispose() {
_animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return SizedBox(
width: expandedSize,
height: expandedSize,
child: AnimatedBuilder(
animation: _animationController,
builder: (BuildContext context, Widget child) {
return Stack(
alignment: Alignment.center,
children: <Widget>[
_buildFabCore(widget.key),
],
);
},
),
);
}
Widget _buildOption(IconData icon, double angle) {
if (_animationController.isDismissed) {
return Container();
}
double iconSize = 0.0;
if (_animationController.value > 0.8) {
iconSize = 26.0 * (_animationController.value - 0.8) * 5;
}
return Transform.rotate(
angle: angle,
child: Align(
alignment: Alignment.topCenter,
child: Padding(
padding: const EdgeInsets.only(top: 8.0),
child: IconButton(
onPressed: _onIconClick,
icon: Transform.rotate(
angle: -angle,
child: Icon(
icon,
color: Colors.black54,
),
),
iconSize: iconSize,
alignment: Alignment.center,
padding: const EdgeInsets.all(0.0),
),
),
),
);
}
Widget _buildExpandedBackground() {
final double size = hiddenSize + (expandedSize - hiddenSize) * _animationController.value;
return AnimatedOpacity(
opacity: _animationController.value,
duration: const Duration(milliseconds: 300),
child: Card(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(100.0)),
elevation: 4.0,
child: Container(
height: size,
width: size,
),
),
);
}
Widget _buildFabCore(Key key) {
final double scaleFactor = 2 * (_animationController.value - 0.5).abs();
return FloatingActionButton(
key: key,
elevation: 0.0,
mini: true,
onPressed: _onFabTap,
backgroundColor: _colorAnimation.value,
child: Transform(
alignment: Alignment.center,
transform: Matrix4.identity()..scale(1.0, scaleFactor),
child: Icon(
_animationController.value > 0.5 ? Icons.close : Icons.filter_list,
color: _animationController.value > 0.5 ? Colors.white:Colors.black54,
size: 26.0,
),
),
);
}
void open() {
if (_animationController.isDismissed) {
_animationController.forward();
}
}
void close() {
if (_animationController.isCompleted) {
_animationController.reverse();
}
}
void _onFabTap() {
if (_animationController.isDismissed) {
open();
} else {
close();
}
}
void _onIconClick() {
widget.onPressed();
close();
}
}
how can i solve this issue? i think main problem is in _buildFabCore(),, method which i have this in this class.
thanks in advance
Consider passing a value to heroTag for the FloatingActionButton inside _buildFabCore or simply pass null.
This may happen if you have another FloatingActionButton is used within the app so if you didn't pass different heroTag for each one of them you will get this error.

Keyboard automatically disappears from TextField in ListView.Builder

I'm trying to implement a solution where a row (containing both a TextField and a Text) in ListView.Builder is automatically for every record retrieved from a webserver.
However when I want to start typing in such a TextField the keyboard appears and immediatly disappears again.
This is the code of my screen.
class GameScreen extends StatelessWidget {
static const RouteName = "/GameScreen";
#override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
const horizontalMargin = 20.0;
return Scaffold(
appBar: getAppBar(),
backgroundColor: Colors.transparent,
body: Stack(
children: <Widget>[
Background(),
Column(
children: <Widget>[
Header("Starting letter: B"),
Expanded(
child: ListBlocProvider(
listWidget: GameCategoriesList(),
itemsService: CategoriesService(),
margin: EdgeInsets.only(
left: horizontalMargin,
bottom: 10,
right: horizontalMargin,
),
),
),
SizedBox(
height: 20,
),
SizedBox(
width: size.width - 40,
height: 60,
child: Container(
height: 60,
child: TextButtonWidget(
() {
// Navigator.of(context).pushNamed(GameScreen.RouteName);
},
"Stop game",
),
),
),
SizedBox(
height: 20,
)
],
),
],
),
);
}
}
This is the code of my ListBlocProvider:
class ListBlocProvider extends StatelessWidget {
final ListWidget listWidget;
final ItemsService itemsService;
final bool useColor;
final bool usePaddingTop;
final double height;
final EdgeInsets margin;
const ListBlocProvider({
#required this.listWidget,
#required this.itemsService,
this.useColor = true,
this.usePaddingTop = true,
this.height = 200,
this.margin,
});
#override
Widget build(BuildContext context) {
const horizontalMargin = 20.0;
return BlocProvider(
create: (context) => ItemsBloc(itemsService: itemsService)..add(ItemsFetched()),
child: Container(
padding: usePaddingTop ? EdgeInsets.only(top: 10) : null,
decoration: BoxDecoration(
color: this.useColor ? Color.fromRGBO(10, 50, 75, 0.9) : null,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10),
),
),
margin: this.margin,
height: this.height,
child: this.listWidget,
),
);
}
}
This is the code of my List:
class GameCategoriesList extends ListWidget {
#override
_GameCategoriesListState createState() => _GameCategoriesListState();
}
class _GameCategoriesListState extends State<GameCategoriesList> {
#override
Widget build(BuildContext context) {
return BlocBuilder<ItemsBloc, ItemsState>(
builder: (context, state) {
if (state is ItemsFailure) {
return Center(
child: Text('failed to fetch categories'),
);
}
if (state is ItemsSuccess) {
if (state.items.isEmpty) {
return Center(
child: Text('no categories found.'),
);
}
return ListView.builder(
itemBuilder: (BuildContext context, int index) {
var textEditingController = TextEditingController();
return GameCategoryItemWidget(
key: UniqueKey(),
categoryModel: state.items[index],
textEditingController: textEditingController,
);
},
itemCount: state.items.length,
);
}
return Center(
child: LoadingIndicator(),
);
},
);
}
}
And this is the code where the both the TextField and the Text are build:
class GameCategoryItemWidget extends StatefulWidget {
final CategoryModel categoryModel;
final TextEditingController textEditingController;
const GameCategoryItemWidget({Key key, this.categoryModel, this.textEditingController}) :
super(key: key);
#override
_GameCategoryItemWidgetState createState() => _GameCategoryItemWidgetState();
}
class _GameCategoryItemWidgetState extends State<GameCategoryItemWidget> {
var formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Container(
child: Form(
key: this.formKey,
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.only(left: 10, top: 20, bottom: 10),
child: Text(
this.widget.categoryModel.name,
style: TextStyle(
color: Colors.white,
fontSize: 18,
),
),
),
Container(
color: Colors.white,
child: InputField(
InputDecoration(labelText: this.widget.categoryModel.name),
this.widget.textEditingController,
false,
),
),
],
),
),
);
}
#override
void dispose() {
this.widget.textEditingController.dispose();
super.dispose();
}
}
The InputField is a custom widget to hide the switch between a Material and a Cupertino version of the TextField.
I've already tried to remove the Key from the custom TextField widget. The funny part is that the input is actually working, however it can't determine for which of the TextFields in the ListView the input is determined so it adds the input to all of them. I've also tried to swap things around with making Stateless widgets Statefull, but that didn't help either.
The entire build is based upon: https://bloclibrary.dev/#/flutterinfinitelisttutorial.
Hoping you guys can help me.

Draw outside listview bounds in Flutter

I want to transform my item that it is bigger than the listview itself. (intention for focused navigation)
My List:
Container(
height: 100,
child: ListView.builder(
itemBuilder: (context, index) => HomeItem(title: '$index'),
scrollDirection: Axis.horizontal,
),
),
My Item:
class HomeItem extends StatelessWidget {
final String title;
final bool expand;
const HomeItem({
#required this.title,
this.expand = false,
});
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: ThemeDimens.padding8),
child: Transform.scale(
scale: expand ? 1.5 : 1,
child: AnimatedContainer(
width: 50,
height: 100,
color: expand ? ThemeColors.accent : ThemeColors.primary,
duration: ThemeDurations.shortAnimationDuration(),
child: Center(
child: Text(title),
),
),
),
);
}
}
Current behaviour
Expected behaviour
If you try to use OverflowBox or Transform, content of an item will still clip and won't be drawn outside of its bounding box. But it's possible to use Overlay to draw an element on top of list and position it on a specific list item, though it's a bit complicated.
class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
final elements = List.generate(12, (i) => i);
int selectedIndex;
OverlayEntry overlayEntry;
List<LayerLink> layerLinks;
#override
void initState() {
super.initState();
// Creating a layer link for each list cell
layerLinks = List.generate(elements.length, (i) => LayerLink());
}
void createOverlayEntry(int i, BuildContext context) {
// Removing an overlay entry, if there was one
overlayEntry?.remove();
final renderBox = context.findRenderObject() as RenderBox;
final size = renderBox.size;
final offset = renderBox.localToGlobal(Offset.zero);
// Creating a new overlay entry linked to specific list element
overlayEntry = OverlayEntry(
builder: (context) => Positioned(
left: 0,
top: 0,
child: CompositedTransformFollower(
link: layerLinks[i],
showWhenUnlinked: false,
offset: Offset(-20, 0),
child: Material(
color: Colors.yellow,
child: InkWell(
onTap: () {
setState(() {
selectedIndex = null;
});
overlayEntry?.remove();
overlayEntry = null;
},
child: Container(
alignment: Alignment.center,
width: 70,
height: elementHeight,
child: Text('$i')
),
)
),
)
)
);
// Inserting an entry
Overlay.of(context).insert(overlayEntry);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
height: elementHeight,
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: elements.length,
itemBuilder: (c, i) {
return CompositedTransformTarget(
link: layerLinks[i],
child: Material(
color: Colors.red,
child: InkWell(
onTap: () {
setState(() {
selectedIndex = i;
});
createOverlayEntry(i, context);
},
child: Container(
alignment: Alignment.center,
width: 30,
child: Text('${elements[i]}'),
),
),
),
);
},
separatorBuilder: (c, i) {
return Container(width: 10, height: 10);
},
),
),
);
}
}

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.