I am trying to ignore multi-finger touches (2-finger specifically) on a Button by wrapping it with IgnorePointer() like so:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(title: '1 touch'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool isSingleTouch = true;
#override
Widget build(BuildContext context) {
return IgnorePointer(
ignoring: !isSingleTouch,
child: RaisedButton(
onPressed: () {
print("Button Tapped");
},
child: Text("Tap with max 1 finger."),
));
}
}
I want isSingleTouch to be true when the user uses one finger but false when he uses two fingers. Is there any way to get the number of fingers and if it is 2 then make the button fail the hit test?
Please check the below example to detect two figure touch. You can modify it as per your requirement.
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Swipe Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: Container(
margin: EdgeInsets.only(top: 100),
child: MultiTouchPage(
backgroundColor: Colors.white,
borderColor: Colors.amber,
minTouches: 2,
onTapCallback: (touchCount, correct) {
print("Touch" + touchCount.toString());
},
),
),
),
);
}
}
class MultiTouchGestureRecognizer extends MultiTapGestureRecognizer {
MultiTouchGestureRecognizerCallback onMultiTap;
var numberOfTouches = 0;
int minNumberOfTouches = 0;
MultiTouchGestureRecognizer() {
super.onTapDown = (pointer, details) => this.addTouch(pointer, details);
super.onTapUp = (pointer, details) => this.removeTouch(pointer, details);
super.onTapCancel = (pointer) => this.cancelTouch(pointer);
super.onTap = (pointer) => this.captureDefaultTap(pointer);
}
void addTouch(int pointer, TapDownDetails details) {
this.numberOfTouches++;
}
void removeTouch(int pointer, TapUpDetails details) {
if (this.numberOfTouches == this.minNumberOfTouches) {
this.onMultiTap(numberOfTouches, true);
} else if (this.numberOfTouches != 0) {
this.onMultiTap(numberOfTouches, false);
}
this.numberOfTouches = 0;
}
void cancelTouch(int pointer) {
this.numberOfTouches = 0;
}
void captureDefaultTap(int pointer) {}
#override
set onTapDown(_onTapDown) {}
#override
set onTapUp(_onTapUp) {}
#override
set onTapCancel(_onTapCancel) {}
#override
set onTap(_onTap) {}
}
typedef MultiTouchGestureRecognizerCallback = void Function(
int touchCount, bool correctNumberOfTouches);
class MultiTouchPage extends StatefulWidget {
final MultiTouchPageCallback onTapCallback;
final int minTouches;
final Color backgroundColor;
final Color borderColor;
MultiTouchPage(
{this.backgroundColor,
this.borderColor,
this.minTouches,
this.onTapCallback});
#override
_MultiTouchPageState createState() => _MultiTouchPageState();
}
class _MultiTouchPageState extends State<MultiTouchPage> {
bool correctNumberOfTouches;
int touchCount;
#override
Widget build(BuildContext context) {
return RawGestureDetector(
gestures: {
MultiTouchGestureRecognizer:
GestureRecognizerFactoryWithHandlers<MultiTouchGestureRecognizer>(
() => MultiTouchGestureRecognizer(),
(MultiTouchGestureRecognizer instance) {
instance.minNumberOfTouches = widget.minTouches;
instance.onMultiTap =
(touchCount, correctNumberOfTouches,) => this.onTap(touchCount, correctNumberOfTouches);
},
),
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Container(
padding: EdgeInsets.all(12.0),
decoration: BoxDecoration(
color: widget.backgroundColor,
border: Border(
top: BorderSide(width: 1.0, color: widget.borderColor),
left: BorderSide(width: 1.0, color: widget.borderColor),
right: BorderSide(width: 1.0, color: widget.borderColor),
bottom: BorderSide(width: 1.0, color: widget.borderColor),
),
),
child: Text(
"Tap with " +
this.touchCount.toString() +
" finger(s).",
textAlign: TextAlign.center),
),
),
]),
);
}
void onTap(int touchCount, bool correctNumberOfTouches) {
this.correctNumberOfTouches = correctNumberOfTouches;
setState(() {
this.touchCount = touchCount;
});
print("Tapped with " + touchCount.toString() + " finger(s)");
widget.onTapCallback(touchCount, correctNumberOfTouches);
}
}
typedef MultiTouchPageCallback = void Function(int touchCount, bool correctNumberOfTouches);
Related
I have a Flutter StatefulWidget and in initState() method I am using WidgetsBinding.instance.addPostFrameCallback to use one instance variable (late List _tracks). like -
WidgetsBinding.instance.addPostFrameCallback((_) {
for(itr = 0; itr<_tracks.length; itr++){
// some logic
}
});
As this would get invoked after all Widgets are done. In one of the CustomPaint's painter class I am initializing that variable.
SizedBox.expand(
child: CustomPaint(
painter: TrackPainter(
trackCalculationListener: (tracks) {
_tracks = tracks;
}),
),
),
It is working fine when I have one screen, i.e the same class. But, When I am adding one screen before that and trying to navigate to this screen from the new screen it is throwing _tracks is not initialized exception.
new screen is very basic -
class MainMenu extends StatefulWidget {
const MainMenu({super.key});
#override
State<MainMenu> createState() => _MainMenuState();
}
class _MainMenuState extends State<MainMenu> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.white,
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const Play(),
maintainState: false));
},
child: const Text('play game'),
),
),
);
}
}
In single screen case the paint method of painter is getting called before postFrameCallback but in case of multiple it is not getting before postFrameCallback and because of that the variable is not getting initialized.
reproducible code -
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
routes: {
'/mainMenu': (context) => const MainMenu(),
'/game': (context) => const MyHomePage(title: 'game'),
},
initialRoute: '/mainMenu',
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late List<Rect> _playerTracks;
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
print(_playerTracks.length);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
color: Colors.white,
margin: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: SizedBox.expand(
child: CustomPaint(
painter: RectanglePainter(
trackCalculationListener: (playerTracks) =>
_playerTracks = playerTracks),
),
),
),
)
],
),
),
);
}
}
class MainMenu extends StatefulWidget {
static String route = '/mainMenu';
const MainMenu({super.key});
#override
State<MainMenu> createState() => _MainMenuState();
}
class _MainMenuState extends State<MainMenu> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
height: 200.0,
color: Colors.white,
child: ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/game');
},
child: const Text('play game'),
),
),
),
);
}
}
class RectanglePainter extends CustomPainter {
Function(List<Rect>) trackCalculationListener;
RectanglePainter({required this.trackCalculationListener});
#override
void paint(Canvas canvas, Size size) {
final Rect rect = Offset.zero & size;
const RadialGradient gradient = RadialGradient(
center: Alignment(0.7, -0.6),
radius: 0.2,
colors: <Color>[Color(0xFFFFFF00), Color(0xFF0099FF)],
stops: <double>[0.4, 1.0],
);
canvas.drawRect(
rect,
Paint()..shader = gradient.createShader(rect),
);
List<Rect> _playerTracks = [];
_playerTracks.add(rect);
trackCalculationListener(_playerTracks);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
I am very new to flutter and would highly appreciate if someone could help me figure out what I am doing wrong here.
Hero animation is the best for navigating between screen, but I need same animation between widgets. Like one card moving another place for example: Product Card moves to shoppingcart and something else. Thanks for answers!
Try this one, add_to_cart_animation:
import 'package:add_to_cart_animation/add_to_cart_animation.dart';
import 'package:add_to_cart_animation/add_to_cart_icon.dart';
import 'package:flutter/material.dart';
import 'list_item.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Add To Cart Animation',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Add To Cart Animation'),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// We can detech the location of the card by this GlobalKey<CartIconKey>
GlobalKey<CartIconKey> gkCart = GlobalKey<CartIconKey>();
late Function(GlobalKey) runAddToCardAnimation;
var _cartQuantityItems = 0;
#override
Widget build(BuildContext context) {
return AddToCartAnimation(
// To send the library the location of the Cart icon
gkCart: gkCart,
rotation: true,
dragToCardCurve: Curves.easeIn,
dragToCardDuration: const Duration(milliseconds: 1000),
previewCurve: Curves.linearToEaseOut,
previewDuration: const Duration(milliseconds: 500),
previewHeight: 30,
previewWidth: 30,
opacity: 0.85,
initiaJump: false,
receiveCreateAddToCardAnimationMethod: (addToCardAnimationMethod) {
// You can run the animation by addToCardAnimationMethod, just pass trough the the global key of the image as parameter
this.runAddToCardAnimation = addToCardAnimationMethod;
},
child: Scaffold(
appBar: AppBar(
title: Text(widget.title),
centerTitle: false,
actions: [
// Improvement/Suggestion 4.4 -> Adding 'clear-cart-button'
IconButton(
icon: Icon(Icons.cleaning_services),
onPressed: () {
_cartQuantityItems = 0;
gkCart.currentState!.runClearCartAnimation();
},
),
SizedBox(width: 16),
AddToCartIcon(
key: gkCart,
icon: Icon(Icons.shopping_cart),
colorBadge: Colors.red,
),
SizedBox(
width: 16,
)
],
),
body: ListView(
children: [
AppListItem(onClick: listClick, index: 1),
AppListItem(onClick: listClick, index: 2),
AppListItem(onClick: listClick, index: 3),
AppListItem(onClick: listClick, index: 4),
AppListItem(onClick: listClick, index: 5),
AppListItem(onClick: listClick, index: 6),
AppListItem(onClick: listClick, index: 7),
],
),
),
);
}
// Improvement/Suggestion 4.4 -> Running AddTOCartAnimation BEFORE runCArtAnimation
void listClick(GlobalKey gkImageContainer) async {
await runAddToCardAnimation(gkImageContainer);
await gkCart.currentState!.runCartAnimation((++_cartQuantityItems).toString());
}
}
OR
[not null safety]
this is a sample of add to cart, add_cart_parabola:
import 'dart:ui';
import 'package:add_cart_parabola/add_cart_parabola.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
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;
GlobalKey floatKey = GlobalKey();
GlobalKey rootKey = GlobalKey();
Offset floatOffset ;
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_){
RenderBox renderBox = floatKey.currentContext.findRenderObject();
floatOffset = renderBox.localToGlobal(Offset.zero);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
key: rootKey,
width: double.infinity,
height: double.infinity,
color: Colors.grey,
child: ListView(
children: List.generate(40, (index){
return generateItem(index);
}).toList(),
),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.yellow,
key: floatKey,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
Widget generateItem(int index){
Text text = Text("item $index",style: TextStyle(fontSize:
25),);
Offset temp;
return GestureDetector(
onPanDown: (details){
temp = new Offset(details.globalPosition.dx, details.globalPosition
.dy);
},
onTap: (){
Function callback ;
setState(() {
OverlayEntry entry = OverlayEntry(
builder: (ctx){
return ParabolaAnimateWidget(rootKey,temp,floatOffset,
Icon(Icons.cancel,color: Colors.greenAccent,),callback,);
}
);
callback = (status){
if(status == AnimationStatus.completed){
entry?.remove();
}
};
Overlay.of(rootKey.currentContext).insert(entry);
});
},
child: Container(
color: Colors.orange,
child: text,
),
);
}
}
For animating widget in the same screen you can use AnimatedPositioned widget see the below code
import 'dart:math';
import 'package:flutter/material.dart';
class AnimatedPositionedDemo extends StatefulWidget {
const AnimatedPositionedDemo({Key? key}) : super(key: key);
static String routeName = 'animated_positioned';
#override
_AnimatedPositionedDemoState createState() => _AnimatedPositionedDemoState();
}
class _AnimatedPositionedDemoState extends State<AnimatedPositionedDemo> {
late double topPosition;
late double leftPosition;
double generateTopPosition(double top) => Random().nextDouble() * top;
double generateLeftPosition(double left) => Random().nextDouble() * left;
#override
void initState() {
super.initState();
topPosition = generateTopPosition(30);
leftPosition = generateLeftPosition(30);
}
void changePosition(double top, double left) {
setState(() {
topPosition = generateTopPosition(top);
leftPosition = generateLeftPosition(left);
});
}
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
final appBar = AppBar(title: const Text('AnimatedPositioned'));
final topPadding = MediaQuery.of(context).padding.top;
// AnimatedPositioned animates changes to a widget's position within a Stack
return Scaffold(
appBar: appBar,
body: SizedBox(
height: size.height,
width: size.width,
child: Stack(
children: [
AnimatedPositioned(
top: topPosition,
left: leftPosition,
duration: const Duration(seconds: 1),
child: InkWell(
onTap: () => changePosition(
size.height -
(appBar.preferredSize.height + topPadding + 50),
size.width - 150),
child: Container(
alignment: Alignment.center,
width: 150,
height: 50,
child: Text(
'Click Me',
style: TextStyle(
color:
Theme.of(context).buttonTheme.colorScheme!.onPrimary,
),
),
color: Theme.of(context).primaryColor,
),
),
),
],
),
),
);
}
}
I hope it works for you
For Animated widgets, flutter team has provided a video on youtube here
And you can read all about them on their website here
Here, I have two files dot_indicator.dart and main.dart.
The function which is inside the Dots class "updatePosition()", how can it be accessed inside the onPageChanged of the PageView widget.
import 'package:flutter/material.dart';
import 'package:dots_indicator/dots_indicator.dart';
class Dots extends StatefulWidget {
#override
_DotsState createState() => _DotsState();
}
class _DotsState extends State<Dots> {
final _totalDots = 2;
double currentPosition = 0.0;
double validPosition(double position) {
if (position >= _totalDots) return 0;
if (position < 0) return _totalDots - 1.0;
return position;
}
void updatePosition(double position) {
setState(() => currentPosition = validPosition(position));
}
String getCurrentPositionPretty() {
return (currentPosition + 1.0).toStringAsPrecision(2);
}
#override
Widget build(BuildContext context) {
return DotsIndicator(
dotsCount: _totalDots,
position: currentPosition,
decorator: DotsDecorator(
activeColor: Colors.green,
activeSize: Size.square(30.0),
activeShape: RoundedRectangleBorder(),
),
);
}
}
This widget had the function updatePosition(index), I want to access it in another class.
import 'package:flutter/material.dart';
import 'package:mobile_app/bottom_nav.dart';
import 'package:mobile_app/dot_indicator.dart';
import 'package:mobile_app/first_page.dart';
import 'package:mobile_app/second_page.dart';
import 'package:provider/provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
backgroundColor: Color.fromRGBO(250, 250, 250, 100),
elevation: 0.0,
title: Stack(
children: <Widget>[
Container(
width: double.infinity,
child: Dots(),
),
],
),
),
body: PageSlider(),
bottomNavigationBar: AppBottomNav(),
),
);
}
}
class PageSlider extends StatefulWidget {
const PageSlider({Key? key}) : super(key: key);
#override
_PageSliderState createState() => _PageSliderState();
}
class _PageSliderState extends State<PageSlider> {
Dots _dots = new Dots();
#override
Widget build(BuildContext context) {
PageController controller = PageController(initialPage: 0, keepPage: true);
return PageView(
controller: controller,
onPageChanged: (index) => {
print(index),
//I want the updatePosition(index) here
},
children: <Widget>[
FirstPage(),
SecondPage(),
],
);
}
}
I tried making the instance of the Dots class and tried to use it inside the PageSlider class, it still wont work.
I'm using ListView with simple containers, when you press container in list view it changes selected container width and colour of border, however when this happens it also moves other containers below. What I would like to get is when you select item, change the width and colour of border and don't move items in list as well as items inside of the container.
Please use code below to reproduce the problem, thanks!
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter border demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
}
List<int> values = [1, 2, 3];
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Border demo'),
centerTitle: true,
),
body: Container(
child: ListView.builder(
itemCount: values.length,
itemBuilder: (BuildContext context, int index) =>
BorderContainer(value: values[index])),
));
}
}
class BorderContainer extends StatefulWidget {
final int value;
const BorderContainer({Key key, this.value}) : super(key: key);
#override
_BorderContainerState createState() => _BorderContainerState();
}
class _BorderContainerState extends State<BorderContainer> {
bool isTapped = false;
#override
Widget build(BuildContext context) {
return Container(
// height: 95, // if we add this rest of list items will not move however it will move items inside of container
child: GestureDetector(
onTapDown: (TapDownDetails details) => setState(() {
isTapped = true;
}),
onTapUp: (TapUpDetails details) => setState(() {
isTapped = false;
}),
child: Container(
margin: EdgeInsets.all(8),
decoration: BoxDecoration(
border: Border.all(
width: isTapped ? 2.0 : 1.0,
//when pressing it moves other items because of width change
color:
isTapped ? Colors.grey : Colors.grey.withOpacity(0.3)),
borderRadius: BorderRadius.circular(16)),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
Text('${widget.value}'),
Text('Another item in container number: ${widget.value}')
],
),
)),
),
);
}
}
Okay i solved it following way: create extra container with thicker border above container with smaller border and only change colour opacity.
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter border demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
}
List<int> values = [1, 2, 3];
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Border demo'),
centerTitle: true,
),
body: Container(
child: ListView.builder(
itemCount: values.length,
itemBuilder: (BuildContext context, int index) =>
BorderContainer(value: values[index])),
));
}
}
class BorderContainer extends StatefulWidget {
final int value;
const BorderContainer({Key key, this.value}) : super(key: key);
#override
_BorderContainerState createState() => _BorderContainerState();
}
class _BorderContainerState extends State<BorderContainer> {
bool isTapped = false;
#override
Widget build(BuildContext context) {
var innerBorder = Border.all(
width: 1.0,
color: isTapped
? Colors.grey.withOpacity(0)
: Colors.grey.withOpacity(0.3));
var outerBorder = Border.all(
width: 3.0, color: isTapped ? Colors.grey : Colors.grey.withOpacity(0));
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
border: outerBorder, borderRadius: BorderRadius.circular(16)),
child: GestureDetector(
onTapDown: (TapDownDetails details) => setState(() {
isTapped = true;
}),
onTapUp: (TapUpDetails details) => setState(() {
isTapped = false;
}),
child: Container(
decoration: BoxDecoration(
border: innerBorder, borderRadius: BorderRadius.circular(16)),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
Text('${widget.value}'),
Text('Another item in container number: ${widget.value}')
],
),
)),
),
),
);
}
}
I have a two-page app. On-Page One I am showing an UUID which changes every 1 second. It is shown using listview. Once the user clicks on the list view it goes to the second page and shows the data on that card.
It should have been the changing UUID. but the data shown is static UUID. How I can pass the data changed on page 1 to page 2?
import 'dart:async';
import 'package:uuid/uuid.dart';
import 'package:uuid/uuid_util.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
List<EuropeanCountries> europeanCountries = [];
class EuropeanCountries {
String myText;
String myUuid;
EuropeanCountries({
this.myText,
this.myUuid,
});
}
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;
int _perPage = 50;
ScrollController _myScrollController = ScrollController();
void _incrementCounter() async {
const ThreeSec = const Duration(seconds: 1);
this._counter++;
europeanCountries.insert(
0,
EuropeanCountries(
myText: this._counter.toString(),
));
print(europeanCountries[0].myText);
setState(() {});
}
void getMoreData() {
print('adding More Product ');
europeanCountries.add(EuropeanCountries(
myText: this._counter.toString(),
));
//europeanCountries.insert(0, EuropeanCountries(myText:this._counter.toString(), myButtonText: "", myColor: Colors.blue));
setState(() {});
}
void generateUUID() async {
var uuid = Uuid();
for (int i = 0; i < 6000; i++) {
await new Future.delayed(new Duration(milliseconds: 1000));
for (EuropeanCountries currCountry in europeanCountries) {
currCountry.myUuid = uuid.v1();
}
setState(() {});
}
}
#override
void initState() {
// TODO: implement initState
super.initState();
generateUUID();
_myScrollController.addListener(() {
double maxscroll = _myScrollController.position.maxScrollExtent;
double currentScroll = _myScrollController.position.pixels;
double delta = MediaQuery.of(context).size.height * 0.25;
print("mac Scroll Controller - " + maxscroll.toString());
print("Current Scroll Controller - " + currentScroll.toString());
print("delta Scroll Controller - " + delta.toString());
if ((maxscroll - currentScroll) < delta) {
getMoreData();
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: _myListView(context),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
Widget _myListView(BuildContext context) {
// backing data
return Container(
child: europeanCountries.length == 0
? Center(
child: Text('No Product to Display'),
)
: ListView.builder(
controller: _myScrollController,
itemCount: europeanCountries.length,
reverse: false,
itemBuilder: (context, index) {
return myContainer(index: index);
},
),
);
}
}
class myContainer extends StatefulWidget {
final int index;
const myContainer({Key key, this.index}) : super(key: key);
#override
_myContainerState createState() => _myContainerState();
}
class _myContainerState extends State<myContainer> {
#override
Widget build(BuildContext context) {
return Container(
height: 120,
decoration: BoxDecoration(
border: Border.all(color: Colors.blue[700]),
shape: BoxShape.rectangle,
borderRadius: BorderRadius.all(Radius.circular(8)),
),
margin: EdgeInsets.all(20),
child: Column(
children: <Widget>[
Text(europeanCountries[widget.index].myText),
SizedBox(
height: 15,
),
RaisedButton(
child: Text('Detail'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondRoute(
myCountry: europeanCountries[widget.index],
)),
);
},
color: Colors.blue[700],
textColor: Colors.white,
padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
splashColor: Colors.black,
),
Text(europeanCountries[widget.index].myUuid != null
? europeanCountries[widget.index].myUuid
: 'Default')
],
),
);
}
}
class SecondRoute extends StatefulWidget {
final EuropeanCountries myCountry;
const SecondRoute({Key key, this.myCountry}) : super(key: key);
#override
_SecondRouteState createState() => _SecondRouteState();
}
class _SecondRouteState extends State<SecondRoute> {
#override
void didUpdateWidget(SecondRoute oldWidget) {
// TODO: implement didUpdateWidget
super.didUpdateWidget(oldWidget);
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: Text(widget.myCountry.myUuid != null
? widget.myCountry.myText
: 'default'),
),
SizedBox(height: 15),
Center(
child: Text(widget.myCountry.myUuid != null
? widget.myCountry.myUuid
: 'default'),
),
],
),
),
),
);
}
}
https://imgur.com/VqRfcZY
<blockquote class="imgur-embed-pub" lang="en" data-id="VqRfcZY"></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script>