ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Flutter - 코딩마스터하기|갤러리 레이아웃
    개발/Flutter 2021. 11. 4. 21:15
    반응형

    gallery layout 만들기

    우선 widgets 폴더에 my_gallery.dart를 만들어준다. 그리고 우선 형태를 보기 위해서 return에 GridView.count를 만들어 주고 corssAxisCount에 3, children에 List.generate를 30을 준다. 그리고 index를 활용한 (index) => Image.network('이미지주소')를 줘서 다른 30개 이미지가 표현 되게 해보면 정상적으로 실행 되는 것을 볼 수 있다.


    class MyGallery extends StatefulWidget {
      const MyGallery({Key key}) : super(key: key);
    
      @override
      _MyGalleryState createState() => _MyGalleryState();
    }
    
    class _MyGalleryState extends State<MyGallery> {
      @override
      Widget build(BuildContext context) {
        return GridView.count(
          crossAxisCount: 3,
          children:
            List.generate(
                30,
                (index) =>
                    Image.network('https://picsum.photos/id/$index/150/150')),
    
        );
      }
    }

    setup gallery access

    local image provider를 이용해서 이전에 찍어놓고 저장되어있는 파일들을 봐보자. 라이브러리를 설치하고 내부 파일을 쓰기 위해서는 권한이 필요하다. AndroidManifest.xml에 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />를 추가해 주면 된다.

     

    create gallery state object

    갤러리도 camera_state처럼 먼저 준비시킬것이다. models에 gallery_state.dart를 만들고 주고 class GalleryState extends ChangeNotifier를 만들어 준다. 그리고 LocalImageProvider _localImageProvider; bool _hasPermission; List<LocalImage> _images; 를 생성해준다. 그리고 initialize()를 사용하기 위해서 Future<bool> initProvider()를 만들어 주고 async를 해준다. _localImageProvider = LocalImageProvider(); 해주고 _hasPermission = await _localImageProvider.initialize();를 해준다. 여기서 if(_hasPermission)을 해주고 true일때 _images에 awiat _localImageProvider.findLatest(30) 으로 최근 30개 이미지를 가져온뒤 notifyListeners();로 알려준다. return true로 해주고 else에는 return false로 해준다. 그리고 다른 곳에서 사용할 수 있게 _images와 _localImageProvider를 get으로 만들어 준다.


    class GalleryState extends ChangeNotifier {
      LocalImageProvider _localImageProvider;
      bool _hasPermission;
      List<LocalImage> _images;
    
      Future<bool> initProvier() async {
        _localImageProvider = LocalImageProvider();
        _hasPermission = await _localImageProvider.initialize();
        if (_hasPermission) {
          _images = await _localImageProvider.findLatest(30); //최근 30개 이미지 가져옴
          notifyListeners();
          return true;
        } else {
          return false;
        }
      }
    
      List<LocalImage> get images => _images;
    
      LocalImageProvider get localImageProvider => _localImageProvider;
    }

    show photos from device on my gallery

    CameraState와 같이 camera_screen에 GalleryState도 미리 생성해 준다. 상단에 GalleryState _galleryState = GalleryState(); 해주고 createState안에 _galleryState.initProvider를 넣어준다. 그리고 home_page에 권한을 미리 받아온다. Platform.isIOS ? Permission.photos : Permission.storage, 를 checkIfPermissionGranted의 권한 주는 부분에 추가해주면된다. 그리고 camera_screen에 porviders 부분에 ChangeNotifierProvider<GalleryState>.value(value: widget._galleryState),를 추가해준다. 그리고 my_gallery에서 이미지를 가져오는 부분을 만들어 준다. 하단에 List<Widget> getImages(GalleryState galleryState)를 만들어 주고  return에 galleryState.images.map()으로 가져온다. map 안에 map((localImage) => Image(image: DeviceImage(localImage),)).toList()를 해줘서 리스트로 반환해주면된다. 그리고 위의 GridView에서 children에 GetImages(galleryState)를 해주면 정상적으로 보인다.


    my_gallery.dart
      List<Widget> getImages(GalleryState galleryState) {
        return galleryState.images.map((localImage) => Image(
              image: DeviceImage(localImage),
            )).toList();
      }

    localimage class to bytes to file

    갤러리에서 각 사진을 누르면 share 페이지로 가게 만들기. LocalImage에서 File로 바로 바꾸는 방법이 없어서 중간에 Byte로 바꿔서 변환해줄것임. localImage를 보면 Uint8List로 받음. 우선 이미지가 눌려지게 하기위해서 Image를 InkWell로 감싸주고 onTap에 Uint8List bytes 를 만들어 줌. 이게 또 Future 이므로 onTap에 async를 해주고 bytes = await를 해줌. awiat뒤에 localImage.getScaledImageBytes(galleryState.localImageProvider, 0.3);으로 byte로 변경해줌. localImage에서 byte로 변경했음. 이제 byte를 파일로 변경해줘야 하는데 우선 byte를 디바이스에 임시파일로 저장후 파일로 만들어 줄 것이다. 사진을 찍어서 path에 저장해준것처럼 path를 만들어 줘야함. take_photo에 _attmeptTakePhoto의 내용을 가져와서 필요한 부분만 남기고 수정해보자.


                    final String timeInMilli = DateTime.now()
                        .microsecondsSinceEpoch
                        .toString(); //1970-01-01 부터 millisecond의 시간
                    try {
                      //((await getTemporaryDirectory()).path+'$timeInMilli.png')로 만들어도 되지만 위험성이 있어서 사용x Join 추천
                      final path = join((await getTemporaryDirectory()).path,
                          '$timeInMilli.png'); //getTemporaryDirectory는 Future사용 .path로 임시저장폴더 주소, 파일명 순서로 경로임
                      File imageFile = File(path)..writeAsBytesSync(bytes);
    
                      Navigator.of(context).push(MaterialPageRoute(
                          builder: (_) => SharePostScreen(imageFile)));
                    } catch (e) {}

    위와 같이 해주면 파일을 저장하고 share screen 까지 볼 수 있다.

     

    cover available area for image

    이미지를 꽉차게 보이게 만들자. child에 Image에 fit 옵션이 있는데 여기에 BoxFit.cover을 해주면 해당 칸에 꽉차게 보이는 것을 알 수 있다. 그런데 로딩이 느리고 메모리 크래쉬가 있다. 이때 해결법은 DeviceImage에 scale를 조절 해주면 된다. 그래서 메모리 부족 현상을 해결할 수 있다.

     

     

    반응형

    댓글

Designed by Tistory.