본문 바로가기
Flutter

[Flutter] ScrollController 특정 위치로 이동하기 & 특정 위젯의 위치, 크기 찾기

by hymndaniel 2023. 2. 1.

MOTIVATION

한 화면에서 사용자에게 제공하는 정보가 2가지인데(월 정보와 일 정보), 일 정보만 바로 볼 수 있도록 특정 위젯의 위치로 스크롤시키고 싶음

접근 방법1. 내가 이동하기 원하는 특정 위젯의 위치(OffSet)을 알아낸 뒤 ScrollController의 animateTo를 이용

접근방법2. scrollable_positioned_list 패키지 사용

둘 다 해본 결과, 패키지 사용이 더 자연스럽다.

 

IMPLEMENT 접근방법1

1. 특정 위젯의 위치를 알아내기

class _MyHomePageState extends State<MyHomePage> {

  ScrollController pageScrollController = ScrollController();

  Size? _getSize() {
    if (_containerKey.currentContext != null) {
      final RenderBox renderBox =
          _containerKey.currentContext!.findRenderObject() as RenderBox;
      Size size = renderBox.size;
      return size;
    }
    
   Offset? _getOffset() {
    if (_containerKey.currentContext != null) {
      final RenderBox renderBox =
          _containerKey.currentContext!.findRenderObject() as RenderBox;
      Offset offset = renderBox.localToGlobal(Offset.zero);
      return offset;
    }
  }

  final GlobalKey _containerKey = GlobalKey();
   Size? size;
  Offset? offset;

  @override
  void initState() {
    super.initState();
    // 위젯의 크기나 위치는 위젯이 렌더링된 후 알 수 있음. 위젯이 바인딩 된 후에 호출하는 함수로 해당 함수 내에서 위젯의 크기 및 위치를 받는 함수를 호출
    WidgetsBinding.instance!.addPostFrameCallback((_) {
      setState(() {
        size = _getSize();
        offset = _getOffset();
      });
    });
  }
  
  // 그다음 위치를 알고싶은 위젯에서
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
              key: _containerKey, //키를 지정
              child: const Text("텍스트."),
            ),
          ),
        ],
      ),
    );
  }
}

2. 사용자의 행동에 따라 scrollController 활용

onTap: () {
              pageScrollController.animateTo(pageScrollController.position.minScrollExtent,
                  duration: Duration(milliseconds: 700), curve: Curves.ease);
            },

 

IMPLEMENT 접근방법2 

scrollable_positioned_list 패키지 사용

1. 사용할 위젯들을 담은 리스트 준비

final ItemScrollController itemScrollController = ItemScrollController();
final ItemPositionsListener itemPositionsListener = ItemPositionsListener.create();

@override
Widget build(BuildContext context) {
  List<Widget> widgetList = [
    _buildTableCalendar(),
    showCalendarButtonWidget(),
    separateLineWidget(),
    _buildFarmWorkWidgets(),
    const SizedBox(height: 20)
  ];
  return Scaffold(
    appBar: farmingDiaryAppBar(),
    body: ScrollablePositionedList.builder(
      itemCount: widgetList.length,
      itemBuilder: (context, index) => widgetList[index],
      itemScrollController: itemScrollController,
      itemPositionsListener: itemPositionsListener,
    ),
  );
}
 

2. 특정 위젯을 눌렀을때 원하는 인덱스의 위젯으로 스크롤

bool _isScrolled = false;

InkWell(
  // 한 번 누르면 원하는 위치로, 한 번 더 누르면 최상위 위치로
  onTap: () {
    if (_showCalendar) {
      if (!_isScrolled) {
        itemScrollController.scrollTo(index: 3, duration: Duration(seconds: 1), curve: Curves.easeInOutCubic);
      }
      if (_isScrolled) {
        itemScrollController.scrollTo(
            index: 0, duration: const Duration(milliseconds: 700), curve: Curves.easeInOutCubic);
      }
      setState(() {
        _isScrolled = !_isScrolled;
      });
    }
  },
  child: Text(
    '텍스트',
    style: TextStyle(
      color: Color(0xff111111),
      fontFamily: 'NotoSansCJKKR',
      fontWeight: FontWeight.w700,
    ),
  ),
),

 

참고

https://petabyte.studio/posts/flutter-get-size-of-widget/

 

[Flutter] 위젯의 크기 / 위치 값을 가져오는 법

Before Start.

petabyte.studio

https://pub.dev/packages/scrollable_positioned_list/versions/0.2.3/example

 

scrollable_positioned_list 0.2.3 | Flutter Package

A list with helper methods to programmatically scroll to an item.

pub.dev

 

728x90