이번에는 선택한 이미지를 삭제할때 매번 FutureBuilder 를 통해서 이미지를 XFile -> Uint8List 로 변경해서 화면에 보여지기때문에 생기는 화면 딜레이 부분을 최적화 해보겠습니다.
개발환경 : 윈도우11, 안드로이드 스튜디오(Arctic Fox | 2020.3.1 Patch 4), flutter 3.0.1
최적화의 핵심은 언제 이미지를 XFile -> Uint8List 변경하는지 입니다.
현재는 화면에 표시할때 변환하지만, 이미지를 로딩할때로 변환 시점을 변경하면 이미지 삭제할때 딜레이 없이 바로 삭제가 가능합니다.
./src/screens/input/multi_image_select.dart - 이미지 컨버팅 시점을 변경하였습니다.
핵심 키워드(XFile.readAsBytes) - XFile 을 Uint8List 로 변경하는 방법
import 'dart:typed_data';
import 'package:extended_image/extended_image.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import '../../constants/common_size.dart';
class MultiImageSelect extends StatefulWidget {
const MultiImageSelect({Key? key}) : super(key: key);
@override
State<MultiImageSelect> createState() => _MultiImageSelectState();
}
class _MultiImageSelectState extends State<MultiImageSelect> {
bool _isPickingImages = false;
// final List<XFile> _images = [];
final List<Uint8List> _images = [];
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
Size _size = MediaQuery.of(context).size;
var imgSize = (_size.width / 3) - padding_16 * 2;
return SizedBox(
height: _size.width / 3,
// width: _size.width,
child: ListView(
// 기본 스크롤 방향을 위/아래 에서 좌/우로 변경해줌,
// 사이즈를 강제로 설정해야 함. 그래서 SizedBox 로 wrapping,
scrollDirection: Axis.horizontal,
children: <Widget>[
Padding(
// 패딩 - 여기서는 전체를 16으로 처리해서 아래는 위/아래/오른쪽만 16 처리할 것,
padding: const EdgeInsets.all(padding_16),
child: InkWell(
// onTap 에서 이미지를 List<XFile> 타입 배열에 추가,
onTap: () async {
_isPickingImages = true;
setState(() {});
final ImagePicker _picker = ImagePicker();
// Pick multiple images
final List<XFile>? images = await _picker.pickMultiImage(imageQuality: 20);
if (images != null && images.isNotEmpty) {
_images.clear();
// 이미지 컨버팅을 로딩할때 처리함,
for (int i = 0; i < images.length; i++) {
var xFile = images[i];
_images.add(await xFile.readAsBytes());
}
// _images.addAll(images);
}
_isPickingImages = false;
setState(() {});
},
child: Container(
width: imgSize,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(padding_16),
border: Border.all(color: Colors.grey, width: 1),
),
// 첫번째 사진 아이콘 부분 구현
child: _isPickingImages
? const Padding(
padding: EdgeInsets.all(padding_16 * 2),
child: CircularProgressIndicator(),
)
: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.camera_alt_rounded, color: Colors.grey),
Text('0/10', style: Theme.of(context).textTheme.subtitle2),
],
),
),
),
),
// 중복되는 사진 부분 구현
// ... 으로 시작하면 기존 리스트에 새로운 결과(List.generate 결과)를 추가할 수 있다.
...List.generate(
_images.length,
(index) => Stack(
children: [
Padding(
// 패딩 - 위에서 전체를 16으로 처리해서 여기서는 위/아래/오른쪽만 16 처리할 것,
padding: const EdgeInsets.only(
right: padding_16, top: padding_16, bottom: padding_16),
// child: ExtendedImage.network(
// 변수(메모리)에 있는 이미지를 보여주기 위해서 ExtendedImage.memory 사용하고,
// 이미지를 화면에 보여주려면 컨버팅이 필요해서 FutureBuilder 로 wrapping 필요함,
// 이미지 컨버팅을 로딩할때 처리해서 FutureBuilder 가 필요없어서 삭제함,
child: ExtendedImage.memory(
_images[index],
width: imgSize,
height: imgSize,
fit: BoxFit.cover,
// 이미지 로딩중 각 이미지별로 인디케이터 처리함,
loadStateChanged: (state) {
switch (state.extendedImageLoadState) {
case LoadState.loading:
return const Center(child: CircularProgressIndicator());
case LoadState.completed:
return null;
case LoadState.failed:
return const Icon(Icons.cancel);
}
},
// shape 을 지정해야만 borderRadius 설정이 정상 동작함,
borderRadius: BorderRadius.circular(padding_16),
shape: BoxShape.rectangle,
),
),
Positioned(
top: 0,
right: 0,
// IconButton 의 기본 사이즈는 24 이므로 패딩 8 을 더해서 40 으로 설정,
width: 40,
height: 40,
child: IconButton(
padding: const EdgeInsets.all(8),
onPressed: () {
// selectImageNotifier.removeImage(index);
debugPrint('remove picture $index');
_images.removeAt(index);
setState(() {});
},
icon: const Icon(Icons.remove_circle),
color: Colors.black54,
),
),
],
),
),
],
),
);
},
);
}
}
[여기서 잠깐만] for문을 구현하는 3가지 방법
- 첫번째 방식은 정상동작을 하지 않았습니다(디버거 걸고 여러번 테스트했으나 원인은 못찾음), 안드로이드 스튜디오 컴파일러가 오류인지 궁금합니다. 참고로 flutter 는 3.0.1 입니다.
- 두번째, 세번째 방식은 정상동작 했습니다.
images.forEach((xfile) async {
_images.add(await xfile.readAsBytes());
});
for (var xFile in images) {
_images.add(await xFile.readAsBytes());
}
for (int i = 0; i < images.length; i++) {
var xFile = images[i];
_images.add(await xFile.readAsBytes());
}
'Flutter > 12 Clone 'Used Goods app'' 카테고리의 다른 글
[Flutter] Clone - 당근마켓33(InputScreen - image picker/Getx) (0) | 2022.08.17 |
---|---|
[Flutter] Clone - 당근마켓32(ItemModel) (0) | 2022.08.12 |
[Flutter] Clone - 당근마켓30(InputScreen - image picker 구현) (0) | 2022.08.11 |
[Flutter] Clone - 당근마켓29(InputScreen - category 구현) (0) | 2022.08.11 |
[Flutter] Clone - 당근마켓28(InputScreen - layout/나머지 부분) (0) | 2022.08.10 |