Study Record

[Flutter] 스와이프로 위젯 삭제하기 (Dismissible) 본문

Flutter/widget_scrollView

[Flutter] 스와이프로 위젯 삭제하기 (Dismissible)

초코초코초코 2023. 3. 10. 20:05
728x90

✍ Dismissible

주로 리스트 뷰(ListView, GridView 등)에서 사용자가 항목을 스와이프 모션으로 삭제하는 것을 가능하게 해주는 위젯이다.

Dismissible({   
  required Key key,  
  required Widget child,  
  Widget? background,  
  Widget? secondaryBackground, 
  Future  Function(DismissDirection)? confirmDismiss,  
  void Function()? onResize,  
  void Function(DismissUpdateDetails)? onUpdate, 
  void Function(DismissDirection)? onDismissed,
  DismissDirection direction = DismissDirection.horizontal,
  Duration? resizeDuration = const Duration(milliseconds: 300),  
  Map  dismissThresholds = const  {}, 
  Duration movementDuration = const Duration(milliseconds: 200),  
  double crossAxisEndOffset = 0.0,   
  DragStartBehavior dragStartBehavior = DragStartBehavior.start,
  HitTestBehavior behavior = HitTestBehavior.opaque, 
})

child 로 스와이프 할 위젯을 넣고 key 도 넣어준다. 만약 stateful 위젯이라면 삭제될 때마다 호출되는 onDismissed 를 사용하여 setState() 를 해주면서 데이터 관리도 해줘야 한다.  background 는 스와이프 과정에서 원래 위젯이 밀려나면서 보이는 위젯이다.

 

 

다음 예시 코드는 플러터 api 공식 사이트에서 가져온 코드의 일부이다.

import 'package:flutter/material.dart';

class MyStatefulWidget extends StatefulWidget {
  const MyStatefulWidget({super.key});

  @override
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  List<int> items = List<int>.generate(100, (int index) => index);

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: items.length,
      padding: const EdgeInsets.symmetric(vertical: 16),
      itemBuilder: (BuildContext context, int index) {
        return Dismissible(
          background: Container(
            color: Colors.green,
          ),
          key: ValueKey<int>(items[index]),
          onDismissed: (DismissDirection direction) {
            setState(() {
              items.removeAt(index);
            });
          },
          child: ListTile(
            title: Text(
              'Item ${items[index]}',
            ),
          ),
        );
      },
    );
  }
}

 

 

 

😶 스와이프 방향 (direction)

direction 인자로 스와이프 방향을 정할 수 있다. 위, 아래와 관련된 방향이면 상위 스크롤 위젯의 방향이 좌, 우 방향의 스크롤이어야 하고, 좌, 우와 관련된 방향이면 스크롤 위젯은 위, 아래 방향의 스크롤이어야 한다.

direction 설명
DismissDirection.up 위로 스와이프 하면서 위젯 삭제하기
DismissDirection.down 아래로 스와이프 하면서 위젯 삭제하기
DismissDirection.vertical 위/아래로 스와이프 하면서 위젯 삭제하기
DismissDirection.startToEnd 글자를 읽는 방향으로 위젯 삭제하기(left to right 라면 왼쪽에서 오른쪽으로 스와이프)
DismissDirection.endToStart 글자를 읽는 반대 방향으로 위젯 삭제하기(left to right 라면 오른쪽에서 왼쪽으로 스와이프)
DismissDirection.horizontal 좌우로 스와이프 하면서 위젯 삭제하기(왼 > 오 , 오 > 왼 둘 다 가능)

 

 

예시 - DismissDirection.vertical , 스크롤 위젯 좌, 우)

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  List<int> items = List<int>.generate(100, (int index) => index);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        height: 300.0,
        child: ListView.builder(
          scrollDirection: Axis.horizontal,
          itemCount: items.length,
          padding: const EdgeInsets.symmetric(horizontal: 16),
          itemBuilder: (BuildContext context, int index) {
            return Dismissible(
              direction: DismissDirection.vertical,
              key: ValueKey<int>(items[index]),
              onDismissed: (DismissDirection direction) {
                setState(() {
                  items.removeAt(index);
                });
              },
              child: Container(
                color: Colors.greenAccent,
                width: 250,
                margin: EdgeInsets.only(right: 16.0, top: 16.0, bottom: 16.0),
                child: Center(child: Text("$index")),
              ),
            );
          },
        ),
      ),
    );
  }
}

 

 

 

😶 background, secondaryBackground

위젯을 스와이프 했을 때 밀리면서 보여지는 위젯을 나타낸다. secondaryBackground 가 null 이 아니면 background 도 null 이 아니어야 한다. 

 

①  background == null && secondaryBackground == null 인 경우 , 스와이프 시 아무런 위젯도 보이지 않는다.

②  backgounrd != null && secondaryBackground == null 인 경우, 양쪽으로 스와이프가 가능하다면 양쪽으로 스와이프 했을 때 똑같이 background 위젯이 보인다.

③  background != null && secondaryBackground != null 인 경우, background아래 → 위, 왼쪽 → 오른쪽으로 스와이프 했을 때를 보여주고 secondaryBackground위 → 아래, 오른쪽 → 왼쪽으로 스와이프 했을 때를 보여준다. 따라서 onDismissed 에서 direction 인자가 DismissDirection.startToEnd, DismissDirection.up 일 때는 background 위젯 쪽으로 스와이프 했을 때이고, direction 인자가 DismissDirection.endToStart, DismissDirection.down 일 때는 secondaryBackground 위젯 쪽으로 스와이프 했을 때이다.

 

 

예시 -  )

class MyStatefulWidget extends StatefulWidget {
  const MyStatefulWidget({super.key});

  @override
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  List<int> items = List<int>.generate(100, (int index) => index);

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: items.length,
      padding: const EdgeInsets.symmetric(vertical: 16),
      itemBuilder: (BuildContext context, int index) {
        return Dismissible(
          direction: DismissDirection.horizontal,
          key: ValueKey<int>(items[index]),
          onDismissed: (DismissDirection direction) {
            setState(() {
              if(direction == DismissDirection.startToEnd) {
                print("background swipe");
              } else if(direction == DismissDirection.endToStart) {
                print("secondaryBackground swipe");
              }
              items.removeAt(index);
            });
          },
          background: Container(
            color: Colors.blue,
          ),
          secondaryBackground: Container(
            color: Colors.deepOrangeAccent,
          ),
          child: ListTile(
            title: Text("item ${items[index]}"),
          ),
        );
      },
    );
  }
}

 

 

 

 

Dismissible class - widgets library - Dart API

A widget that can be dismissed by dragging in the indicated direction. Dragging or flinging this widget in the DismissDirection causes the child to slide out of view. Following the slide animation, if resizeDuration is non-null, the Dismissible widget anim

api.flutter.dev

 

728x90