Thursday, July 6, 2023

Flutter ListView에서 특정 위치로 스크롤하는 방법

Flutter에서 SingleChildScrollView를 사용하여 특정 위치로 스크롤하는 방법

Flutter에서 scrollView의 특정 위젯으로 스크롤 이동하려면, GlobalKey와 Scrollable.ensureVisible() 메소드를 사용할 수 있습니다. 이 포스트에서는 이를 어떻게 구현하는지에 대해 자세히 설명하겠습니다.

GlobalKey 사용하기

먼저, 이동하려는 목표 위젯에 GlobalKey를 할당해야 합니다. GlobalKey는 전역에서 참조할 수 있는 키로, 위젯의 상태와 위치에 대한 정보를 제공합니다. GlobalKey를 생성하려면 아래와 같이 코드를 작성합니다.

GlobalKey _globalKey = GlobalKey();

목표 위젯에 GlobalKey 추가하기

생성한 GlobalKey를 목표 위젯에 할당합니다. 이 예에서는 Container 위젯을 사용하였습니다.

Container(
  key: _globalKey,
  ...
)

Scrollable.ensureVisible() 사용하기

스크롤을 이동하려는 시점에서 Scrollable.ensureVisible() 메소드를 호출합니다. 이 메소드는 GlobalKey의 currentContext를 인자로 받아 해당 위젯이 화면에 보이도록 스크롤을 이동합니다.

void scrollToWidget() {
  Scrollable.ensureVisible(
    _globalKey.currentContext,
  );
}

이제 위의 코드를 종합하여 전체 코드를 확인해 보겠습니다.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  GlobalKey _globalKey = GlobalKey();

  void scrollToWidget() {
    Scrollable.ensureVisible(
      _globalKey.currentContext,
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Scroll to Widget Example'),
        ),
        body: SingleChildScrollView(
          child: Column(
            children: [
              Container(
                height: 200,
                color: Colors.yellow,
              ),
              ElevatedButton(
                onPressed: scrollToWidget,
                child: Text('Scroll to Target Widget'),
              ),
              Container(
                key: _globalKey,
                height: 200,
                color: Colors.red,
              ),
              Container(
                height: 200,
                color: Colors.blue,
              ),
            ],
          ),
        ),
      ),
   );
  }
}

이 코드를 실행하면, 빨간색 Container까지 스크롤 되는 것을 확인할 수 있습니다.

Scrollable.ensureVisible()의 사용법과 예시

Scrollable.ensureVisible() 메서드는 특정 위젯이 화면에 표시되도록 스크롤 위치를 조정합니다. 이 기능을 사용하려면 몇 가지 단계를 따라야 합니다.

GlobalKey 생성하기

키를 생성하여 이후에 스크롤 위치를 참조할 위젯을 식별합니다.

GlobalKey _globalKey = GlobalKey();

스크롤 대상 위젯에 GlobalKey 할당하기

위젯에 생성한 GlobalKey를 할당하여 해당 위치로 스크롤 할 수 있도록 합니다.

Container(
  key: _globalKey,
  ...
)

Scrollable.ensureVisible() 호출하기

스크롤 위치를 조정하려는 시점에서 Scrollable.ensureVisible() 메서드를 호출합니다. 해당 메서드는 인자로 GlobalKey의 currentContext를 받아 해당 위젯의 위치로 스크롤을 이동합니다.

void scrollToTarget() {
  Scrollable.ensureVisible(
    _globalKey.currentContext,
  );
}

예제 코드

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  GlobalKey _globalKey = GlobalKey();

  void scrollToTarget() {
    Scrollable.ensureVisible(
      _globalKey.currentContext,
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Scroll to Widget Example'),
        ),
        body: SingleChildScrollView(
          child: Column(
            children: [
              Container(
                height: 200,
                color: Colors.yellow,
              ),
              ElevatedButton(
                onPressed: scrollToTarget,
                child: Text('Scroll to Target Widget'),
              ),
              Container(
                key: _globalKey,
                height: 200,
                color: Colors.red,
              ),
              Container(
                height: 200,
                color: Colors.blue,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

이 예제에서는 화면에 노란색, 빨간색, 파란색 Container가 순차적으로 나열되어 있습니다. 사용자가 ElevatedButton을 클릭하면 빨간색 Container로 자동 스크롤되는 것을 확인할 수 있습니다.

ListView.builder()나 ListView가 적합하지 않은 이유

Scrollable.ensureVisible()을 사용하여 특정 위치로 스크롤하려면 GlobalKey를 사용하여 해당 위치에 대한 참조를 생성해야 합니다. 그러나 ListView.builder()와 ListView에는 몇 가지 제한 사항이 있습니다.

GlobalKey를 사용할 수 없는 상황

ListView.builder()와 ListView는 수많은 아이템을 처리할 때 높은 효율성을 보장하기 위해 아이템 재사용 및 비활성화 메커니즘을 사용합니다. 이로 인해 GlobalKey를 각 아이템에 할당할 때 일부 문제가 발생할 수 있습니다.

특히 많은 수의 아이템이 포함된 ListView.builder()를 사용하면 각 아이템에 GlobalKey를 지정하면 'multiple widgets used the same GlobalKey' 오류가 발생할 수도 있습니다. 이는 같은 키를 사용하는 여러 위젯이 동시에 활성화되어 충돌이 발생했음을 나타냅니다.

스크롤 위치를 얻기 어려운 상황

ListView.builder()와 ListView는 각 아이템 간에 고정 된 높이가 없을 때 스크롤 위치를 계산하기 어려울 수 있습니다. 또한 위젯 재사용 및 비활성화 메커니즘으로 인해 특정 아이템의 위치를 미리 정확하게 파악할 수 없을 수 있습니다.

대안: SingleChildScrollView

이러한 문제를 해결하기 위해 SingleChildScrollView를 사용할 수 있습니다. SingleChildScrollView는 SingleChildScrollView의 자식 위젯을 전부 렌더링하고 화면 내부에서만 보여주는 뷰포트를 조작합니다. 따라서 GlobalKey를 통해 특정 위젯의 위치로 이동하는 것이 더 쉽고 안정적입니다.

단점으로는 수많은 아이템을 포함하거나 복잡한 위젯 구조를 가진 페이지에서 사용하면 전체 렌더링 성능이 저하되거나, 메모리 이슈가 발생할 수 있습니다. 이러한 특성에 따라 애플리케이션에 가장 적합한 위젯을 선택하십시오.

관련 자료를 더 찾아보려면, Flutter 공식 문서의 Scrollable.ensureVisible() 섹션을 참조하십시오. 또한, 온라인 커뮤니티에서 다른 개발자들과 함께 이러한 문제에 대해 논의하고 싶다면, StackOverflow의 Flutter 태그를 방문해 보시기 바랍니다.


0 개의 댓글:

Post a Comment