How to stop a widget to reload on setState() method in StatefulWidget Class in Flutter - flutter

What I am trying to achieve is to save the state of the Widget i.e it should not refresh when the setState() method is been called.
class _GenderSelectionPageState extends State<GenderSelectionPage> {
bool isFemaleSelected = false;
AdmobBannerSize bannerSize;
GlobalKey _globalKey = new GlobalKey();
bool isLoaded = false;
#override
void initState() {
// TODO: implement initState
super.initState();
bannerSize = AdmobBannerSize.BANNER;
}
#override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;
return new Scaffold(
body: new Container(
width: width,
child: new Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Flexible(
child: new Hero(
tag: "gender",
child: Material(
child: new Row(
children: <Widget>[
InkWell(
onTap: () {
setState(() {
if (isFemaleSelected) {
isFemaleSelected = false;
} else {
isFemaleSelected = true;
}
});
},
child: Opacity(
child: Image.asset(
"assets/woman.png",
height: height / 4,
width: width / 2 - 12,
),
opacity: isFemaleSelected ? 1.0 : 0.30,
),
),
InkWell(
onTap: () {
setState(() {
if (isFemaleSelected) {
isFemaleSelected = false;
} else {
isFemaleSelected = true;
}
});
},
child: Opacity(
opacity: !isFemaleSelected ? 1.0 : 0.30,
child: Image.asset(
"assets/boy.png",
height: height / 4,
width: width / 2 - 12,
),
),
),
],
),
),
),
),
],
),
flex: 1,
),
InkWell(
onTap: () {
setState(() {
});
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext) =>
new HeightWeightSelection(isFemaleSelected
? "assets/woman.png"
: "assets/boy.png")));
},
child: Container(
margin: EdgeInsets.only(bottom: 12.0),
child: new Image.asset(
"assets/next.png",
height: 64.0,
width: 64.0,
),
)),
new AdmobBannerWrapper(adUnitId: getBannerAdUnitId(),adSize: bannerSize,key: _globalKey,),
/* new AdmobBanner(
adUnitId: getBannerAdUnitId(),
adSize: bannerSize,
listener:
(AdmobAdEvent event, Map<String, dynamic> args) {
handleEvent(event, args, 'Banner');
},
),*/
],
),
)),
);
}
I don't want to call the AdmobBannerWrapper every time I press my image button at the bottom.AdmobBannerWrapper should be loaded once only but the thing is whenever I click the Next Image it load AdmobBannerWrapper method every time.

Build it in initState() then use it's reference wherever required it will not build again until parent widget reinitialized.
var banner;
#override
void initState() {
// TODO: implement initState
super.initState();
bannerSize = AdmobBannerSize.BANNER;
banner = AdmobBannerWrapper(adUnitId: getBannerAdUnitId(),adSize: bannerSize,key:_globalKey,);
}
than call it in by reference here banner
#override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;
return new Scaffold(
body: new Container(
width: width,
child: new Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Flexible(
child: new Hero(
tag: "gender",
child: Material(
child: new Row(
children: <Widget>[
InkWell(
onTap: () {
setState(() {
if (isFemaleSelected) {
isFemaleSelected = false;
} else {
isFemaleSelected = true;
}
});
},
child: Opacity(
child: Image.asset(
"assets/woman.png",
height: height / 4,
width: width / 2 - 12,
),
opacity: isFemaleSelected ? 1.0 : 0.30,
),
),
InkWell(
onTap: () {
setState(() {
if (isFemaleSelected) {
isFemaleSelected = false;
} else {
isFemaleSelected = true;
}
});
},
child: Opacity(
opacity: !isFemaleSelected ? 1.0 : 0.30,
child: Image.asset(
"assets/boy.png",
height: height / 4,
width: width / 2 - 12,
),
),
),
],
),
),
),
),
],
),
flex: 1,
),
InkWell(
onTap: () {
setState(() {
});
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext) =>
new HeightWeightSelection(isFemaleSelected
? "assets/woman.png"
: "assets/boy.png")));
},
child: Container(
margin: EdgeInsets.only(bottom: 12.0),
child: new Image.asset(
"assets/next.png",
height: 64.0,
width: 64.0,
),
)),
banner, /*this is our variable */
/* new AdmobBanner(
adUnitId: getBannerAdUnitId(),
adSize: bannerSize,
listener:
(AdmobAdEvent event, Map<String, dynamic> args) {
handleEvent(event, args, 'Banner');
},
),*/
],
),
)),
);
}

Put it inside a stateless widget:
class AdBanner extends StatelessWidget{
final adUnitId;
final adSize;
const AdBanner({Key key, this.adUnitId, this.adSize}) : super(key: key);
Widget build(BuildContext context){
return AdmobBannerWrapper(
adUnitId: getBannerAdUnitId(),
adSize: bannerSize,
key: _globalKey,
);
}
}
next time when you call setState if the parameters are unchanged, it is not going to get rebuilt.

Related

flutter app freezes if animation is added inside futureBuilder

I have this application where I will have futurebuilder to get data first, and then return a scaffold with a separate splash screen to simulate the screen darken effect with alertdialog while enabling setstate (I tested, they dont allow setstate with alert dialog). However, when I used Animated Opacity, Color Tween or Animated Switcher, as soon as the screen loads, the app freezes.
code:
class MainPageState extends State<MainPage> with TickerProviderStateMixin {
GlobalKey imageKey = GlobalKey();
late Animation splashAnimation;
late AnimationController splashController;
double splashOpacity = 0;
#override
void initState() {
splashController =
AnimationController(vsync: this, duration: Duration(milliseconds: 400));
splashAnimation =
ColorTween(begin: Colors.transparent, end: Color.fromARGB(155, 0, 0, 0))
.animate(splashController);
super.initState();
}
#override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;
PageLoader pageLoader = context.watch<PageLoader>();
TabProperty tabProperty = context.watch<TabProperty>();
return WillPopScope(
onWillPop: () async {
//check if user logged in ? disable back btn : exit app
bool login = false;
await StorageManager.readData("loggedIn")
.then((value) => login = value);
if (login) {
return false;
} else {
SystemNavigator.pop();
}
return false;
},
child: FutureBuilder(
future: getMenuAndAccountInfo(pageLoader),
builder: ((context, snapshot) {
//placeholder
if (!snapshot.hasData) {
return Stack(children: [
SafeArea(
child: Scaffold(
body: pageLoader.currentPage,
),
),
Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
color: Color.fromARGB(100, 0, 0, 0),
),
Center(child: CircularProgressIndicator()),
]);
} else {
List<dynamic> menuData =
(snapshot.data as Map<String, dynamic>)["Menu"];
return SafeArea(
child: RepaintBoundary(
key: imageKey,
child: Stack(
children: [
Scaffold(
body: pageLoader.currentPage,
bottomNavigationBar: Container(
height: height * 0.07,
color: Colors.blue,
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: MaterialButton(
padding: EdgeInsets.zero,
splashColor: Colors.orange,
highlightColor: Colors.transparent,
onPressed: () {
setState(() {});
splashOpacity = 1;
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.bookmark,
color: Colors.white,
size: height * 0.035,
),
Text(
"Bookmark",
style: TextStyle(
color: Colors.white,
fontSize: height * 0.02),
),
],
)),
),
Expanded(
child: MaterialButton(
padding: EdgeInsets.zero,
splashColor: Colors.orange,
highlightColor: Colors.transparent,
onPressed: () {
setState(() {});
splashOpacity = 1;
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.account_circle_rounded,
color: Colors.white,
size: height * 0.035,
),
Text(
"Profile",
style: TextStyle(
color: Colors.white,
fontSize: height * 0.02),
)
],
)),
),
],
),
),
),
Positioned.fill(
child: AnimatedOpacity(
opacity: splashOpacity,
duration: Duration(milliseconds: 400),
child: Container(
color: Color.fromARGB(155, 0, 0, 0),
),
),
)
],
),
),
);
}
}),
),
);
}
NEVER build the future as the future: parameter to the FutureBuilder!
future: getMenuAndAccountInfo(pageLoader),
No!
Instead, you want to declare a variable to hold the future in State, and in initState, initialize that variable, and in your FutureBuilder, reference that variable.
For details, see the first few paragraphs of the FutureBuilder documentation, or see my video on that.

video playing in background flutter

im working through a scrollable page view somewhat like tic tok and each time i leave the screen the video continuously play in the background, which i dont want, cuz this code ids from a youtube tutorial i dont know how to work around the problem, so please help me check problem for a viable solution
import 'package:app/packageManager/package.dart';
import 'dart:io';
class Reels extends StatefulWidget {
const Reels({Key? key}) : super(key: key);
#override
State<Reels> createState() => _ReelsState();
}
vidPicker(ImageSource src, BuildContext context) async{
final vid = await ImagePicker().pickVideo(source: src);
if(vid != null){
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => VideoUploader(
videoPath: vid.path, videoName:vid.name,
videoFile:File(vid.path)
)));
}
} //To Pick a Video
showDialogueBox(BuildContext, context){
return showDialog(context: context, builder: (context) => SimpleDialog(
children: [
SimpleDialogOption(
onPressed: () => vidPicker(ImageSource.gallery, context),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: const [
Icon(Icons.image),
Text(" Gallery ")
],
),
),
),
SimpleDialogOption(
onPressed: () => Navigator.of(context).pop(),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: const [
Icon(Icons.cancel),
Text(" Cancel ")
],
),
),
)
],
));
} //TO Show Option Like Gallery and Cancel
class _ReelsState extends State<Reels> {
#override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
automaticallyImplyLeading: false,
elevation: 0,
flexibleSpace: SizedBox(
height: 200,
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
IconButton(onPressed: () => showDialogueBox(BuildContext,context),
icon: const Icon(Icons.add),
iconSize: 35,
color: Colors.teal[300],
)
],
),
),
),
backgroundColor: Colors.transparent,
),
body: StreamBuilder(
stream: fireStore.collection("videoReels").snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
// TODO: Put Progress Bar Here
if (!snapshot.hasData) return const Text("Loading...");
return PageView.builder(
itemCount: snapshot.data!.docs.length,
scrollDirection: Axis.vertical,
controller: PageController(viewportFraction: 1, initialPage: 0),
itemBuilder: (context, index){
DocumentSnapshot dataSnapshot = snapshot.data!.docs[index];
return Stack(
alignment: Alignment.bottomCenter,
children: [
VideoPlayerContent(videoUrl: dataSnapshot["videoUrl"]),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
flex: 3,
child: Container(
height: MediaQuery.of(context).size.height/6,
padding: const EdgeInsets.all(10.0),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
children: [
InkWell(
onTap: () => {},
child: const Icon(Icons.thumb_up, color: Colors.blueAccent,),
),
const SizedBox(width: 30,),
InkWell(
onTap: () => {},
child: const Icon(Icons.favorite, color: Colors.red,),
)
],
),
const SizedBox(width: 20,),
InkWell(
onTap: () => {},
child: Text(" Add Comment here... ", style: TextStyle( color: Colors.grey[500] ),),
)
],
),
const SizedBox(height: 30,),
// Second Row
Padding(
padding: const EdgeInsets.fromLTRB(30.0, 4.0,30.0,4.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
InkWell(
onTap: () => { } ,
child:ClipRRect(
borderRadius: BorderRadius.circular(50.0),
child: CircleAvatar(backgroundImage: NetworkImage(dataSnapshot['avatar']), radius: 25,),
),
),
Text((dataSnapshot["videoUrl"])),
ElevatedButton(onPressed: ()=> {}, child: Text("Subscribe"))
],
),
)
],
),
),
),
// TODO: Remove this later
],
)
],
);
},
);
}
),
);
}
}
import 'package:app/packageManager/package.dart';
class VideoPlayerContent extends StatefulWidget {
final videoUrl;
const VideoPlayerContent({Key? key, required this.videoUrl}) : super(key: key);
#override
State<VideoPlayerContent> createState() => _VideoPlayerContentState();
}
class _VideoPlayerContentState extends State<VideoPlayerContent> {
late VideoPlayerController _videoController;
late Future _initializeVideoPlayer;
#override
void initState(){
_videoController = VideoPlayerController.network(widget.videoUrl);
_initializeVideoPlayer = _videoController.initialize();
_videoController.play();
_videoController.setVolume(1);
_videoController.setLooping(true);
super.initState();
}
#override
void dispose (){
_videoController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: FutureBuilder(
future: _initializeVideoPlayer,
builder: (context, snapshot){
if (snapshot.connectionState == ConnectionState.done){
return VideoPlayer(_videoController);
}else{
return Container(
color: Colors.black,
child: const Center(
child: CircularProgressIndicator(
value: 0.8,
valueColor: AlwaysStoppedAnimation<Color>(Colors.purpleAccent),
),
)
);
}
},
),
);
}
}
Have you tried WidgetsBindingObserver and VisibilityDetector?
If you have not, then it might be handy to you.
For WidgetBindingObserver, simply use it as mixin like this:
class _VideoPlayerContentState extends State<VideoPlayerContent> with WidgetsBindingObserver{
#override
void initState(){
WidgetsBinding.instance?.addObserver(this);
super.initState();
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.resumed:
// TODO: Handle this case.
break;
case AppLifecycleState.inactive:
// Do like this in other lifecylestate if required !
_videoController.pause();
// TODO: Handle this case.
break;
case AppLifecycleState.paused:
// TODO: Handle this case.
break;
case AppLifecycleState.detached:
// TODO: Handle this case.
break;
}
super.didChangeAppLifecycleState(state);
}
// rest of the code .....
#override
void dispose(){
WidgetsBinding.instance?.removeObserver(this);
super.dispose();
}
}
Using visibility detector:
simply wrap the video player with this widget like:
VisibilityDetector(
// Must provide key
key: ValueKey<String>('give any string value to represent key'),
onVisibilityChanged: (visibilityInfo) {
// 0 ---> visible, 1 --> not visible
if(visibilityInfo.visibleFraction == 0){
_videoController.pause();
// might need setState over here
}
},
child : VideoPlayer(_videoController)
);

How to make Flutter Draggable feedback widget look the same like its child widget?

I would like to obtain the effect of having the same Draggable for both child and feedback composed widgets. Look at _getDraggablePaperSheets().
But I get totally different text size for the feedback widget. Why is that?
code disclaimer: every PaperSheet has its rotation and color kept inside Controller and is based on questionNumber, so it should look the same.
class Phase3Screen extends StatelessWidget {
static const ROUTE = '/oneoften/phase3';
final QuestionsController controller = Get.put(QuestionsController());
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
child: Stack(
children: [
DragTarget<int>(
builder: (
BuildContext context,
List<dynamic> accepted,
List<dynamic> rejected,
) {
return Container(
height: double.infinity,
width: double.infinity,
child: Align(
alignment: Alignment.bottomCenter,
child: Obx(() {
return Text('Question number: ${controller.getQuestionNumber}');
}),
),
);
},
onAccept: (int draggableData) {
debugPrint('draggable onAccept');
controller.nextQuestion();
},
onWillAccept: (item) {
debugPrint('draggable is on the target $item');
return true;
},
onLeave: (item) {
debugPrint('draggable has left the target $item');
},
),
Center(
child: Obx(
() {
return Stack(
children: _getDraggablePaperSheets(controller.getQuestionsStackSize),
);
},
),
),
],
),
),
),
);
}
List<Widget> _getDraggablePaperSheets(int currentQuestionsStackSize) {
List<Widget> sheets = [];
int i = 0;
logger.d("currentQuestionsStackSize = $currentQuestionsStackSize");
for (i = 1; i < currentQuestionsStackSize; i++) {
sheets.add(
Draggable(
maxSimultaneousDrags: 1,
data: i,
child: PaperSheet(questionNumber: i),
feedback: PaperSheet(questionNumber: i)
),
);
}
return sheets;
}
}
class PaperSheet extends GetView<QuestionsController> {
PaperSheet({
required this.questionNumber,
Key? key,
}) : super(key: key);
final questionNumber;
#override
Widget build(BuildContext context) {
return Container(
transform: Matrix4.rotationZ(controller.assignedRotationZ(questionNumber)),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(8.0)),
child: Container(
width: 250,
height: 420,
color: controller.assignedBackgroundColor(questionNumber),
child: Column(children: [
Expanded(
child: Container(
padding: const EdgeInsets.all(12.0),
alignment: Alignment.center,
child: Obx(
() {
return Text(
'Question: ${controller.currentQuestionText}',
style: TextStyle(
color: controller.assignedTextColor(questionNumber),
),
);
},
),
),
),
Expanded(
child: Container(
padding: const EdgeInsets.all(12.0),
child: Obx(() {
return Center(
child: Text(
'Answer: ${controller.currentQuestionAnswer}',
style: TextStyle(
color: controller.assignedTextColor(questionNumber),
),
),
);
}),
),
),
]),
),
),
);
}
}
Try to wrap with Material widget

Flutter : how to hide and show button on last and first index in listView

i set two buttons(left and right Button) on top of ListView. buttons work for scrolling on click. now i want to hide the left button when index is 0 and the right button when index is last. more explain to clear, the left button will be hidden in first index and the right button will be hidden in last index. please help me.
class ScrollingLeftAndRightButtonHide extends StatefulWidget {
#override
_ScrolllingOnClickButtonState createState() =>
_ScrolllingOnClickButtonState();}
class _ScrolllingOnClickButtonState
extends State<ScrollingLeftAndRightButtonHide> {
final _controller = ScrollController();
var _width = 100.0;
#override
Widget build(BuildContext context) {
var sizeDevice = MediaQuery.of(context).size;
this._width = sizeDevice.width;
var recentIndexIncrease = 0;
var recentIndexDecrease = 0;
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Column(
children: <Widget>[
Expanded(
flex: 1,
child: Container(
color: Colors.green,
)),
Expanded(
flex: 2,
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: ClipOval(
child: Material(
color: Colors.blue, // button color
child: InkWell(
splashColor: Colors.red, // inkwell color
child: SizedBox(
width: 56,
height: 56,
child: Icon(Icons.arrow_back)),
onTap: () {
var recentIndexDecreaseMinus =
recentIndexDecrease--;
_animateToIndex(recentIndexDecrease);
},
),
),
),
),
Expanded(
flex: 2,
child: Container(
color: Colors.transparent,
)),
Padding(
padding: const EdgeInsets.only(right: 8),
child: ClipOval(
child: Material(
color: Colors.blue, // button color
child: InkWell(
splashColor: Colors.red, // inkwell color
child: SizedBox(
width: 56,
height: 56,
child: Icon(Icons.arrow_forward)),
onTap: () {
_animateToIndex(recentIndexIncrease);
},
),
),
),
),
],
)),
Expanded(
flex: 16,
child: Container(
// height: 400,
child: ListView.builder(
controller: _controller,
scrollDirection: Axis.horizontal,
physics: PageScrollPhysics(),
itemCount: word_data.drink.length,
itemBuilder: (BuildContext context, int index) {
recentIndexIncrease = index;
recentIndexDecrease = index;
var wordDataReplace = word_data.drink[index]
.replaceAll(" ", "_")
.toLowerCase();
return Container(
child: Column(
children: <Widget>[
Expanded(
flex: 6,
child: GestureDetector(
child: Container(
color: Colors.purple,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Image.asset(
"asset/drink_images/" +
wordDataReplace +
".png",
fit: BoxFit.contain,
),
),
),
)),
],
),
width: sizeDevice.width,
);
}),
color: Colors.yellow,
),
),
],
),
),
);
}
_animateToIndex(i) => _controller.animateTo(_width * i,
duration: Duration(seconds: 1), curve: Curves.fastOutSlowIn);
}
this image of (ListView with top two Button)
I think it might be easier for you to replace ListView.builder by a Flutter_Swiper it will make your life a lot easier. Or maybe you can add a listner to your ScrollController in the initState where it handles the value of two Boolean variables leftButtonEnabled and rightButtonEnabled and set them to true or false depending on the position of the Controller
EDIT :
here's an example of using Flutter swiper in your code, I tried to make it simple and in the same time adding multiple features that can help you ( like SwiperControl ) I hope it helps you a little bit.
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
home: ScrollingLeftAndRightButtonHide(),
),
);
}
class ScrollingLeftAndRightButtonHide extends StatefulWidget {
#override
_ScrolllingOnClickButtonState createState() =>
_ScrolllingOnClickButtonState();
}
class _ScrolllingOnClickButtonState
extends State<ScrollingLeftAndRightButtonHide> {
SwiperController _controller = SwiperController();
SwiperControl _control = SwiperControl(color: Colors.white);
double get _width => MediaQuery.of(context).size.width;
double get _height => MediaQuery.of(context).size.height;
bool inFirstPage = true;
bool inLastPage = false;
List<String> word_data = [
"First",
"Second",
"Third",
"Fourth",
"Fifth",
"Sixth",
"Last",
];
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: Column(
children: <Widget>[
Container(
color: Colors.white,
child: Row(
children: <Widget>[
if (!inFirstPage)
IconButton(
color: Colors.indigoAccent,
onPressed: () {
_controller.previous();
},
icon: Icon(Icons.arrow_back),
),
Spacer(),
if (!inLastPage)
IconButton(
color: Colors.indigoAccent,
onPressed: () {
_controller.next();
},
icon: Icon(Icons.arrow_forward),
),
],
),
),
Expanded(
child: Container(
color: Colors.white,
child: Swiper(
controller: _controller,
control: _control,
loop: false,
scrollDirection: Axis.horizontal,
itemCount: word_data.length,
onIndexChanged: (value) {
if (value == word_data.length - 1)
setState(() {
inLastPage = true;
});
else if (value == 0)
setState(() {
inFirstPage = true;
});
else {
setState(() {
inFirstPage = false;
inLastPage = false;
});
}
},
itemBuilder: (BuildContext context, int index) {
return Container(
child: Column(
children: <Widget>[
Expanded(
child: GestureDetector(
child: Container(
width: _width,
alignment: Alignment.center,
color: Colors.indigoAccent,
child: Text(word_data[index]),
),
),
),
],
),
);
},
),
),
),
],
),
),
);
}
}
Add two variables in your state as
class _ScrolllingOnClickButtonState
extends State<ScrollingLeftAndRightButtonHide> {
bool leftEnabled = false; //this is initial visibility of left button
bool rightEnabled = true; //this is initial visibility of right button
........
Then in your build function where you are displaying left and right button add if statement
#override
Widget build(BuildContext context) {
var sizeDevice = MediaQuery.of(context).size;
this._width = sizeDevice.width;
var recentIndexIncrease = 0;
var recentIndexDecrease = 0;
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Column(
.............
if(leftEnabled)
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: ClipOval(
child: Material(
color: Colors.blue, // button color
child: InkWell(
splashColor: Colors.red, // inkwell color
child: SizedBox(
width: 56,
height: 56,
child: Icon(Icons.arrow_back)),
onTap: () {
var recentIndexDecreaseMinus =
recentIndexDecrease--;
_animateToIndex(recentIndexDecrease);
if (index == 0) { //Your logic to detect start of the list.
leftEnabled = false; //if it is the start make left invisible
}
if(list.size > 1)
rightEnabled = true; //whenever left button is pressed and your data has more than 1 element make right visible
setState(() {});
},
),
),
),
),
...............
Same code for the right button.
You cannot do it through your current structure of code. To achieve it you will have to move those arrow button Icons inside of the listView like this:
return ListView.builder(
scrollDirection: Axis.horizontal,
physics: PageScrollPhysics(),
itemCount: 5,
itemBuilder: (BuildContext context, int index) {
recentIndexIncrease = index;
recentIndexDecrease = index;
var wordDataReplace = word_data.drink[index].replaceAll(" ", "_").toLowerCase();
return Column(
children: <Widget>[
Row(
children: [
//Left arrow is the button indicating left arrow
if (index != 0) LeftArrow,
//Rightarrow is the button indicating right arrow
if (index != 4) RightArrow
],
),
Expanded(
child: GestureDetector(
child: Container(
color: Colors.purple,
padding: const EdgeInsets.all(10.0),
child: Image.asset("asset/drink_images/" +
wordDataReplace +
".png",
fit: BoxFit.contain,
),
),
)),
],
);
});

How to make this corousel slider clickable in flutter

Here is my code for corousel slider in Flutter, I want to make this slides clickable how can I do that?
When an image in corousel slider is clicked I want to open screen particular to the image category.
class _CarouselExampleState extends State<CarouselExample> {
List imgNews = [
"images/groceries.jpg",
"images/image_1.png",
"images/photographer.jpg",
"images/electrician.jpg",
];
#override
void initState() {
super.initState();
}
List<T> map<T>(List list, Function handler) {
List<T> result = [];
for (var i = 0; i < list.length; i++) {
result.add(handler(i, list[i]));
}
return result;
}
int _current = 0;
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Stack(
children: [
CarouselSlider(
options: CarouselOptions(
autoPlay: true,
height: 150,
viewportFraction: 1.0,
onPageChanged: (index, reason) {
setState(() {
_current = index;
});
},
),
items: imgNews.map(
(url) {
return Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
ClipRRect(
child: Image.asset(
url,
fit: BoxFit.fill,
height: 150,
width: 300,
),
),
],
)
);
},
).toList(),
),
Padding(
padding: EdgeInsets.only(top:150),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: map<Widget>(imgNews, (index, url) {
return Container(
width: 6.0,
height: 8.0,
margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 5.0),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _current == index ? Colors.red : Colors.blueGrey,
),
);
}),
),
),
],
)
]
);
}
}
I tried many ways but I was not able to make this corousel_slider clickable, anyone please help, when an image is clicked i want to open screen particular to the image category.
You can use InkWell widget wrapped in Material -
child: Material(
color: Colors.yellow,
child: InkWell(
onTap: () {
// Do something.
},
),
),
In your specific case -
...
items: imgNews.map(
(url) {
return Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
ClipRRect(
child: Material(
color: Colors.yellow,
child: InkWell(
onTap: () {
// Do something.
},
child: Image.asset(
URL,
fit: BoxFit.fill,
height: 150,
width: 300,
),
),
),
),
],
),
);
},
).toList(),
...
Here is How you can do that
First Make Carousel Image clickable
in your Case: Wrap it With GestureDetector
ClipRRect(
child: Image.asset(
url,
fit: BoxFit.fill,
height: 150,
width: 300,
),
),
Second Then on Tap of Image Get the Image Index and Pass it to A Function
onTap: () {
imgList.indexOf(url);
indexMethod(imgList.indexOf(url).toString());
},
Last Create a Method
indexMethod(String index) {
switch (index) {
case '0':
{
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HelpPage()),
);
}
break;
case '1':
{
Navigator.push(
context,
MaterialPageRoute(builder: (context) => UpdatesPage()),
);
}
break;
case '2':
{
Navigator.push(
context,
MaterialPageRoute(builder: (context) => UserProfile()),
);
}
break;
}
}
I Just Added This Functionality to My CarouselSlider :D