Hello i am creating flutter app and trying to draw image and i successfully did that from below answer
This is the main answer from where i can get idea about dropping pin on tap
From this answer i am drwaing image successfully
but issue is that pin is not drawn to exact offset(x&y) position here i am attaching screen shot so you can get better idea.
Here is the screen shot please take a look at the exact issue
and here is my code from which i can get x and y position where user tapped
return Scaffold(
appBar: AppBar(
title: Text(widget.title,style: TextStyle(color: Colors.white),),
backgroundColor: Color.fromRGBO(86, 35, 127, 1),
brightness: Brightness.dark
),
body: SafeArea(
top: true,
bottom: true,
left: true,
right: true,
child: Stack(
children: [
Listener(
onPointerDown: (PointerDownEvent event) {
RenderBox referenceBox = _paintKey.currentContext.findRenderObject();
Offset offset = referenceBox.globalToLocal(event.position); // here i am getting offset where user tapped
setState(() {
_offset = offset;
isDroppedPin = true;
});
if (widget.pinNo <= 5){
}else{
Toast.show("Maximum Pin Limit Reached", context, duration: Toast.LENGTH_SHORT, gravity: Toast.BOTTOM);
}
},
child: InteractiveViewer(
minScale: 0.1,
maxScale: 3,
child: Stack(
children: [
new CustomPaint(
key: _paintKey,
painter: new MyCustomPainter(_image,_offset),
),
],
),
),
),
Positioned.fill(
child: Align(
alignment: Alignment.bottomCenter,
child: Container(
margin: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 50,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Color.fromRGBO(86, 35, 127, 1), // background
onPrimary: Colors.white,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(5)),
),// foreground
),
onPressed: () {
if (isDroppedPin == false){
Toast.show("Please Add pin", context, duration: Toast.LENGTH_SHORT, gravity: Toast.BOTTOM);
}else{
Navigator.push(context, EOBAElementFormRoute(_offset.dx.toString(),_offset.dy.toString(),widget.title,widget.pinNo,widget.image_url,widget.type,widget.drawing_id));
}
},
child: Container(
width: double.infinity,
child: Text('Next', style: TextStyle(color: Colors.white,fontSize: 17,fontWeight: FontWeight.w500),textAlign: TextAlign.center,),
),
),
),
),
)
],
),
)
);
and here is class where pin is drawing
class MyCustomPainter extends CustomPainter {
ui.Image image;
final Offset _offset;
MyCustomPainter(this.image,this._offset) : super();
#override
Future paint(Canvas canvas, Size size) async {
if (image != null) {
canvas.drawImage(image, _offset, new Paint());
}
}
#override
bool shouldRepaint(MyCustomPainter other) => other._offset != _offset;
}
can any one have idea why pin is not drawn to exact position where user tapped
Related
How do I end the drop with proper velocity to a given offset
I am trying make something similar to SlidingUpPanel, but can't figure out how to implement.
final bottom = ValueNotifier<double>(0.0);
Stack(
children: [
ValueListenableBuilder<double>(
valueListenable: bottom,
builder: (context, value, child) => Positioned(
bottom: value,
left: 0,
right: 0,
child: GestureDetector(
onVerticalDragStart: (value) {
},
onVerticalDragUpdate: (DragUpdateDetails value) {
bottom.value -= value.delta.dy;
},
onVerticalDragEnd: (value) {
const double minFlingVelocity = 365.0;
if (value.velocity.pixelsPerSecond.dy.abs() >=
minFlingVelocity) {
// bottom.value =
// MediaQuery.of(context).size.height / 2;
}
},
child: Container(
width: double.maxFinite,
height: 200,
color: Colors.green,
),
),
),
)
],
),
Sorry in advance as the issue might be something very small.
So i have got this file
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import '../utils/authentication.dart';
import '../utils/stated.dart';
import 'user_info_screen.dart';
class CategoryScreen extends StatefulWidget {
const CategoryScreen({Key? key, required User user, required Stated stated, required int intel})
: _user = user, _stated = stated, _intel = intel,
super(key: key);
final User _user;
final Stated _stated;
final int _intel;
#override
_CategoryScreenState createState() => _CategoryScreenState();
}
class _CategoryScreenState extends State<CategoryScreen> {
late User _user;
late Stated _stated;
late int _intel;
bool loaded = false;
List<Widget> rows = [];
int limit = 2;
var temporal = {};
#override
void initState() {
_user = widget._user;
_stated = widget._stated;
_intel = widget._intel;
super.initState();
}
#override
Widget build(BuildContext context) {
//print(_user.photoURL);
if (!loaded) {
print(rows.toString());
setState(() {
// Rows ==============================================================================================================
FirebaseFirestore.instance.collection('listings').where('category', isEqualTo: _stated.CATEGORIES[_intel]).orderBy('views', descending: true).limit(limit).get().then((value) {
rows.add(
Padding(
padding: EdgeInsets.only(top: 16.0, bottom: 16.0, right: 16.0, left: 16.0),
child: Text(
_stated.CATEGORIES[_intel],
style: TextStyle(
fontSize: 30,
color: Colors.white,
letterSpacing: 2,
),
),
)
);
value.docs.forEach((element) {
if (element.data()['reviewed'] == false) {
rows.add(
Container(
height: 30.0,
)
);
rows.add(
OutlineButton(
onPressed: () async {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DisplayScreen(
user: _user,
stated: _stated,
intel: element.id,
),
),
);
},
child: Column(
children: <Widget> [
Container(
height: 175.0,
width: 200,
child: Image.network(element.data()['image']['0']),
),
Container(
height: 75.0,
width: 200,
child: Padding(
padding: EdgeInsets.only(top: 10.0, bottom: 10.0, right: 16.0, left: 16.0),
child: Center(
child: Text(
element.data()['title'],
style: TextStyle(
fontSize: 15,
color: Colors.white,
letterSpacing: 2,
),
),
),
),
),
],
)
)
);
}
});
}).then((e) {
loaded = true;
print(rows.toString());
if (rows.length == limit) {
rows.add(
Container(
height: 30.0,
)
);
rows.add(
OutlineButton(
onPressed: () async {
},
child: Column(
children: <Widget> [
Container(
height: 250.0,
width: 200,
child: Padding(
padding: EdgeInsets.only(top: 10.0, bottom: 10.0, right: 16.0, left: 16.0),
child: Center(
child: Text(
'Load More',
style: TextStyle(
fontSize: 15,
color: Colors.white,
letterSpacing: 2,
),
),
),
),
),
],
)
)
);
}
});
});
// End of setState =============================================================
}
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.black,
actions: <Widget>[
ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.black),
shape: MaterialStateProperty.all(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(40),
),
),
),
onPressed: () async {
User? user =
await Authentication.signInWithGoogle(context: context);
if (user != null) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => UserInfoScreen(
user: user,
),
),
);
}
},
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 10),
child: _user.photoURL != null
? ClipOval(
child: Material(
color: Colors.black.withOpacity(0.3),
child: Image.network(
(_user.photoURL!).replaceAll("=s96-c", "=s1000-c"),
height: 50.0,
),
),
)
: ClipOval(
child: Material(
color: Colors.black.withOpacity(0.3),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Icon(
Icons.person,
size: 50,
color: Colors.grey,
),
),
),
),
),
),
],
),
body: Center(
child: ListView(
shrinkWrap: true,
padding: EdgeInsets.all(10.0),
children: rows,
),
)
);
}
}
The page loads fine without errors, however the concept of the page is that is the "Category" page for my app, the idea is that once rerouted to this page i create a listview to not leave the screen blank, and run a Firebase call to load the items, currently is set to a limit of 2 items(for testing), and i create card like containers that hold the data of the items.
Issue is that all the items in the list are stored in 'rows', and this variable is updated as i check by printing it on the console, however the page on the screen does not update.
I do believe its a common or basic thing that i am forgetting/missing because there are no errors, or probably how i am setting the list, but every time i search for this issue online no body has had this issue.
How do i make the list on screen show?
PS: as android studio is, if I press CTRL-S to save the code it also hot-reloads the simulator, and for a split second in the simulator the list shows up.
There is a lot of business logic inside the build method that blocks your UI rendering until you get the result from Firestore - this is bad and definitely not a way to go.
You should start by learning more about FutureBuilder or any state management solution on retrieving data and building the UI based on state changes. I would recommend starting from this Codelab (or any other Firestore + Flutter tutorial) just to get the idea of how to work with Firestore in Flutter: https://firebase.google.com/codelabs/firebase-get-to-know-flutter
I am creating a Journal mobile application which would work as a medium to view magazines and daily news updates. This is my first flutter project and I am totally new to flutter. So kindly excuse me if I had said something wrong about something or didnt provide enough information.
I used a code from github for the main page of my application and made few changes to accommodate my needs. Now in my code, the home page consists of a side menu bar and this bar consists of 4 buttons, namely Home, My Profile, Premium and FAQ. The GlobalKeys for the side menu bar is called using a list by the name _keys which is of the type GlobalKey. I tried changing the data type of the list _keys to Widget and then called the corresponding Widgets of the classes. But then two errors popped out.
The getter 'currentContext' isn't defined for the class 'Widget'.
The argument type 'Widget' can't be assigned to the parameter type 'GlobalKey<State>'.
Now I would like the list _keys to be of the type Widget in order for me to call upon it's corresponding widgets of Home, My Profile, Premium and FAQ from each of it's classes in order for me to view the corresponding pages. Or if it is not possible, I would love to know an alternative for it to start working.
Following is the code of my application.
import 'dart:math' as math;
import 'package:flutter/scheduler.dart';
import 'package:google_signin_example/google%20sign%20in/logged_in_widget.dart';
import 'package:google_signin_example/main app/lib/ui_3/TravelBean.dart';
import 'package:google_signin_example/main app/lib/ui_3/magazine/screens/home_screen.dart';
import 'package:google_signin_example/main%20app/lib/ui_3/FAQ/faq.dart';
import 'package:google_signin_example/main%20app/lib/ui_3/Newspaper%20and%20Kiddos/lib_kiddos/main.dart';
import 'package:google_signin_example/main%20app/lib/ui_3/Newspaper%20and%20Kiddos/lib_news/main.dart';
import 'package:google_signin_example/main%20app/lib/ui_3/premium/premium.dart';
import 'package:google_signin_example/widget/sign_up_widget.dart';
import 'detail_page.dart';
class HomePage1 extends StatefulWidget {
#override
_HomePage1State createState() => _HomePage1State();
}
class _HomePage1State extends State<HomePage1> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Container(
child: Row(
children: <Widget>[
LeftWidget(),
Expanded(
child: RightWidget(),
)
],
),
),
);
}
}
class LeftWidget extends StatefulWidget {
#override
_LeftWidgetState createState() => _LeftWidgetState();
}
class _LeftWidgetState extends State<LeftWidget> with TickerProviderStateMixin {
List<String> _list = ["Home", "My profile", "Premium", "FAQ"];
List <Widget> _keys = [
HomePage1(), //These are the widgets from different classes.
LoggedInWidget(),
premium(),
faq(),
/*GlobalKey(), //This was available before I made the changes.
GlobalKey(),
GlobalKey(),
GlobalKey()*/
];
int checkIndex = 0;
Offset checkedPositionOffset = Offset(0, 0);
Offset lastCheckOffset = Offset(0, 0);
Offset animationOffset = Offset(0, 0);
Animation _animation;
AnimationController _animationController;
#override
void initState() {
checkIndex = _list.length - 1;
super.initState();
SchedulerBinding.instance.endOfFrame.then((value) {
calcuteCheckOffset();
addAnimation();
});
}
void calcuteCheckOffset() {
lastCheckOffset = checkedPositionOffset;
RenderBox renderBox = _keys[checkIndex].currentContext.findRenderObject(); //This is where the first error occurs.
Offset widgetOffset = renderBox.localToGlobal(Offset(0, 0));
Size widgetSise = renderBox.size;
checkedPositionOffset = Offset(widgetOffset.dx + widgetSise.width,
widgetOffset.dy + widgetSise.height);
}
#override
Widget build(BuildContext context) {
return Container(
child: Stack(
children: <Widget>[
Container(
width: 50,
decoration: BoxDecoration(
color: Color(0xff000000),
borderRadius: BorderRadius.circular(30),
),
child: Column(
children: _buildList(),
),
),
Positioned(
top: animationOffset.dy,
left: animationOffset.dx,
child: CustomPaint(
painter: CheckPointPainter(Offset(10, 0)),
),
)
],
),
);
}
List<Widget> _buildList() {
List<Widget> _widget_list = [];
_widget_list.add(Padding(
padding: EdgeInsets.only(
top: 50,
),
child: Icon(
Icons.settings,
color: Colors.white,
size: 30,
),
));
for (int i = 0; i < _list.length; i++) {
_widget_list.add(Expanded(
child: GestureDetector(
onTap: () {
indexChecked(i);
},
child: VerticalText(
_list[i],
_keys[i], //This is where the second error occurs.
checkIndex == i &&
(_animationController != null &&
_animationController.isCompleted))),
));
}
_widget_list.add(Padding(
padding: EdgeInsets.only(
top: 50,
bottom: 50,
),
child: Image(image: AssetImage('assets/images/Voix.png')),
));
return _widget_list;
}
void indexChecked(int i) {
if (checkIndex == i) return;
setState(() {
checkIndex = i;
calcuteCheckOffset();
addAnimation();
});
}
void addAnimation() {
_animationController =
AnimationController(duration: Duration(milliseconds: 300), vsync: this)
..addListener(() {
setState(() {
animationOffset =
Offset(checkedPositionOffset.dx, _animation.value);
});
});
_animation = Tween(begin: lastCheckOffset.dy, end: checkedPositionOffset.dy)
.animate(CurvedAnimation(
parent: _animationController, curve: Curves.easeInOutBack));
_animationController.forward();
}
}
class CheckPointPainter extends CustomPainter {
double pointRadius = 5;
double radius = 30;
Offset offset;
CheckPointPainter(this.offset);
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()..style = PaintingStyle.fill;
double startAngle = -math.pi / 2;
double sweepAngle = math.pi;
paint.color = Color(0xff000000);
canvas.drawArc(
Rect.fromCircle(center: Offset(offset.dx, offset.dy), radius: radius),
startAngle,
sweepAngle,
false,
paint);
paint.color = Color(0xffffffff);
canvas.drawCircle(
Offset(offset.dx - pointRadius / 2, offset.dy - pointRadius / 2),
pointRadius,
paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
class VerticalText extends StatelessWidget {
String name;
bool checked;
GlobalKey globalKey;
VerticalText(this.name, this.globalKey, this.checked);
#override
Widget build(BuildContext context) {
return RotatedBox(
key: globalKey,
quarterTurns: 3,
child: Text(
name,
style: TextStyle(
color: checked ? Color(0xffffffff) : Colors.grey,
fontSize: 16,
),
),
);
}
}
class RightWidget extends StatefulWidget {
#override
_RightWidgetState createState() => _RightWidgetState();
}
class _RightWidgetState extends State<RightWidget>
with TickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: 5);
}
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(
left: 15,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 50, left: 20),
child: Text(
"Voix Home",
style: TextStyle(
color: Colors.black,
fontSize: 25,
),
),
),
Padding(
padding: const EdgeInsets.only(top: 15, left: 10),
child: SizedBox(
height: 30,
child: TabBar(
isScrollable: true,
unselectedLabelColor: Colors.black,
labelColor: Color(0xffffffff),
controller: _tabController,
indicator: BoxDecoration(
color: Color(0xff9e9e9e),
borderRadius: BorderRadius.only(
topRight: Radius.circular(20),
bottomLeft: Radius.circular(20),
),
),
tabs: <Widget>[
Tab(
text: "Flash",
),
Tab(
text: "Magazine",
),
Tab(
text: "Newspaper",
),
Tab(
text: "Kiddos",
),
Tab(
text: "Editorial",
),
],
),
),
),
Expanded(
child: TabBarView(
controller: _tabController,
children: <Widget>[
TravelWidget(),
HomeScreen(),
News(),
Kiddos(),
RightBody(),
// RightBody(),
],
),
)
],
),
);
}
}
class RightBody extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(
left: 15,
),
color: Colors.white,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.only(
top: 20,
),
child: Text(
"Flash!",
style: TextStyle(
color: Colors.black,
fontSize: 20,
),
),
),
Expanded(
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
Container(
width: 220,
margin: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(40),
image: new DecorationImage(
image: new AssetImage('assets/images/bottom1.jpg'),
fit: BoxFit.cover,
),
boxShadow: [
BoxShadow(
spreadRadius: 5,
blurRadius: 5,
offset: Offset(1, 2),
color: Color(0x33757575),
),
],
),
),
Container(
width: 220,
margin: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(40),
boxShadow: [
BoxShadow(
spreadRadius: 5,
blurRadius: 5,
offset: Offset(1, 2),
color: Color(0x33757575),
),
],
),
),
],
),
),
],
),
);
}
}
class TravelWidget extends StatelessWidget {
List<TravelBean> _list = TravelBean.generateTravelBean();
#override
Widget build(BuildContext context) {
return PageView.builder(
controller: PageController(viewportFraction: 0.9),
itemBuilder: (context, index) {
var bean = _list[index];
return GestureDetector(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return DetailPage(bean);
}));
},
child: Hero(
tag: bean.url,
child: Stack(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 30, right: 10),
child: ClipRRect(
borderRadius: BorderRadius.circular(5),
child: Image.asset(
bean.url,
width: MediaQuery.of(context).size.width,
fit: BoxFit.cover,
),
),
),
Positioned(
bottom: 80,
left: 15,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Material(
color: Colors.transparent,
child: Text(
bean.location,
style: TextStyle(
color: Colors.black54,
fontSize: 15,
),
),
),
Material(
color: Colors.transparent,
child: Text(
bean.name,
style: TextStyle(
color: Colors.black,
fontSize: 20,
),
),
),
],
),
),
Positioned(
bottom: 0,
right: 30,
child: Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(30),
),
child: Icon(
Icons.arrow_forward,
color: Colors.white,
size: 30,
),
),
)
],
),
),
);
},
itemCount: _list.length,
);
}
}
At the beginning, when I leave the list _keys to be of the type GlobalKey and don't comment out the following 4 GlobalKeys I get the output but the side menu bar won't work.
This is my application with GlobalKeys in place of those Widgets
I want those corresponding pages to display when clicked on. But that render object just switches between the options and the same page is displayed.
So kindly help me out.
PS : As said earlier I'm new to flutter, so kindly don't mistake me if I had something wrong.
I suggest you check about flutter state management, especially Mobx with Provider, it will be kind easier for you.
i need help for recreate this sample animation with flutter, i try with using showDialog() but i don't see animation, i used Hero() with tag but don'work, please help me!
it can be done using Stack, AnimatedPositioned and AnimatedContainer:
check sample code below:
import 'package:flutter/material.dart';
class MyPage extends StatefulWidget {
#override
_MyPageState createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
bool isOpen = false;
// AnimatedContainer dimensions:
double width = 55, height = 55;
// AnimatedPositioned positions:
double left = 20, bottom = 20;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
color: Color(0xff151515),
child: Stack(
children: <Widget>[
Positioned(
left: 0,
top: 0,
right: 0,
bottom: 0,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("TIMER", style: TextStyle(color: Colors.white, fontSize: 36, fontWeight: FontWeight.w700),),
Text("00 : 00", style: TextStyle(color: Colors.white, fontSize: 36, fontWeight: FontWeight.w700),),
],
),
),
Positioned(
left: 0,
top: 0,
right: 0,
bottom: 0,
child: GestureDetector(
child: AnimatedOpacity(
// If the widget is visible, animate to 0.0 (invisible).
// If the widget is hidden, animate to 1.0 (fully visible).
opacity: isOpen ? 1.0 : 0.0,
duration: Duration(milliseconds: 500),
// The green box must be a child of the AnimatedOpacity widget.
child: Container(
width: 200.0,
height: 200.0,
color: Colors.black45,
),
),
onTap: () {
if (isOpen) {
setState(() {
width = 55; height = 55;
left = 20; bottom = 20;
isOpen = false;
});
}
},
),
),
AnimatedPositioned(
left: left,
bottom: bottom,
duration: Duration(milliseconds: 500),
curve: Curves.easeInOut,
child: GestureDetector(
child: AnimatedContainer(
width: width,
height: height,
decoration: new BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(28)),
duration: Duration(milliseconds: 500),
curve: Curves.easeInOut,
// child: dialog container content goes here,
),
onTap: () {
if (!isOpen) {
setState(() {
width = 200; height = 200;
left = 60; bottom = 60;
isOpen = !isOpen;
});
}
},
),
),
Positioned(
bottom: 30,
left: 40,
child: IgnorePointer(
child: Text(
'1',
style: TextStyle(color: Colors.white, fontSize: 30),
),
),
),
],
),
),
),
);
}
}
I'm building a simple app ( some type of blog ) using just flutter no other libraries.
Now, I have Implemented an infinite scroll for new posts with GridView.count everything is working fine,
But I need to be there a message and an indicator at the end of the list to tell the user to wait to tell the new content load from the server I can't find a way to implement such a thing on my code!!
The code so far:
class _BrandsSingle extends State<BrandsSingle> {
List phones = [];
ScrollController _scrollController = new ScrollController();
int pageNumber = 1;
bool loading = false;
Future fetchPhonesByBrand(int page) async {
page = pageNumber;
loading = true;
final response = await http.get('http://192.168.1.6:3000/reviews/${widget.id}/$page');
if (response.statusCode == 200) {
setState(() {
phones.addAll(jsonDecode(response.body));
loading = false;
});
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load post');
}
}
#override
void dispose() {
_scrollController.dispose();
super.dispose();
}
#override
void initState() {
this.fetchPhonesByBrand(pageNumber);
super.initState();
_scrollController.addListener( () {
if ( _scrollController.position.pixels == _scrollController.position.maxScrollExtent ) {
pageNumber++;
print(pageNumber);
fetchPhonesByBrand(pageNumber);
}
});
}
Widget build(BuildContext context) {
// TODO: implement build
if ( loading == true ) {
return Scaffold(
appBar: AppBar(
title: Text(widget.id),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(),
SizedBox( height: 15 ),
Text(
"من فضلك أنتظر قليلاً...",
style: TextStyle(
fontSize: 20,
fontFamily: 'Mada'
),
),
],
),
),
);
}
return Scaffold(
appBar: AppBar(
title: Text(
widget.id.toUpperCase(),
style: TextStyle(
letterSpacing: 2,
fontFamily: 'Mada'
),
)
),
body: GridView.count(
controller: _scrollController,
crossAxisCount: 1,
children: List.generate(
phones.length,
(int index) {
var phone = phones[index];
return Card(
child: Ink.image(
image: NetworkImage(phone['image']),
child: InkWell(
onTap: () => Navigator.of(context).pushNamed('/phone', arguments: phone['id']),
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Color.fromRGBO(0, 0, 0, 0), Color.fromRGBO(0, 0, 0, 0.7)],
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Padding(
padding: EdgeInsets.only( bottom: 10, left: 10, right: 10 ),
child: Center(
child: Text(
'مواصفات ${phone['title'].toString().toUpperCase()}',
style: TextStyle(
fontSize: 16,
fontFamily: 'Mada',
letterSpacing: 2,
color: Colors.white,
),
),
),
),
],
),
),
),
),
);
}
),
),
);
}
}
You could add the loading as last item of your list:
The List length should be phones.length + 1
If index <= phones.length - 1 you return the Card of a normal item
Otherwise you return the loading widget
You may need to check some edge cases like:
If the list is empty
If the list height is smaller than the screen so it won't scroll
If some requests fail
If a request doesn't have more items