N coding

Flutter : Flutter onDrawerSlide 구현하기 본문

Dart&Flutter

Flutter : Flutter onDrawerSlide 구현하기

NYWOO19 2022. 1. 20. 20:53

https://www.notion.so/Drawer-onPositionChanged-1292141c52334e0abca936fed3f7a603

 

Drawer onDrawerSlide

Android로 치자면 DrawerListener.onDrawerSlide 같은 것

www.notion.so

Android로 치자면 DrawerListener.[onDrawerSlide](https://developer.android.com/reference/androidx/drawerlayout/widget/DrawerLayout.DrawerListener#onDrawerSlide(android.view.View, float)) 같은 것

Flutter는 2.0 에서 업데이트 된 Scaffold.onDrawerChanged로 open인지 close 인지만 알 수 있다.

open/close 여부는 내부 코드를 까보면 drawer의 위치가 0.5를 기준으로 변한다.

그렇다면 onDrawerSlide 처럼 몇 퍼센트 정도 열렸는지를 알 수는 없을까? ⇒ 정식으로는 없다.

하지만 돌고돌아서 구현해낼 수는 있다.

1. 코드 수정하기

당연히 권장되는 방법은 아니지만 Drawer 위젯 내부 코드를 수정하면 가져올 수 있다.

AnimationController의 value를 가져오거나 읽어오면 된다.

class DrawerControllerState extends State<DrawerController> with SingleTickerProviderStateMixin {
  @override
  void initState() {
    super.initState();
    _scrimColorTween = _buildScrimColorTween();
    _controller = AnimationController(
      value: widget.isDrawerOpen ? 1.0 : 0.0,
      duration: _kBaseSettleDuration,
      vsync: this,
    );
    _controller
      ..addListener(_animationChanged)
      ..addStatusListener(_animationStatusChanged);
  }

...
}

2. 직접 Drawer를 구현하기 or 구현된 Plugin을 찾기

엄청나게 잘 만들어진 라이브러리, 플러그인들이 많다. 특정한 걸 하고 싶은 게 아니라 그냥 화려한 효과를 원한다면 좋은 선택일 것 같다.

https://www.youtube.com/watch?v=ZHRhSFXqHJY

Drawer Animation in Flutter

Flutter Animated Navigation Drawer

3. Drawer의 현재 position을 알아내서 내가 움직이고 싶은 것을 움직이기

import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';

    class DrawerListener extends StatefulWidget {
      final Widget child;
      final void Function(FractionalOffset offset) onPositionChange;

      DrawerListener({
        required this.child,
        this.onPositionChange,
      });

      @override
      _DrawerListenerState createState() => _DrawerListenerState();
    }

    class _DrawerListenerState extends State<DrawerListener> {
      int taskID;
      Offset currentOffset;

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

      _postTask() {
        taskID = SchedulerBinding.instance.scheduleFrameCallback((_) {
          if (widget.onPositionChange != null) {
            final box = context?.findRenderObject();
            if (box != null) {
              Offset newOffset = box.globalToLocal(Offset.zero);
              if (newOffset != currentOffset) {
                currentOffset = newOffset;
                widget.onPositionChange(
                  FractionalOffset.fromOffsetAndRect(
                    currentOffset,
                    Rect.fromLTRB(0, 0, box.size.width, box.size.height),
                  ),
                );
              }
            }
          }

          _postTask();
        });
      }

      @override
      void dispose() {
        SchedulerBinding.instance.cancelFrameCallbackWithId(taskID);
        super.dispose();
      }

      @override
      Widget build(BuildContext context) {
        return widget.child,
      }
    }

Flutter: possible to detect when a drawer is open?

이 stackoverflow에 달린 답변이 그나마 도움이 되었다. 나는 거의 flutter + drawer로 검색된 모든 글을 읽고 다녔는데 이게 내가 원하던 답에 가장 근접했음.

Drawer(child)의 RenderObject의 Local에서의 위치를 찾은 뒤,

그 Offset이 현재 box(child = Drawer) 크기에 비해 얼마의 비율인지를 FractionalOffset으로 계산해서 onPositionChange의 인자로 넘겨준다.

width의 위치 비율만을 보고 싶으면 currentOffset.dx / box.size.width 처럼 계산해도 될 것 같다.

이렇게 구현을 하면, 본인이 onPositionChange를 사용하는 것?에 따라서 자연스러울 수도 있고, 완전히 자연스럽게 보이지는 않을 수도 있다. 내 경우는 좀 버벅임이 있었다.

ScheduleBinding.instance.scheduleFrameCallback이 build 이후에 schedule해놓는 거라서 빌드 속도나 Drawer를 드래그하는 속도에 따라서 수치가 휙휙 바뀌는 경우에는 좀 부자연스러웠음. 그래도 없는 것보다는 나으니 그냥 썼다 대충.

더 좋은 방법이 있으면 comment를 남겨주세요..!

아니면 비슷하게 GestureDetector로 현재 Drag되는 위치, 손가락이 움직인 정도를 가지고 파악을 해도 될 것 같다.

https://stackoverflow.com/questions/47272323/flutter-get-the-local-position-from-the-gesturedetector

issue도 있고,.. Priority는 비록 높진 않지만 언젠가는 되겠지.. 안 어렵잖아 ㅠ 해줘

'Dart&Flutter' 카테고리의 다른 글

Flutter : How to develop flutter on tizen?  (0) 2022.01.20
Dart : async/await/Future  (0) 2022.01.20
Flutter : FFI  (0) 2022.01.20
Dart : what is extenstion ? extension keyword  (0) 2022.01.20
Dart : enum with values (enum-like class)  (0) 2022.01.20