인문주의 사피엔스

Flutter에서 Overlay 클래스 사용하기 본문

프로그래밍/Flutter

Flutter에서 Overlay 클래스 사용하기

인문주 2022. 3. 15. 22:33
반응형

Overlay는 Flutter로 만든 앱의 화면 맨위에 독립적인 위젯을 추가할 때 사용하는 클래스입니다. 아래 그림은 Overlay의 사용법을 테스트하기 위해 만든 예제 앱의 화면입니다. 

 

Overlay 테스트 앱

 

Add 버튼을 누를 때마다 화면에 100x100 크기의 사각형이 하나씩 추가됩니다. Remove 버튼을 누르면 마지막에 추가된 사각형이 화면에서 제거됩니다. 각 사각형의 위치와 색깔은 무작위로 선택되고 위치를 나타내는 숫자가 그 위에 표시됩니다.

 

Overlay 클래스

Overlay의 사용법은 Stack 클래스와 비슷합니다. 화면에 위젯들을 쌓아올리는 방식입니다. 다른 점은 Overlay를 통해 추가되는 위젯은 앱의 기본 위젯 트리에서 벗어나 독립적으로 존재한다는 것입니다. 따라서 Overlay는 다음과 같이 싱글톤 방식으로 사용됩니다.

 

final overlayEntry = OverlayEntry();
Overlay.of(context).insert(overlayEntry);

 

위젯을 쌓아올리기 위해서는 OverlayEntry를 사용해야 합니다. OverlayEntry는 화면에 쌓이는 하나의 층에 해당됩니다. OverlayEntry가 제공하는 WidgetBuilder를 통해 실제 위젯이 생성됩니다. 위젯은 insert를 호출하는 순서대로 쌓입니다. 따라서 나중에 추가한 위젯이 가장 위에 놓이게 됩니다. 

 

OverlayEntry의 인스턴스는 프로그래머가 직접 관리해야 합니다. 추가했던 위젯을 제거하기 위해서는 다음과 같이 OverlayEntry 인스턴스의 remove를 호출해야 합니다.

 

overlayEntry.remove();

 

OverlayEntry 클래스

OverlayEntry가 제공하는 WidgetBuilder를 통해 구체적인 위젯을 생성할 수 있습니다. 아래 코드는 100x100 크기의 사각형을 화면 좌상으로부터 100x100 위치에 표시하는 예를 나타낸 것입니다. Stack 클래스를 사용할 때처럼 Positioned이 사용되고 있습니다.

 

final overlayEntry = OverlayEntry(
    builder: (context) {
        return Positioned(
            left: 100,
            top: 100,
            width: 100,
            height: 100,
            child: Container(),
        );
    },
);

 

예제 앱 구현하기

먼저 OverlayEntry의 인스턴스를 저장하기 위한 배열을 다음과 같이 선언합니다.

 

final overlays = <OverlayEntry>[];

 

그리고 OverlayEntry 인스턴스 생성해서 배열과 화면에 추가합니다.

 

void addOverlay() {
    overlays.add(overlayEntry);
    Overlay.of(context).insert(overlays.last);
}

 

다음은 OverlayEntry 인스턴스를 제거하는 함수입니다.

 

void removeOverlay() {
    if (overlays.isNotEmpty) overlays.removeLast().remove();
}

 

OverlayEntry의 인스턴스는 다음과 같이 생성됩니다.

 

OverlayEntry get overlayEntry {
    final random = Random.secure();
    final screen = MediaQuery.of(context).size;
    final offsetX = random.nextInt(screen.width.toInt() ~/ 2);
    final offsetY = random.nextInt(screen.height.toInt() ~/ 2);
    final color = Colors.primaries[random.nextInt(Colors.primaries.length)];
    return OverlayEntry(
      builder: (context) {
        return Positioned(
          left: offsetX.toDouble(),
          bottom: offsetY.toDouble(),
          width: 100,
          height: 100,
          child: Material(
            child: Container(
              color: color,
              child: Center(child: Text('$offsetX $offsetY')),
            ),
          ),
        );
      },
    );
}

 

다음은 소스코드의 전체 내용입니다.

 

 

반응형
Comments