Flutter Sticker Editor

一个功能强大的 Flutter 贴图编辑器组件。

Features

  • 🖼️ Image Editing

    • Crop, rotate, and scale images
    • Apply filters and adjustments
  • 🎨 Drawing Tools

    • Free-hand drawing
    • Customizable brush settings
  • 📝 Sticker Management

    • Add and manage stickers
    • Drag, resize, and rotate stickers
    • Layer management

Getting Started

Add this to your package's pubspec.yaml file:

dependencies:
  flutter_sticker_editor: ^0.0.1

1、初始化设置

在使用组件之前,需要先初始化 DrawerInfo Provider:

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => DrawerInfo()),
      ],
      child: MyApp(),
    ),
  );
}

2、使用组件

全部默认

  @override
  Widget build(BuildContext context) {
    return StickerEditor();
  }

自定义界面

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_sticker_editor/flutter_sticker_editor.dart';
import 'package:provider/provider.dart';

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

  @override
  State<DrawerPage> createState() => _DrawerPageState();
}

class _DrawerPageState extends State<DrawerPage> {

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

  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    StickerEditorConfig config = StickerEditorConfig(
      // customPickerPanel: _buildPickerWidget(),
      customDrawerPanel: _buildDrawerWidgetCustom() // 方式1
      // customDrawerPanel: _buildDrawerWidget() // 方式二
    );
    return StickerEditor(
      onComplete: (Uint8List uint8List, { bool isSaveChihiros = false, bool isPublishList = false }) {
      },
      config: config,
    );
  }

  Widget _buildPickerWidget() {
    return SizedBox(
      child: GestureDetector(
        onTap: () {
          context.read<DrawerInfo>().gotoStep(EditorStep.ready);
        },
        child: Image.asset(
          'assets/images/stickers/niumao1.png',
          width: 50,
          height: 50,
          fit: BoxFit.cover,
        ),
      ),
    );
  }

  StickerDrawer _buildDrawerWidget() {
    final List<StickerItem> defaultStickers = [
        StickerItem(
          id: 'niumao1',
          path: 'assets/images/stickers/niumao1.png',
          category: '最近',
        ),
        StickerItem(
          id: 'niumao2',
          path: 'assets/images/stickers/niumao2.png',
          category: '前景',
        ),
        StickerItem(
          id: 'niumao3',
          path: 'assets/images/stickers/niumao3.png',
          category: '中景',
        ),
        StickerItem(
          id: 'padi1',
          path: 'assets/images/stickers/padi1.png',
          category: '背景',
        ),
    ];
    return StickerDrawer(
      stickerSelectPanel: StickerSelectPanel(
        stickers: defaultStickers,
      ),
    );
  }

  StickerDrawer _buildDrawerWidgetCustom() {
    final List<StickerItem> defaultStickers = [
      StickerItem(
        id: 'niumao1',
        path: 'assets/images/stickers/niumao1.png',
        category: '最近',
      ),
      StickerItem(
        id: 'niumao2',
        path: 'assets/images/stickers/niumao2.png',
        category: '前景',
      ),
      StickerItem(
        id: 'niumao3',
        path: 'assets/images/stickers/niumao3.png',
        category: '中景',
      ),
      StickerItem(
        id: 'padi1',
        path: 'assets/images/stickers/padi1.png',
        category: '背景',
      ),
    ];
    return StickerDrawer(
      stickerSelectPanel: StickerSelectPanel(
        customContent: (context, scrollCtrl, selectedIndex) {
          print('selected: ${selectedIndex}');
          return ListView.builder(
            controller: scrollCtrl,
            itemCount: defaultStickers.length,
            itemBuilder: (context, index) {
              return ListTile(
                title: Text(
                  defaultStickers[index].id,
                  style: const TextStyle(
                    color: Colors.black12,
                    fontSize: 16,
                  ),
                ),
                onTap: () {
                  // 添加贴纸
                  context.read<DrawerInfo>().quickAddSticker(
                    defaultStickers[index].path,
                  );
                },
              );
            },
          );
        },
      ),
    );
  }

}

使用单独功能(API)

1、添加背景贴纸(必须)

final drawerInfo = Provider.of<DrawerInfo>(context, listen: false);
      drawerInfo.bgImageFile = _imageFile;

2、添加贴纸

快捷添加:

await context.read<DrawerInfo>().quickAddSticker(path);

自定义添加:


// 加载图片
if (path.startsWith('http')) {
  // 网络图片加载
  final response = await NetworkAssetBundle(Uri.parse(path)).load(path);
  final Uint8List bytes = response.buffer.asUint8List();
  img = await decodeImageFromList(bytes);
} else {
  // 本地图片加载
  final ByteData data = await rootBundle.load(path);
  final Uint8List bytes = data.buffer.asUint8List();
  img = await decodeImageFromList(bytes);
}

// 初始化贴纸
final sticker = Sticker(
  stickerId: "sticker_id_123", // 贴纸ID,不可重复
  stickerName: "图层${_stickers.length + 1}",
  width: 100,
  height: 100,
  offset: const Offset(50, 50),
  brushPaths: [],
  rotation: 0,
  image: img,
);
// 添加贴纸
context.read<DrawerInfo>().addSticker(sticker);

3、删除贴纸

// 删除贴纸[stickerId]
context.read<DrawerInfo>().deleteStickerById(stickerId);

获取指定贴纸

// 获取指定贴纸
context.read<DrawerInfo>().getStickerById(stickerId);

获取当前选中的贴纸

// 获取当前选中的贴纸
String? selectedStickerId = context.read<DrawerInfo>().selectedStickerId;
if (selectedStickerId != null) {
  print('Selected Sticker ID: $selectedStickerId');
  Sticker? currentSticker = context.read<DrawerInfo>().getStickerById(stickerId);
} else {
  print('No sticker selected.');
}

获取贴纸列表