How to animate widgets automatically in Flutter? - flutter

I have a Future which returns a List and using FutureBuilder and inside it a ListView.builder I show data that I got from Future.
But the problem is, whenever Future returns data my list of widgets just pops directly into the screen. I want to give it a animation (fade or curve) which I am not supposed to trigger manually, instead I want that when I got the data from Future my list to pop to screen not direcly but with some latency/fade/curve or any other animation.
How can I achieve that?

You can use a opacity animation, here you can see an example.
Then you can set
bool _visible = true; //Put this inside your initState
AnimatedOpacity(
opacity: _visible ? 1.0 : 0.0,
duration: Duration(milliseconds: 500),
child:ListView.builder(
itemCount: count,
padding: EdgeInsets.all(10.0),
itemBuilder: (BuildContext context, int position) {
return Card(
color: Colors.white,
elevation: 2.0,
child: ListTile(
title: Text(this.list[position].name),
subtitle: Text(this.list[position].type),
trailing: GestureDetector(
child: Icon(Icons.delete, color: Colors.grey,),
onTap: () {
_delete(context, list[position]);
},
),
onTap: () {
debugPrint("ListTile Tapped");
navigateToDetail(this.list[position]);
},
),
);
},
)
),

Related

How to change the value of 'selectedIndex' from one dart file to the other dart file using flutter GetX?

I have my custom Bottom Navigation Bar in one dart file, i.e. bottomnavbar.dart. And I have list of multiple screens(or pages) in my home.dart file. I am using an .obs variable to store my selected index value.
code from home.dart file:
var selectedIndex = 0.obs;
final screen = [
const Page1(),
const Page2(),
const Page3(),
const Page4(),
const Page5(),
];
...
body: screen[selectedIndex.value],
...
Even if I change the variable value (like 0.obs to 1.obs), page not changing, why??
next of, In my bottomnavbar.dart file, I have extracted and made a widget for my nav bar 'items'. And I have tried to wrap the item widget with Obx:
Widget bnbItems(String image, int index, double height) {
return Obx(
() => InkWell(
splashColor: Theme.of(context).brightness == Brightness.dark
? Colors.white.withOpacity(0.5)
: Colors.pink.withOpacity(0.5),
enableFeedback: true,
onTap: () => setState(() {
selectedIndex.value = index;
_controller.animateTo(index / 4);
// print(selectedIndex);
}),
child: Container(
alignment: Alignment.center,
width: 50,
height: 50,
child: Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Image.asset(
image,
height: height,
),
),
),
),
);}
and I am getting this error:
[Get] the improper use of a GetX has been detected.
You should only use GetX or Obx for the specific widget that will be updated.
If you are seeing this error, you probably did not insert any observable variables into GetX/Obx
or insert them outside the scope that GetX considers suitable for an update
(example: GetX => HeavyWidget => variableObservable).
If you need to update a parent widget and a child widget, wrap each one in an Obx/GetX.
Can anyone give me the solution with some code and explanation? And also how will I be able to set a particular screen as the initial screen?
Replace on tap with this code
onTap: () {
selectedIndex.value = 1; // page index you want to view
},
then remove Obx(()=> on bnbItems widget
Widget bnbItems(String image, int index, double height) {
return InkWell(
splashColor: Theme.of(context).brightness == Brightness.dark
? Colors.white.withOpacity(0.5)
: Colors.pink.withOpacity(0.5),
enableFeedback: true,
onTap: () {
selectedIndex.value = 1; // page index you want to view
},
child: Container(
alignment: Alignment.center,
width: 50,
height: 50,
child: Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Image.asset(
image,
height: height,
),
),
),
);}
then use Obx(()=> wrapper on the body's widget
body: Obx(() => screen[selectedIndex.value]),
why you are using setState in GetX structure?
Try this code for onTap()
onTap: () {
selectedIndex.value = index;
_controller.animateTo(index / 4);
// print(selectedIndex);
},
to set initial screen use index no of that screen in var selectedIndex = 0.obs; instead of 0.

have search bar handle one tap and two taps differently

I am pretty new to flutter/dart, so this might be a silly question...
I wanted to have a search bar, that when tapped the first time, displays a series of listview tiles (like pre-canned search terms). I wanted a subsequent tap to then open the soft keyboard for user input. As it stands now, a single tap opens the listview tiles, and also opens the soft keyboard.
After some looking around, I am thinking I would need to wrap the searchbar in a GestureDetector, and handle the tap / double-tap gestures through that. What I can't quite figure out, is how to tie the GestureDetector gestures, ontap and ondoubletap, to the child widget actions... I think when the searchbar gets focus (onTap), the soft keyboard opens, so not sure if that behavior can be (easily) uncoupled...
The flutter cookbook example uses this:
ScaffoldMessenger.of(context).showSnackBar(snackBar);
but the API docs say this only manages snackbars and MaterialBanners:
"Manages SnackBars and MaterialBanners for descendant Scaffolds."
Here is the framework I have so far:
Widget searchBar() {
//final FloatingSearchBarController searchBarController = FloatingSearchBarController();
return
GestureDetector(
onTap: () =>{},
onDoubleTap: () => {},
child: FloatingSearchBar(
controller: searchBarController,
hint: "search",
openAxisAlignment: 0.0,
width: 600,
axisAlignment: 0.0,
scrollPadding: const EdgeInsets.only(top: 16, bottom: 20),
elevation: 4.0,
onQueryChanged: (query) {
},
builder: (BuildContext context, Animation<double> transition) {
return ClipRRect(
child: Material(
color: Colors.white,
child: Container(
color: Colors.white,
child: Column(
children: [
ListTile(
title: const Text('Item 1'),
onTap: () {},
),
ListTile(
title: const Text('Item 2'),
onTap: () {},
),
ListTile(
title: const Text('Item 3'),
onTap: () {},
),
],
),
),
)
);
},
)
);
Any thoughts would be greatly appreciated!

Flutter Button inside a Wheel ListView Widget

I am using a ListWheelScrollView more specific a clickable one.
(clickable_list_wheel_view)
I am trying to have a button inside my itemWidget but I can not click it. This is my list:
return ClickableListWheelScrollView(
scrollController: _scrollController,
itemHeight: _itemHeight,
itemCount: months.length,
scrollOnTap: true,
onItemTapCallback: (index) {
print(index)
},
child: ListWheelScrollView.useDelegate(
controller: _scrollController,
itemExtent: _itemHeight,
physics: FixedExtentScrollPhysics(),
diameterRatio: 3,
squeeze: 0.95,
onSelectedItemChanged: (index) {
// print(index);
},
childDelegate: ListWheelChildBuilderDelegate(
builder: (context, index) => MonthCardWidget(
month: months[index],
),
childCount: months.length,
),
),
);
Inside my MonthCardWidget I have this simple button:
Container(
height: 45,
width: 45,
color: Colors.transparent,
child: IconButton(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
onPressed: () {
print('flip');
},
icon: SvgPicture.asset('assets/images/flip.svg',
height: 20, width: 20),
),
),
Everything is getting displayed just fine but onPressed is never called on my button. I guess the GestureDetector is overriding the button? Is there any workaround for this? I couldn't find anything on this.
The GestureDetector is simply on top of the listView:
#override
Widget build(BuildContext context) {
if (_listHeight == .0) {
return MeasureSize(
child: Container(
child: widget.child,
),
onChange: (value) {
setState(() {
_listHeight = value.height;
});
},
);
}
return GestureDetector(
onTap: _onTap,
onTapUp: (tapUpDetails) {
_tapUpDetails = tapUpDetails?.localPosition;
},
child: widget.child,
);
}
The click will never reach your GestureDetector, you need to specify the click in the ClickableListWheelScrollView here:
onItemTapCallback: (index) {
print(index)
},
If the print you have there isn't printing, then get with the ClickableListWheelScrollView plugin publisher. You'll need logic to reach the changes you want with the button based on the index number passed from the ClickableListWheelScrollView I think....so a map of setState functions might do it.
Think of the button just being a view, and you're just running the function logic in parallel to each button based on its position in the list. The button is buried under the list, you need a layer above the ListWheel, which is the Clickable plugin, but obviously it becomes disconnected from the button, so you need to create logic to link them based on the index value, which is the position of the object in the list.
What I typically do:
onSelectedItemChanged: (index) {
// print(index);
},
This Will return the index position of the item in your list. Use this to change a variable.
Wrap your scroller in a GestureDetector.
In the Gesture Detector, write or call a function that takes your index position variable and performs your function as you desire.
If you need to control where in your list position the scroll begins, or remember its position when you rebuild etc, use a FixedExtentScrollController with an initialItem.
Everything slaves off the index of the onSelectedItemChanged in this way, and you use the FixedExtentScrollController to set a starting position at build. Remember that the list begins at 0.

I am using Flutter swiper package and I want to achieve the following activity

I am Using a Swiper Widget. I was able to swipe front and back. But i also want the functionality swiping to the next card while on a onPressed event. Moreover by pressing a button, I want to move to the next card. How to achieve this functionality.
This is my Swiper Widget.
Swiper(
scrollDirection: Axis.horizontal,
itemCount: studentDataWithAttendanceData.isEmpty
? 0
: studentDataWithAttendanceData.length,
itemBuilder: (BuildContext context, int index) {
return MyClassRoomCard(
studentData:
studentDataWithAttendanceData[index]
.studentData,
attendanceStatus:
studentDataWithAttendanceData[index]
.attendanceStatus,
);
},
scale: 0.8,
viewportFraction: 0.9,
onIndexChanged: rollNumberCallback,
layout: SwiperLayout.STACK,
itemWidth: 375,
itemHeight: 500,
pagination: SwiperPagination(
builder: DotSwiperPaginationBuilder(
activeColor: Colors.indigo.shade400,
color: Colors.grey.shade400,
),
),
control: SwiperControl(
color: Colors.indigo.shade400,
padding: EdgeInsets.symmetric(horizontal: 15.0),
iconPrevious: Icons.arrow_back_ios_rounded,
iconNext: Icons.arrow_forward_ios_rounded,
size: 20,
),
)
And this is my button
RaisedButton(
elevation: 5.0,
padding: EdgeInsets.all(22.0),
onPressed: onTap,//---------------->by tapping this, I want to change the card to the next.
child: Icon(
icon,
color: iconColor,
size: 50.0,
),
color: buttonColor,
shape: CircleBorder(),
),
add a controller to the swipper
SwiperController controller = SwiperController();
then on the onTap
call
controller.next()
You have to define and add controller to the swipper after that you can control the swipper on onTap event.such as
final controller=SwiperController()
After that assign it to the Swipper as
Swiper(
controller: SwiperController(),
//Rest are the same...
)
Now you can control the index of the swipper using the controller and change the state by calling method such as
controller.move(1);
controller.next();
controller.previous();
onTap(){
controller.next();
//call the method
}

Remove Padding on CupertinoSliverNavigationBar

I am trying to use CupertinoSliverNavigationBar, actually it's great, but for some reason I can't place the trailing right on the end of navigation bar. I looked up and I (guess, I) found that there's Padding inside it
this is my code
new CupertinoPageScaffold(
child: new CustomScrollView(
slivers: <Widget>[
new CupertinoSliverNavigationBar(
largeTitle: new Text('Tasks'),
trailing: new CupertinoButton(
child: new Icon(AdditionalCupertinoIcons.compose, size: 32.0),
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return new CupertinoAlertDialog();
});
},
padding: EdgeInsets.all(0.0),
),
)
],
),
),
Sadly, no can-do.
Looking at this line of source code, you can see that they are using a Padding at the end, which is _kNavBarEdgePadding, i.e. 16.0. Same for the start.
This means that with the CupertinoSliverNavigationBar you will not be able to remove that Padding because there is no access point to change it. You will have to create your own widget for that.
The _CupertinoPersistentNavigationBar widget contains the Padding and is used by CupertinoSliverNavigationBar, as can be seen here and for completion here.
There is an easy way to move a widget on the screen:
Widget _adjustNavigationBarButtonPosition(Widget button, double x) {
if (button == null) return null;
return Container(
transform: Matrix4.translationValues(x, 0, 0),
child: button,
);
}
Wrap your CupertinoButton with this method and specify an offset. To remove the padding completely, the offset should be 16.0.
You can use Matrix4.translationValues to move a child within the container. In your case x Matrix4.translationValues(12, 0, 0), should be positive to move the trailing to the right.
new CupertinoPageScaffold(
child: new CustomScrollView(
slivers: <Widget>[
new CupertinoSliverNavigationBar(
largeTitle: new Text('Tasks'),
trailing: Container(
transform: Matrix4.translationValues(12, 0, 0),
child : CupertinoButton(
child: new Icon(AdditionalCupertinoIcons.compose, size: 32.0),
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return new CupertinoAlertDialog();
});
},
)
),
)
],
),
),