Group Study (2024-2025)/Flutter

[Flutter] 8주차 스터디_FutureBuilder와 ListView 이해하기

예빙빙 2024. 11. 27. 00:05

7주차에 Data Fetching 과정을 통해 외부 데이터를 가져와보았습니다. 8주차에서는 Future 형태로 받은 데이터를 처리해서 화면에 출력해보겠습니다.


1. Future 데이터 불러오기

Future 데이터를 불러와서 보여주는 방법으로는 2가지가 존재합니다. 첫 번째로는 async/await으로 데이터를 불러오는 방법이고 두 번째로는 StatelessWidget에서 FutureBuilder를 사용하는 방법입니다.

1. async/await로 데이터 불러오기

기초적인 방법으로 Api를 연결한 함수를 불러와서 리스트 형태로 데이터를 반환 후 리스트에 저장해주고 initState()를 사용해서 업데이트 해줍니다.

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  List<WebtoonModel> webtoons = [];
  bool isLoading = true;

  void waitForWebToons() async {
    webtoons = await ApiService.getTodaysToons();
    isLoading = false;
    setState(() {});
  }

  @override
  void initState() {
    super.initState();
    waitForWebToons();
  }

2. StatelessWidget에서 FutureBuilder 위젯 사용하기

Flutter에서는 state를 잘 사용하지 않기 때문에 2번을 많이 사용합니다.

class HomeScreen extends StatelessWidget {
  HomeScreen({super.key});

  Future<List<WebtoonModel>> webtoons = ApiService.getTodaysToons();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
    	...
      ),
      body: FutureBuilder(
        future: webtoons,
        builder: (context, snapshot) {
          if (snapshot.hasData) { //데이터가 존재한다면
            return const Text("There is data!");
          }
          return const Text('Loading....');
        },
      ),
    );
  }
}
  • FutureBuilder:
    • future 와 builder 를 인자로 받아, 데이터가 로드될 때와 로드된 상태를 다르게 렌더링함
    • future : 데이터가 로드된 상태
    • builder : 데이터가 로드될 때 (대기)
  • snapshot:
    • 다양한 메소드로 데이터를 받았는지 아니면 오류가 났는지 등 상태를 알 수 있다.
    • FutureBuilder 의 builder 는 AsyncSnapshot 객체를 전달받아, snapshot.hasData 로 데이터를 확인하거나 snapshot.error 로 오류를 처리할 수 있음

2. Future 데이터 ListView로 출력하기

이제 받아온 데이터를 출력해보겠습니다. ListView를 통해 출력해보았습니다.

1. ListView.builder()

  • ListView.builder() 는 많은 수의 항목을 효율적으로 렌더링하는 데 적합합니다. 필요한 항목만 생성하므로 성능이 좋습니다.
  • itemBuilder:
    • 각 아이템을 생성하는 빌더 함수로, 인덱스를 기반으로 데이터를 가져옵니다
ListView.builder(
  itemCount: snapshot.data!.length,
  itemBuilder: (context, index) {
    var webtoon = snapshot.data![index];
    return Webtoon(title: webtoon.title, thumb: webtoon.thumb, id: webtoon.id);
  }
)

 

2. ListView.seperated()

ListView.separated(
  itemCount: snapshot.data!.length,
  itemBuilder: (context, index) {
    var webtoon = snapshot.data![index];
    return Webtoon(title: webtoon.title, thumb: webtoon.thumb, id: webtoon.id);
  },
  separatorBuilder: (context, index) => const SizedBox(width: 40),
)

항목 사이에 구분 위젯을 추가하는 ListView 로, separatorBuilder 를 통해 구분자를 정의할 수 있습니다.

3. UI 구성하기

1. clipBehavior

  • Container의 자식 위젯이 부모의 경계를 넘을 때 자르는 동작을 설정합니다.
    • Clip.hardEdge: 자식 위젯이 Container의 경계를 넘으면 잘라냅니다.
Container(
  clipBehavior: Clip.hardEdge,
  decoration: BoxDecoration(
    borderRadius: BorderRadius.circular(10),
  ),
  child: Image.network(thumb)
)

 

2. 상세페이지 작성하기

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => DetailScreen(title: title, thumb: thumb, id: id),
    fullscreenDialog: true,
  ),
)
  • GestureDetector은 동작에 반응하는 위젯입니다. 위젯을 클릭하면 Navigator.push 를 통해 상세 화면으로 이동Navigator.push 는 새로운 화면을 스택에 추가합니다
  • MaterialPageRoute 는 화면 전환 애니메이션을 제공합니다
  • fullScreenDialog: true 를 통해 화면이 아래에서 위로 올라오는 애니메이션을 줄 수 있습니다.

4. 결과 화면

실습화면 결과입니다.