I am creating a gridview of images using future but during scrolling of gridview app crashes and there is not error but just
Lost connection to device.
Exited (sigterm)
the images reappear and disappear when scrolling up and down .
i have tried using image.network , cached network image , fadein image but not working . i have also limit my image request to 40 but also it crashes . image size are only 20-100 kb range .
// future function to load subcategory json
Future<subcategory> fetchallsubcategory() async {
final path = (await getApplicationDocumentsDirectory()).path;
final myDataResource = HttpNetworkResource(
url: serverurl +
"classes/subCategory?limit=40",
parser: (contents) => json.decode(contents),
headers: header,
cache: FileResource(File('$path/subcategoryall.json')),
maxAge: Duration(minutes: 10),
strategy: CacheStrategy.cacheFirst,
);
final myData = await myDataResource.get();
return subcategory.fromJson(myData);
}
//grid view
FutureBuilder(
future: fetchallsubcategory(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
return snapshot.hasData ? GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2),
itemCount: snapshot.data.results.length,
// padding: EdgeInsets.all(2.0),
// scrollDirection: Axis.horizontal,
itemBuilder: (context, int) {
return Card(
child:
CachedNetworkImage(imageUrl : snapshot.data.results[int].image),
);
}
) :CircularProgressIndicator();
},
)
I have created the same kind of app. I found NeverScrollableScrollPhysics() very helpful for scrollable image gridview. I hope the following code snippet helps you.
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Column(
children: <Widget>[
ConstrainedBox(
constraints: BoxConstraints(
minHeight: 10, // Set as you want or you can remove it also.
maxHeight: double.infinity,
),
child: Container(
child: GridView.count(
crossAxisCount:
MediaQuery.of(context).orientation == Orientation.portrait
? 3
: 4,
shrinkWrap: true,
scrollDirection: Axis.vertical,
physics: NeverScrollableScrollPhysics(),
childAspectRatio: .6,
children: thumbUrls
.map((urlThumb) => Card(
child: Container(
decoration: BoxDecoration(color: Colors.white),
child: GestureDetector(
onTap: () => Navigator.push(context,
new MaterialPageRoute(
builder: (context) {
return new FullScreenImagePage(wallpapers[urlThumb]);//Map wallpaper = {url_thumb : [id, url_image]}
})),
child: new Image.network(
urlThumb,
fit: BoxFit.cover,
),
)),
))
.toList(),
),
),
)
],
),
],
);
}
}
Related
I have been trying to add drag/drop support to my app, currently what I have come with is using this library:
reorderable_grid_view
I used this example code:
code link
The reason I used this library is that it's smooth enough of animations when dragging. But what I want to do is to drag one item to another so that I can merge the one to another object when I drop. (It's like in Android/iOS home screen where you can drag apps to folders or drag into another that it creates a folder)
I have searched all the site but couldn't come across with such thing, only drag/drop libraries are available. Can anyone help me on this?
Thanks in advance.
class MyHomePage extends StatelessWidget {
MyHomePage({super.key});
final ValueNotifier<List<ValueNotifier<List<Widget>>>> items = ValueNotifier([
ValueNotifier([Text("A")]),
ValueNotifier([Text("B")]),
ValueNotifier([Text("C")]),
ValueNotifier([Text("D")]),
]);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 20.0),
child: ValueListenableBuilder(
valueListenable: items,
builder: (BuildContext context, List<ValueNotifier<List<Widget>>> folders, Widget? child) {
return GridView.builder(
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemCount: folders.length,
itemBuilder: (context, index) {
ValueNotifier<List<Widget>> item = folders[index];
return LongPressDraggable(
delay: const Duration(milliseconds: 500),
feedback: SizedBox(width: MediaQuery.of(context).size.width / 4, height: MediaQuery.of(context).size.width / 4, child: FittedBox(child: Icon(Icons.folder))),
data: index,
childWhenDragging: const SizedBox(),
child: DragTarget(
onAccept: (data) {
List<Widget> alreadyHaved = item.value;
alreadyHaved.addAll(folders[data as int].value);
item.value = alreadyHaved;
items.value.removeAt(data);
items.notifyListeners();
},
builder: (context, candidateData, rejectedData) {
return ValueListenableBuilder(
valueListenable: item,
builder: (BuildContext context, List<Widget> boxValues, Widget? child) {
return Stack(children: [
const Positioned.fill(
child: FittedBox(
child: Icon(
Icons.folder,
color: Colors.amber,
))),
Positioned.fill(
child: LayoutBuilder(
builder: (p0, p1) => SizedBox(
height: p1.maxHeight * .7,
width: p1.maxWidth * .7,
child: Center(
child: Wrap(
children: boxValues,
),
))),
)
]);
},
);
},
),
);
});
},
),
),
),
],
),
);
}
}
I'm creating a chat feature in flutter but noticed this behavior on IOS that doesnt shrink the list so you can see the last sent message. How can I have the listview builder shrink to show the last message when the keyboard appears?
Note: This issue doesn't happen on Android
Scaffold(
resizeToAvoidBottomInset: true,
body: Stack(
children: <Widget>[
StreamBuilder(
stream: _chats,
builder: (context, snapshot) {
if (!snapshot.hasData) return Container();
return snapshot.hasData
? GestureDetector(
onPanDown: (_) {
FocusScope.of(context).requestFocus(FocusNode());
},
child: ListView.builder(
shrinkWrap: true,
controller: _scrollController,
padding: EdgeInsets.only(top: 10, bottom: 100),
itemCount: snapshot.data.docs.length,
itemBuilder: (context, index) {
return MessageWidget(
tripId: widget.docId,
uid: snapshot.data.docs[index].data()["uid"],
messageId: snapshot.data.docs[index].id,
message: snapshot.data.docs[index].data()["message"],
sender: snapshot.data.docs[index].data()["senderName"],
sentByMe: widget.uid ==
snapshot.data.docs[index].data()["uid"],
mediaFileUrl:
snapshot.data.docs[index].data()["mediaFileUrl"],
);
}),
)
: Container();
},
);
]
)
)
I think you can try the 'reverse' property from the ListView.builder.
Tell me if this example didn't fit your needs, can you share us your code ? (I didn't see why you use a Stack and what could be the issue around that).
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Expanded(
child: Stack(
children: <Widget>[
StreamBuilder<dynamic>(
builder: (context, dynamic snapshot) {
return GestureDetector(
onPanDown: (_) {
FocusScope.of(context).unfocus();
},
child: ListView.builder(
reverse: true,
shrinkWrap: true,
itemCount: 100,
padding: const EdgeInsets.only(top: 10, bottom: 10),
itemBuilder: (context, index) {
return ListTile(title: Text(index.toString()));
},
),
);
},
),
],
),
),
Container(
padding: const EdgeInsets.all(8),
color: Colors.black12,
child: const TextField(),
),
],
),
);
}
}
I am using an API to build a movies application, I had a problem with making theListView to be from left to right instead of up and dowm.I am trying to create a horizontal list view but it displayed not as expected. You can see how it looks in the Image bellow. It works with me usually but it my first time to do that inside a listview builder. How to fix that?
Note: I want the full screen to be vertical and this part only horizontal.
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child:
FutureBuilder(
future: getData(),
builder: (BuildContext context,AsyncSnapshot snapshot){
if(snapshot.data == null){
return Container(
child: Center(
child:CircularProgressIndicator() ,),);
}
else{
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context,int i){
if(snapshot.data==null){
return Center(
child: CircularProgressIndicator(),
);
}
else{
return Container(
height: 250,
child: Card(
child: ListView(
scrollDirection: Axis.horizontal,
children: [
Image(image: NetworkImage(snapshot.data[i].poster))
],
),
),
);
}}
);
}
}
,),
),
);
}
}
Image
You can use scrollDirection: Axis.horizontal,
inside the Listview.Builder to make it scroll horizontally and add a width for the container that's being returned.
Try below code hope its helpful to you . declare your ListView.builder() like below refer Listview here
Container(
width: double.infinity,
height: 180,
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: 10,
itemBuilder: (BuildContext context, int i) {
return Container(
height: 50,
child: Card(
child: Image.network(
'https://tech.pelmorex.com/wp-content/uploads/2020/10/flutter.png',
),
),
);
},
),
),
Your result screen->
I have checkbox for selecting and deselecting photos.
There is a visible loading screen for each tap.
_mediaList has the photo asset. mediaModel has the necessary methods to add and remove the path of selected and deselected photos respectively.
Widget build(BuildContext context) {
super.build(context);
return GridView.builder(
itemCount: _mediaList.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, mainAxisSpacing: 4.0, crossAxisSpacing: 4.0),
itemBuilder: (BuildContext context, int index) {
final saved = mediaModel.getMedia().contains(
_mediaList[index].relativePath + '/' + _mediaList[index].title);
return FutureBuilder(
future: _mediaList[index].thumbDataWithSize(200, 200),
builder: (BuildContext context, snapshot) => snapshot.hasData
? GridTile(
header: saved
? Icon(Icons.check_circle, color: Colors.white,)
: Icon(Icons.check_circle_outline, color: Colors.white,),
child: GestureDetector(
child: Image.memory(
snapshot.data,
fit: BoxFit.cover,
),
onTap: () => setState(() => saved
? mediaModel.removeMedia(
_mediaList[index].relativePath +
'/' +
_mediaList[index].title)
: mediaModel.addMedia(
_mediaList[index].relativePath +
'/' +
_mediaList[index].title))),
)
: Container());
},
);
}
EDIT: After some analysis, I found out using Provider to load images might be the right way.
Can you help me in converting this code to Provider?
Thanks in advance!!!
Screenshot:
Full code:
class FooPage extends State<SoPage> {
static const int _count = 10;
final List<bool> _checks = List.generate(_count, (_) => false);
#override
Widget build(BuildContext context) {
return Scaffold(
body: GridView.builder(
itemCount: _count,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemBuilder: (_, i) {
return Stack(
children: [
Container(color: Colors.red[(i * 100) % 900]),
Align(
alignment: Alignment.topCenter,
child: Checkbox(
value: _checks[i],
onChanged: (newValue) => setState(() => _checks[i] = newValue),
),
),
],
);
},
),
);
}
}
I display many images in a Staggered Gridview in a Flutter application.
Everytime I call setState({}), for example after deleting an item, the page jumps to top. How could I remove this behavior?
This is my code:
final _scaffoldKey = new GlobalKey<ScaffoldState>();
.. outside the build function. And then...
return loadingScreen == true
? LoadingScreen()
: Scaffold(
key: _scaffoldKey,
body: CustomScrollView(
slivers: <Widget>[
_AppBar(
theme: theme,
index: index,
albumImagePath: albumImagePath,
albumID: albumID,
albumValue: albumValue,
addPictureToGallery: _addPictureToGallery,
),
SliverToBoxAdapter(
child: Column(
children: <Widget>[
InfoBar(
albumPicturesSum: albumPicturesSum,
getBilderString: _getBilderString,
theme: theme,
getVideoProgress: _getVideoProgress,
progress: progress,
),
albumID == 99999999
? // Demo Projekt
DemoImageGrid(
demoImageList: demoImageList,
getDemoImagesJson: _getDemoImagesJson,
)
: UserImageGrid(
picturesData: picturesData,
albumID: albumID,
showPictureActions: _showPictureActions)
],
),
)
],
),
);
}
The UserImageGrid looks like the following:
class UserImageGrid extends StatelessWidget {
final Pictures picturesData;
final int albumID;
final Function showPictureActions;
final _key = new UniqueKey();
UserImageGrid(
{#required this.picturesData,
#required this.albumID,
#required this.showPictureActions});
#override
Widget build(BuildContext context) {
return FutureBuilder(
key: _key,
future: picturesData.getPicturesFromAlbum(albumID),
builder: (BuildContext context, AsyncSnapshot snapshot) {
// Normale Projekte
if (snapshot.hasData && snapshot.data.length == 0) {
return Center(
child: Column(
children: <Widget>[
Lottie.asset('assets/lottie/drone.json',
width: 250,
options: LottieOptions(enableMergePaths: false)),
],
),
);
}
if (!snapshot.hasData ||
snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else {
return Container(
child: StaggeredGridView.countBuilder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.all(0),
crossAxisCount: 6,
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) =>
GestureDetector(
onLongPress: () {
showPictureActions(snapshot.data[index]);
},
onTap: () async {
await showDialog(
context: context,
builder: (_) {
return Dialog(
child: Stack(
children: [
Container(
margin: const EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 10.0,
),
height: 500.0,
child: ClipRect(
child: PhotoView(
maxScale:
PhotoViewComputedScale.covered * 2.0,
minScale:
PhotoViewComputedScale.contained *
0.8,
initialScale:
PhotoViewComputedScale.covered,
imageProvider: FileImage(
File(snapshot.data[index].path))),
),
),
Positioned(
bottom: 20,
left: 20,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
DateFormat(tr("date_format")).format(
snapshot.data[index].timestamp
.toDateTime()),
style: TextStyle(color: Colors.white),
),
),
)
],
));
});
},
child: Container(
child: Image.file(
File(snapshot.data[index].thumbPath),
fit: BoxFit.cover,
)),
),
staggeredTileBuilder: (int index) =>
new StaggeredTile.count(2, index.isEven ? 2 : 2),
mainAxisSpacing: 5.0,
crossAxisSpacing: 5.0,
),
);
}
});
}
}
What could be the issue?
I found a solution for this issue. The problem was not the setState({}). It was the return Widget of the FutureBuilder.
I changed
if (!snapshot.hasData || snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
to:
if (!snapshot.hasData || snapshot.connectionState == ConnectionState.waiting) {
return Container(
height: MediaQuery.of(context).size.height,
);
}
I donĀ“t exactly know why, but with this change the page is not jumping to top anymore on setState({})