搜尋套件、儲存庫與 APP 分類

flutter_swipe_action_cell 封面
套件詳情v3.1.9

flutter_swipe_action_cell

一個出色的 UI 套件,包含 iOS 風格的單元格滑動操作效果。您可以使用此套件來實現 iOS 風格的 tableView 單元格滑動操作

AndroidiOSWebmacOSWindowsLinux
近 30 天下載
3.1萬
喜歡數
464
Pub 分數
150

安裝套件

flutter pub add flutter_swipe_action_cell

套件介紹

根據套件公開資料產生的選型評估,僅供參考。

flutter_swipe_action_cell 是一個 Flutter 套件,可在清單項目上啟用類似 iOS 的滑動操作,模擬原生 iOS 表格檢視中的互動行為。它允許使用者透過水平滑動清單單元格來顯示操作按鈕,藉由直覺的手勢增強使用者互動體驗。此套件支援 Android、iOS、Web、macOS、Windows 與 Linux 多個平台,非常適合追求一致且精緻 UI 經驗的跨平台應用。開發者可自訂滑動操作的外觀與行為,以符合其應用的設計語言。

適用情境

  • 在列表中實現 iOS 風格的滑動刪除或滑動操作
  • 建立具有情境動作的互動式清單項目
  • 提升任務管理或訊息應用中的使用者體驗
  • 建構響應式且由手勢驅動的介面
  • 向聊天或通知列表添加滑動效果
  • 設計現代的、原生樣式的移動使用者介面

主要特色

  • iOS 風格的水平滑動操作
  • 可自定義的操作按鈕和顏色
  • 支援多種滑動方向
  • 跨平台相容性
  • 與 ListView 及其他列表組件的輕鬆整合
  • 可設定的動畫與時間

適合對象

  • 開發 iOS 風格的 Flutter 應用程式開發者
  • 優先考慮原生使用者體驗模式的團隊
  • 需要互動式列表項目行為的應用程式
  • 以使用者介面為重點的專案,具有基於手勢的互動
  • 跨平台開發者,針對多個作業系統

使用建議

  • 可能需要為非 iOS 平台添加額外樣式
  • 大型清單的效能影響
  • 有限的內建可存取性功能
  • 複雜操作工作流程需要自訂邏輯
  • 未針對垂直滑動手勢進行優化
  • 需要在嵌套滾動上下文中謹慎處理觸控事件

原始 README

以下為關聯原始碼儲存庫的 README 原文快照,最新內容請造訪原始碼儲存庫。

Language:

English | 中文简体

flutter_swipe_action_cell

A package that can give you a cell that can be swiped, effect is like iOS native

If you like this package, you can give me a star😀. The more stars this project has, the more time I will speant in the project😀
Donate:
Alipay Wechat

Get started

3.0.0 and later version is for flutter 3
pub home page click here: pub
install:
flutter_swipe_action_cell: ^3.1.9

1.Preview:

Simple delete Perform first action when full swipe
Delete with animation More than one action
Effect like WeChat(confirm delete) Automatically adjust the button width
Effect like WeChat collection Page: Customize your button shape
With leading Action and trailing action
Edit mode

Full example:

Preview (YouTobe video)

And you can find full example code in example page

Examples

  • Example 1: Simple delete the item in ListView

  • Tip: put the code in the itemBuilder of your ListView
 SwipeActionCell(
      key: ObjectKey(list[index]), /// this key is necessary
      trailingActions: <SwipeAction>[
        SwipeAction(
            title: "delete",
            onTap: (CompletionHandler handler) async {
              list.removeAt(index);
              setState(() {});
            },
            color: Colors.red),
      ],
      child: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Text("this is index of ${list[index]}",
            style: TextStyle(fontSize: 40)),
      ),
    );
  • Example 2: Perform first action when full swipe

SwipeActionCell(
      /// this key is necessary
      key: ObjectKey(list[index]),
      trailingActions: <SwipeAction>[
        SwipeAction(
            /// this is the same as iOS native
            performsFirstActionWithFullSwipe: true,
            title: "delete",
            onTap: (CompletionHandler handler) async {
              list.removeAt(index);
              setState(() {});
            },
            color: Colors.red),
      ],
      child: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Text("this is index of ${list[index]}",
            style: TextStyle(fontSize: 40)),
      ),
    );
  • Example 3: Delete with animation

SwipeActionCell(
     key: ObjectKey(list[index]),
     trailingActions: <SwipeAction>[
       SwipeAction(
           title: "delete",
           onTap: (CompletionHandler handler) async {
             
             /// await handler(true) : will delete this row
             /// And after delete animation,setState will called to 
             /// sync your data source with your UI

             await handler(true);
             list.removeAt(index);
             setState(() {});
           },
           color: Colors.red),
     ],
     child: Padding(
       padding: const EdgeInsets.all(8.0),
       child: Text("this is index of ${list[index]}",
           style: TextStyle(fontSize: 40)),
     ),
   );
  • Example 4: More than one action:

SwipeActionCell(
     key: ObjectKey(list[index]),
     trailingActions: <SwipeAction>[
       SwipeAction(
           title: "delete",
           onTap: (CompletionHandler handler) async {
             await handler(true);
             list.removeAt(index);
             setState(() {});
           },
           color: Colors.red),

       SwipeAction(
           widthSpace: 120,
           title: "popAlert",
           onTap: (CompletionHandler handler) async {
             /// false means that you just do nothing,it will close
             /// action buttons by default
             handler(false);
             showCupertinoDialog(
                 context: context,
                 builder: (c) {
                   return CupertinoAlertDialog(
                     title: Text('ok'),
                     actions: <Widget>[
                       CupertinoDialogAction(
                         child: Text('confirm'),
                         isDestructiveAction: true,
                         onPressed: () {
                           Navigator.pop(context);
                         },
                       ),
                     ],
                   );
                 });
           },
           color: Colors.orange),
     ],
     child: Padding(
       padding: const EdgeInsets.all(8.0),
       child: Text(
           "this is index of ${list[index]}",
           style: TextStyle(fontSize: 40)),
     ),
   );
  • Example 5:Delete like WeChat message page(need to confirm it:

return SwipeActionCell(
      key: ValueKey(list[index]),
      trailingActions: <SwipeAction>[
        SwipeAction(
          ///
          /// This attr should be passed to first action
          ///
          nestedAction: SwipeNestedAction(title: "确认删除"),
          title: "删除",
          onTap: (CompletionHandler handler) async {
            await handler(true);
            list.removeAt(index);
            setState(() {});
          },
          color: Colors.red,
        ),
        SwipeAction(
            title: "置顶",
            onTap: (CompletionHandler handler) async {
              /// false means that you just do nothing,it will close
              /// action buttons by default
              handler(false);
            },
            color: Colors.grey),
      ],
      child: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Text("this is index of ${list[index]}",
            style: TextStyle(fontSize: 40)),
      ),
    );
  • Example 6:Edit mode(just like iOS native effect)

/// To controller edit mode
SwipeActionEditController controller;

/// 在initState
@override
  void initState() {
    super.initState();
    controller = SwipeActionController();
  }
/// To get the selected rows index
List<int> selectedIndexes = controller.getSelectedIndexes();


/// open cell
controller.openCellAt(index: 2, trailing: true, animated: true);

/// close cell
controller.closeAllOpenCell();

/// whether any cell is currently open (e.g. to let a back gesture close it first)
bool hasOpen = controller.hasAnyOpenCell;

/// toggleEditingMode
controller.toggleEditingMode()

/// startEditMode
controller.startEditingMode()

/// stopEditMode
controller.stopEditingMode()

/// select cell
controller.selectCellAt(indexPaths:[1,2,3])

controller.deselectCellAt(indexPaths:[1,2,3])

/// pass your data length to selectedAll
controller.selectAll(30
)

/// deselect all cell
controller deselectAll()

ListView.builder(
        itemBuilder: (c, index) {
          return _item(index);
        },
        itemCount: list.length,
      );


 Widget _item(int index) {
     return SwipeActionCell(
       /// controller
       controller: controller,
       /// index is required if you want to enter edit mode
       index: index,
       key: ValueKey(list[index]),
       trailingActions: [
         SwipeAction(
             /// this is the same as iOS native
             performsFirstActionWithFullSwipe: true,
             onTap: (handler) async {
               await handler(true);
               list.removeAt(index);
               setState(() {});
             },
             title: "delete"),
       ],
       child: Padding(
         padding: const EdgeInsets.all(15.0),
         child: Text("This is index of ${list[index]}",
             style: TextStyle(fontSize: 35)),
       ),
     );
   }

  • Example 7:customize shape


Widget _item(int index) {
    return SwipeActionCell(
      key: ValueKey(list[index]),
      trailingActions: [
        SwipeAction(
            nestedAction: SwipeNestedAction(
              /// customize your nested action content
              content: Container(
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(30),
                  color: Colors.red,
                ),
                width: 130,
                height: 60,
                child: OverflowBox(
                  maxWidth: double.infinity,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Icon(
                        Icons.delete,
                        color: Colors.white,
                      ),
                      Text('确认删除',
                          style: TextStyle(color: Colors.white, fontSize: 20)),
                    ],
                  ),
                ),
              ),
            ),

            /// you should set the default  bg color to transparent
            color: Colors.transparent,

            /// set content instead of title of icon
            content: _getIconButton(Colors.red, Icons.delete),
            onTap: (handler) async {
              list.removeAt(index);
              setState(() {});
            }),
        SwipeAction(
            content: _getIconButton(Colors.grey, Icons.vertical_align_top),
            color: Colors.transparent,
            onTap: (handler) {}),
      ],
      child: Padding(
        padding: const EdgeInsets.all(15.0),
        child: Text(
            "This is index of ${list[index]},Awesome Swipe Action Cell!! I like it very much!",
            style: TextStyle(fontSize: 25)),
      ),
    );
  }

  Widget _getIconButton(color, icon) {
    return Container(
      width: 50,
      height: 50,
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(25),

        /// set you real bg color in your content
        color: color,
      ),
      child: Icon(
        icon,
        color: Colors.white,
      ),
    );
  }

  • Example 8:Close opening cell when navigator change its routes.

Add a SwipeActionNavigatorObserver in MaterialApp's navigatorObservers

return MaterialApp(
  navigatorObservers: [SwipeActionNavigatorObserver()],
  ....
);

About CompletionHandler in onTap function of SwipeAction

it means how you want control this cell after you tap it. If you don't want any animation, just don't call it and update your data and UI with setState()

If you want some animation:

  • handler(true) : Means this row will be deleted(You should call setState after it)

  • await handler(true) : Means that you will await the animation to complete(you should call setState after it so that you will get an animation)

  • handler(false) : means it will not delete this row.By default, it just close this cell's action buttons.

  • await handler(false) : means it will wait the close animation to complete.

About all parameter:

I wrote them in my code with dart doc comments. You can read them in source code.

所屬分類

原始碼儲存庫

使用此套件的專案