본문 바로가기
Dart/Flutter

[Flutter] 플러터 GetX에서 Hero 위젯 사용하기

by 검은냥냥이 2022. 12. 30.

플러터에서 GetX에서 Hero를 사용하려면, 제대로 작동이 안 되는 것을 볼 수 있습니다. 해당 이미지가 Init 시점보다 먼저와 야하기 때문인데요. GetX 패턴을 사용하다 보면 사실상 사용하기가 까다롭다고 볼 수 있습니다. 그래서 GetX에서 사용할 수 있는 방법을 소개합니다.

 

예시

class ListWidget extends GetView<ListController> {
  const ListWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: List.generate(
        controller.data.length,
        (index) {
          return CardWidget(index: index);
        },
      ),
    );
  }
}

class CardWidget extends GetView<ListController> {
  const CardWidget({
    super.key,
    required this.index,
  });

  final int index;

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: () {
        // 페이지 이동과 동시에 Argument 전달
         Get.toNamed(
          '/list/$index',
          arguments: {
            'image': controller.data[index].image,
          },
        );
      },
      child: SizedBox(
        width: 320,
        height: 160,
        child: Card(
          child: Hero(
            tag: 'card_$index',
            child: Image.network(
              controller.data[index].image,
              fit: BoxFit.cover,
            ),
          ),
        ),
      ),
    );
  }
}

먼저, 리스트가 있는 페이지라고 가정하고 해당 리스트 박스에는 `Hero`를 감싼 이미지가 있습니다. 카드 위젯을 클릭하면, 다음 상세 화면으로 이동하면서 `Arguments`에 리스트에서 받았던 이미지를 같이 전달합니다.

받는 쪽은 `Arguments`에서 받은 이미지를 뷰단에 먼저 보여주면 됩니다. 여기서 `Hero`를 감싼 이미지 위젯은 데이터를 받는 과정인 로딩화면을 분기해서 `Obx`를 걸거나 그러면 안 됩니다.

컨트롤러에 `Init`보다 `Arguments` 값이 먼저 도달하고, 변수를 통하여 뷰단에 로딩 인디케이터를 이미지 위젯 아래쪽에 걸어주셔야 합니다. (화면이 바뀌면 안 됨)

 

class ListDetailWidget extends GetView<ListDetailController> {
  const ListDetailWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        /// 데이터를 받기 이전에 로딩 인디케이터를 노출하는 부분
        SizedBox(
          width: 320,
          height: 160,
          child: Card(
            child: Hero(
              tag: 'card_${controller.arguments['id']}',
              child: Image.network(
                controller.arguments['image'],
                fit: BoxFit.cover,
              ),
            ),
          ),
        ),

        /// 데이터를 받아 로딩 인디케이터를 분기하는 부분
        controller.isLoad.value
            ? const CircularProgressIndicator()
            : const Text(
              '데이터를 외부에서 받아 노출하는 부분',
            ),
      ],
    );
  }
}

위처럼 데이터를 받아 처리하는 곳과 아규먼트로 받는 이미지 구간을 나눠서 해주면, `Hero` 위젯이 정상 작동할 것입니다.

물론, 로딩인디케이터를 안 달았다고 해서 데이터를 받아서 처리하는 것도 `Hero` 작동이 되지 않습니다. 컨트롤러 주입시점과 `Init` 시점 문제가 있기 때문입니다.

 

작동영상

플러터 Hero 적용 샘플 영상

 

728x90
사업자 정보 표시
레플라 | 홍대기 | 경기도 부천시 부일로 519 화신오피스텔 1404호 | 사업자 등록번호 : 726-04-01977 | TEL : 070-8800-6071 | Mail : support@reafla.co.kr | 통신판매신고번호 : 호 | 사이버몰의 이용약관 바로가기