Reputation: 343
I am trying to create a custom image picker that looks something like this:
As you can see the images are capped at a set height however maintain their aspect ratio (i.e. vertical images are vertical and horizontal images are horizontal). I have created the entire custom image picker. However, I'm struggling with the aspect ratio part. I'd prefer not to use a library, however, if it's easier then please provide the adjusted code.
Could you please provide a solution with code? FYI I'm using photo_manager to retrieve the images/videos.
This is what it all looks like right now:
Here is my code:
class MediaGrid extends StatefulWidget {
@override
_MediaGridState createState() => _MediaGridState();
}
class _MediaGridState extends State<MediaGrid> {
List<Widget> _mediaList = [];
int currentPage = 0;
int? lastPage;
@override
void initState() {
super.initState();
_fetchNewMedia();
}
_handleScrollEvent(ScrollNotification scroll) {
if (scroll.metrics.pixels / scroll.metrics.maxScrollExtent > 0.33) {
if (currentPage != lastPage) {
_fetchNewMedia();
}
}
}
_fetchNewMedia() async {
lastPage = currentPage;
var result = await PhotoManager.requestPermission();
if (result) {
// success
//load the album list
List<AssetPathEntity> albums =
await PhotoManager.getAssetPathList(onlyAll: true);
print(albums);
List<AssetEntity> media =
await albums[0].getAssetListPaged(currentPage, 60);
print(media);
List<Widget> temp = [];
for (var asset in media) {
temp.add(
FutureBuilder<dynamic>(
future: asset.thumbDataWithSize(300, 300),
builder: (BuildContext context, snapshot) {
if (snapshot.connectionState == ConnectionState.done)
return Stack(
children: <Widget>[
Expanded(
child: Image.memory(snapshot.data, fit: BoxFit.cover),
),
if (asset.type == AssetType.video)
Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: EdgeInsets.only(right: 5, bottom: 5),
child: Icon(
Icons.videocam_rounded,
color: Colors.white,
),
),
),
],
);
return Container();
},
),
);
}
setState(() {
_mediaList.addAll(temp);
currentPage++;
});
} else {
// fail
/// if result is fail, you can call `PhotoManager.openSetting();` to open android/ios applicaton's setting to get permission
}
}
@override
Widget build(BuildContext context) {
return NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification scroll) {
return _handleScrollEvent(scroll);
},
child: GridView.builder(
physics: NeverScrollableScrollPhysics(),
itemCount: _mediaList.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 5.0,
crossAxisSpacing: 5.0,
),
itemBuilder: (BuildContext context, int index) {
return _mediaList[index];
}),
);
}
}
Upvotes: 1
Views: 1237
Reputation: 79
You can use https://pub.dev/packages/flutter_staggered_grid_view This plugin has options to modify the aspect ratio
Upvotes: 0
Reputation: 63569
I hope this is thing you are looking for, replace container with image.
import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'dart:math' as math;
class TestScreen extends StatefulWidget {
TestScreen({Key? key}) : super(key: key);
@override
_TestScreenState createState() => _TestScreenState();
}
class _TestScreenState extends State<TestScreen> {
final _items = List.generate(
100,
(index) => ClipRRect(
borderRadius: BorderRadius.circular(
8,
),
child: Container(
height: 124,
color: Color(
(math.Random().nextDouble() * 0xFFFFFF).toInt(),
).withOpacity(1.0),
),
));
@override
Widget build(BuildContext context) {
return Container(
child: StaggeredGridView.countBuilder(
mainAxisSpacing: 2,
crossAxisSpacing: 2,
crossAxisCount: 6,
itemCount: 100,
itemBuilder: (context, index) {
return _items[index];
},
staggeredTileBuilder: (index) {
if (index % 6 == 0 || index % 6 == 3) {
return StaggeredTile.count(2, 1);
} else if (index % 6 == 1 || index % 6 == 2) {
return StaggeredTile.count(4, 1);
} else
return StaggeredTile.count(3, 1);
},
),
);
}
}
Upvotes: 1
Reputation: 2503
This idea will only work if you wish to give each image a single specified height. And using fit: BoxFit.cover
to fill up the remaining space.
Now you must find a way to get the width of each image, in my code its of Network Images
From here use the width as the flex value.
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
Future<Size> _calculateImageDimension(String url) {
Completer<Size> completer = Completer();
Image image = Image.network(url);
image.image.resolve(ImageConfiguration()).addListener(
ImageStreamListener(
(ImageInfo image, bool synchronousCall) {
var myImage = image.image;
Size size = Size(myImage.width.toDouble(), myImage.height.toDouble());
completer.complete(size);
},
),
);
return completer.future;
}
@override
Widget build(BuildContext context) {
//for odd no. of images you might have to add more conditions to your widget
final _netWorkimages = [
'https://images.pexels.com/photos/7179053/pexels-photo-7179053.jpeg?cs=srgb&dl=pexels-olya-prutskova-7179053.jpg&fm=jpg',
'https://images.pexels.com/photos/7527509/pexels-photo-7527509.jpeg?cs=srgb&dl=pexels-john-lee-7527509.jpg&fm=jpg',
'https://images.pexels.com/photos/8018591/pexels-photo-8018591.jpeg?cs=srgb&dl=pexels-inna-stellinna-8018591.jpg&fm=jpg',
'https://images.pexels.com/photos/3244513/pexels-photo-3244513.jpeg?cs=srgb&dl=pexels-andy-vu-3244513.jpg&fm=jpg',
'https://images.pexels.com/photos/694587/pexels-photo-694587.jpeg?cs=srgb&dl=pexels-samuel-silitonga-694587.jpg&fm=jpg',
'https://images.pexels.com/photos/5121986/pexels-photo-5121986.jpeg?cs=srgb&dl=pexels-marcelo-chagas-5121986.jpg&fm=jpg',
'https://images.pexels.com/photos/4519234/pexels-photo-4519234.jpeg?cs=srgb&dl=pexels-dinielle-de-veyra-4519234.jpg&fm=jpg',
'https://images.pexels.com/photos/2286385/pexels-photo-2286385.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260',
'https://images.pexels.com/photos/35629/bing-cherries-ripe-red-fruit.jpg?cs=srgb&dl=pexels-pixabay-35629.jpg&fm=jpg',
'https://images.pexels.com/photos/4033324/pexels-photo-4033324.jpeg?cs=srgb&dl=pexels-karolina-grabowska-4033324.jpg&fm=jpg'
];
List<Future<Size>> _niSizes = [];
_netWorkimages.forEach((url) {
_niSizes.add(_calculateImageDimension(url));
});
return FutureBuilder<List<Size>>(
future: Future.wait(_niSizes),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return Center(
child: CircularProgressIndicator(),
);
else
return ListView.builder(
itemCount: _netWorkimages.length - 1,
itemBuilder: (context, i) {
return i.isEven
? Container(
height: 120,
child: Row(
children: [
Flexible(
flex: snapshot.data![i].width.toInt(),
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Image(
image: NetworkImage(_netWorkimages[i]),
fit: BoxFit.cover,
height: double.infinity,
width: double.infinity,
),
)),
Flexible(
flex: snapshot.data![i + 1].width.toInt(),
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Image(
image: NetworkImage(_netWorkimages[i + 1]),
fit: BoxFit.cover,
height: double.infinity,
width: double.infinity,
),
)),
],
),
)
: SizedBox.shrink();
});
},
);
}
}
Upvotes: 1