SnappingSheet2는 수직 및 수평 방향으로 미리 정의된 위치에 자동으로 고정되는 드래그 가능한 바텀 시트를 생성할 수 있는 Flutter 패키지입니다. 부드러운 애니메이션과 사용자 지정 가능한 스냅 포인트를 제공하여 모달, 필터 또는 인터랙티브 패널에 적합합니다. 이 위젯은 Android, iOS, Web, macOS, Windows, Linux 등 여러 플랫폼을 지원하며 장치 간 일관된 동작을 보장합니다. 유연한 제스처와 반응형 레이아웃을 통해 사용자 경험을 향상시킵니다.
사용 사례
인터랙티브 하단 패널
필터 또는 설정 드로어
드래그로 열기 기능이 있는 모달 대화상자
사용자 정의 가능한 슬라이드업 인터페이스
다중 방향 시트 탐색
주요 기능
여러 수직/수평 위치로 스냅하기
부드러운 드래그 애니메이션
크로스 플랫폼 지원
사용자 정의 가능한 스냅 포인트
손짓 기반 상호작용
적합한 대상
동적 바텀 시트를 구축하는 개발자
제스처 기반 모달이 필요한 앱
유연한 패널 위치 지정이 필요한 UI
다중 플랫폼을 대상으로 하는 프로젝트
상호작용 가능한 오버레이로 디자인 시스템 만들기
고려 사항
레이아웃 제약 조건을 신중하게 다뤄야 합니다
복잡한 콘텐츠에 성능 튜닝이 필요할 수 있습니다
수직/수평 스냅만 가능
전체 화면 오버레이에 적합하지 않습니다
올바른 부모 위젯 구성에 따라 달라집니다
원본 README
연결된 소스 저장소의 README 원문 스냅샷입니다. 최신 내용은 저장소에서 확인하세요.
Snapping Sheet
A package that provides a highly customizable sheet widget that snaps to different vertical & horizontal positions
Can adapt to scrollable
widgets inside the sheet.
Fully customizable animation
and content.
Not limited to the bottom part
of the app.
You can find and run the examples closing this repository and running the app from the example folder.
Getting started
As usual, begin by adding the package to your pubspec.yaml file, see install instruction.
Here is the most basic setup with the Snapping Sheet:
import'package:flutter/material.dart';
import'package:snapping_sheet/snapping_sheet.dart';
classGettingStartedExampleextendsStatelessWidget{
@overrideWidgetbuild(BuildContext context) {
returnScaffold(
body: SnappingSheet(
// TODO: Add your content that is placed// behind the sheet. (Can be left empty)
child: MyOwnPageContent(),
grabbingHeight: 75,
// TODO: Add your grabbing widget here,
grabbing: MyOwnGrabbingWidget(),
sheetBelow: SnappingSheetContent(
draggable: true,
// TODO: Add your sheet content here
child: MyOwnSheetContent(),
),
),
);
}
}
Customize snapping positions
To change the snap positions for the sheet, change the snappingPositions parameter
witch takes in a list of SnappingPosition.factor or SnappingPosition.pixels. These
two objects are used to specify the location using a factor or pixels. You also have the option
to specify the duration and curve of how the sheet should snap to that given position.
You can place content both below or/and above the grabbing part of the sheet. If you do not want any content in the above or below part of the sheet, pass in null.
sizeBehavior: How the size of the content should behave. Can either be SheetSizeFill which fills the available height of the sheet, or SheetSizeStatic, which takes in a height that is respected in the sheet.
draggable: If the sheet itself can be draggable to expand or close the Snapping Sheet.
In order to make the sheet know about the scroll controller, you need to provide it in the SnappingSheetContent class (See example below). It is recommended to set lockOverflowDrag to true to prevent the sheet to be dragged above or below its max and min snapping position.
SnappingSheet(
lockOverflowDrag: true, // (Recommended) Set this to true.
sheetBelow: SnappingSheetContent(
// Pass in the scroll controller here!
childScrollController: _myScrollController,
draggable: true,
child: ListView(
// And in the scrollable widget that you create!
controller: _myScrollController,
// OBS! Should be false if it is in sheetBelow.// OBS! Should be true if it is in sheetAbove.
reverse: false,
),
),
)
OBS that the scrollable widget, e.g ListView, SingleChildScrollView, etc. needs to have the correct reverse value depending on were it is located. If the scrollable widget is in the sheetBelow, the reverse value should be set to false. If it is located in the sheetAbove it should be set to true. The reason is that the current logic of the SnappingSheet only support that configuration of a scrollable widget.
Using the SnappingSheetController
You can control the Snapping Sheet using the SnappingSheetController
// Create your controllerfinal snappingSheetController = SnappingSheetController();
SnappingSheet(
// Connect it to the SnappingSheet
controller: SnappingSheetController();
sheetAbove: SnappingSheetContent(
draggable: false,
child: Container(color: Colors.blue),
),
sheetBelow: SnappingSheetContent(
draggable: true,
child: Container(color: Colors.red),
),
)
// You can now control the sheet in multiple ways.
snappingSheetController.snapToPosition(
SnappingPosition.factor(positionFactor: 0.75),
);
snappingSheetController.stopCurrentSnapping();
snappingSheetController.setSnappingSheetPosition(100);
// You can also extract information from the sheet
snappingSheetController.currentPosition;
snappingSheetController.currentSnappingPosition;
snappingSheetController.currentlySnapping;
snappingSheetController.isAttached;
Listen to changes
You can listen to movement and when a snapping animation is completed by using the following parameters:
SnappingSheet(
onSheetMoved: (sheetPosition) {
print("Current position ${sheetPosition.pixels}");
},
onSnapCompleted: (sheetPosition, snappingPosition) {
print("Current position ${sheetPosition.pixels}");
print("Current snapping position $snappingPosition");
},
onSnapStart: (sheetPosition, snappingPosition) {
print("Current position ${sheetPosition.pixels}");
print("Next snapping position $snappingPosition");
},
)
Horizontal Snapping Sheet
There also exist a horizontal mode for the snapping sheet. To use it, see the code below:
SnappingSheet.horizontal(
// TODO: Add your content that is placed// behind the sheet. (Can be left empty)
child: MyOwnPageContent(),
grabbingWidth: 50,
// TODO: Add your grabbing widget here,
grabbing: MyOwnGrabbingWidget(),
sheetLeft: SnappingSheetContent(
draggable: true,
// TODO: Add your sheet content here
child: MyOwnSheetContent(),
),
),
A more complex example of a horizontal SnappingSheet can be found here.