본문 바로가기
Flutter

Flutter 매우 간단한 무한 스크롤 만들기

by Empering 2021. 4. 29.
반응형

시작하기

Flutter 의 ListView 위젯과 GetX를 이용해 마지막 리스트에 도달 하면 추가적인 데이터를 서버에서 가지고 오는 UI를 구현합니다. (GetX 대신 Provider나 StatefullWedget으로 변경해도 됩니다.)

 

GetX 사용을 위한 기본 설정들

💡
GetX를 사용하지 않는경우 해당항목 생략

 

  • pubspec.yaml dependencies 추가
get: ^4.1.4

 

  • main.dart MaterialApp → GetMaterialApp 으로 변경
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      initialBinding: AppBinding(),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter!'),
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Center(
              child: ElevatedButton(
                onPressed: () {
                  Get.to(() => InfiniteScrollView());
                },
                child: Text('Infinite Scroll View'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

 

  • AppBinding
class AppBinding extends Bindings {
  @override
  void dependencies() {
    Get.put(InfiniteScrollController());
  }
}

 

Infinite Scroll Controller

💡
GetX를 사용해 구현했습니다.

 

class InfiniteScrollController extends GetxController {
  var scrollController = ScrollController().obs;

  var data = <int>[].obs;
  var isLoading = false.obs;
  var hasMore = false.obs;

  @override
  void onInit() {
    _getData();

    this.scrollController.value.addListener(() {
      if (this.scrollController.value.position.pixels ==
              this.scrollController.value.position.maxScrollExtent &&
          this.hasMore.value) {
        _getData();
      }
    });

    super.onInit();
  }

  _getData() async {
    isLoading.value = true;

    await Future.delayed(Duration(seconds: 2));

    int offset = data.length;
    var appendData = List<int>.generate(10, (i) => i + 1 + offset);
    data.addAll(appendData);

    isLoading.value = false;
    hasMore.value = data.length < 30;
  }

  reload() async {
    isLoading.value = true;
    data.clear();

    await Future.delayed(Duration(seconds: 2));

    _getData();
  }
}

 

코드 설명

  • 리스트뷰의 상태를 감지하기 위한 ScrollController
    • ScrollController의 position 값을 이용해 가장 마지막 행에 도달했는지 확인
    • 마지막 행에 도달한 경우 _getData 를 실행하는 addListener추가
  • 리스트뷰에 표시할 데이터인 data
    • 실제 서버에서 데이터를 가지고 오는 것을 시뮬레이션 하기위해 강제로 2초의 딜레이 설정
    • 가지고 온 데이터의 총 갯수가 30개 이상이라면 더이상 데이터가 없는 것으로 판단
  • 로딩중 이나, 다음 데이터 존재여부체크를 위한 isLoading, hasMore

 

Infinite Scroll View

 

class InfiniteScrollView extends GetView<InfiniteScrollController> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Infinite Scroll'),
      ),
      body: Obx(
        () => Padding(
          padding: const EdgeInsets.all(10.0),
          child: ListView.separated(
            controller: controller.scrollController.value,
            itemBuilder: (_, index) {
              print(controller.hasMore.value);

              if (index < controller.data.length) {
                var datum = controller.data[index];
                return Material(
                  elevation: 10.0,
                  child: Container(
                    padding: const EdgeInsets.all(10.0),
                    child: ListTile(
                      leading: Icon(Icons.android_outlined),
                      title: Text('$datum 번째 데이터'),
                      trailing: Icon(Icons.arrow_forward_outlined),
                    ),
                  ),
                );
              }

              if (controller.hasMore.value || controller.isLoading.value) {
                return Center(child: RefreshProgressIndicator());
              }

              return Container(
                padding: const EdgeInsets.all(10.0),
                child: Center(
                  child: Column(
                    children: [
                      Text('데이터의 마지막 입니다'),
                      IconButton(
                        onPressed: () {
                          controller.reload();
                        },
                        icon: Icon(Icons.refresh_outlined),
                      ),
                    ],
                  ),
                ),
              );
            },
            separatorBuilder: (_, index) => Divider(),
            itemCount: controller.data.length + 1,
          ),
        ),
      ),
    );
  }
}

 

코드설명

  • GetX의 Obx를 이용해 Reactive처리
  • 기본적인 ListView를 구성하되, itemCount를 실제데이터 갯수 + 1로 지정
    • 추가된 행에서 ProgressIndicator 혹은 데이터없음 안내 표시

 

 

실제 동작 화면

 

 

소스 링크

flutter_infinite_scroll
Instantly share code, notes, and snippets. You can't perform that action at this time. You signed in with another tab or window. You signed out in another tab or window. Reload to refresh your session. Reload to refresh your session.
https://gist.github.com/empering/53d4fd10b6f3ca15c1338943bb155012

 

empering/flutter_smaple
A new Flutter project. This project is a starting point for a Flutter application. A few resources to get you started if this is your first Flutter project: For help getting started with Flutter, view our online documentation, which offers tutorials, samples, guidance on mobile development, and a full API reference.
https://github.com/empering/flutter_smaple

 

반응형

댓글