Flutter粘性元素管理插件stick_it的使用

Flutter粘性元素管理插件stick_it的使用

Stick It

Stick It 是一个基于 flutter_simple_sticker_view 的分支。该插件允许用户将贴纸附加到另一张图像上。贴纸可以移动、缩放,并且现在还可以旋转。你可以导出你创建的组合为图像。

最简单的例子 高级例子

开始使用

在你的 pubspec.yaml 文件中添加 stick_it 作为依赖项。 你可以查看 安装页面。 查看 示例页面 以获取带有背景图像选择器、图像导出、图像保存和自定义设置的高级示例。

dependencies:
  stick_it: ^latest_version

导入库

在你的 Dart 文件中导入 stick_it 库:

import 'package:stick_it/stick_it.dart';

简单的例子

以下是一个最简单的例子,展示了如何在一张背景图上放置多个贴纸。

import 'package:flutter/material.dart';
import 'package:stick_it/stick_it.dart';

class SimplestExample extends StatelessWidget {
  const SimplestExample({Key? key}) : super(key: key);
  static String routeName = 'simplest-example';
  static String routeTitle = 'Simplest Example';
  final String _background =
      'https://images.unsplash.com/photo-1545147986-a9d6f2ab03b5?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=934&q=80';

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(routeTitle),
      ),
      body: StickIt(
        /// StickIt 需要两个命名参数。
        ///
        /// [Widget] child - 贴纸应该放置在其上的子组件。
        /// [List<Image>] stickerList - 用户可用的贴纸列表。
        ///
        /// StickIt 支持许多与样式相关的可选命名参数,
        /// 你可以在 AdvancedExample 中更改并查看它们。(待定)
        child: Image.network(_background),
        stickerList: [
          Image.asset('assets/icons8-anubis-48.png'),
          Image.asset('assets/icons8-bt21-shooky-48.png'),
          Image.asset('assets/icons8-fire-48.png'),
          Image.asset('assets/icons8-jake-48.png'),
          Image.asset('assets/icons8-keiji-akaashi-48.png'),
          Image.asset('assets/icons8-mate-48.png'),
          Image.asset('assets/icons8-pagoda-48.png'),
          Image.asset('assets/icons8-spring-48.png'),
          Image.asset('assets/icons8-totoro-48.png'),
          Image.asset('assets/icons8-year-of-dragon-48.png'),
        ],
      ),
    );
  }
}

支持的参数

以下是 StickIt 类支持的一些参数及其描述:

参数名称 类型 是否必需 默认值 描述
child Widget 是 你希望放置贴纸的内容
stickerList List<Image> 是 贴纸列表,这些贴纸将在底部面板中显示,并可以放置在你的子组件上
devicePixelRatio double 否 3.0 设备像素比
panelBackgroundColor Color 否 Colors.black 底部面板的背景颜色
panelHeight double 否 200.0 底部面板的高度
panelStickerBackgroundColor Color 否 Colors.white10 贴纸容器的背景颜色
panelStickerCrossAxisCount int 否 4 定义每个网格行中包含的贴纸数量
panelStickerAspectRatio double 否 1.0 子轴对主轴的比率
stickerMaxScale double 否 2.0 贴纸的最大缩放比例
stickerMinScale double 否 0.5 贴纸的最小缩放比例
stickerRotatable bool 否 true 控制贴纸是否可旋转,如果设为 false,则不旋转
stickerSize double 否 100.0 放置在 Stack 中时贴纸的 Rect 大小
viewPort Size 否 Size(constraints.maxWidth, constraints.maxHeight) 视口大小,默认使用可用空间

支持的方法

以下是 StickIt 类支持的一些方法及其描述:

方法名 返回类型 描述
exportImage() Future 从你的组合中创建一个 Uint8List,可以用来保存为图像。在生成之前,它会清除所有选择,因此它们不会出现在新创建的图像上。

高级用法

以下是一个更高级的例子,展示了如何让用户从相册或相机中选择背景,并将创建的图像保存到相册中。

预览

高级例子

依赖项安装

我们依赖一些外部包来处理图像及其保存位置:

  • Extended Image - 一个强大的图像官方扩展库,支持占位符(加载/失败状态)、缓存网络、缩放图像、照片视图、滑动页面、编辑(裁剪、旋转、翻转)等。
  • Image Picker - 一个用于从图库中选择图片或使用相机拍摄新图片的 Flutter 插件。
  • Gallery Saver - 将网络或临时文件保存到外部存储。图片和视频将显示在 Android 图库和 iOS 相册中。
  • Path Provider - 一个用于查找文件系统中常用位置的 Flutter 插件。支持 iOS、Android、Linux 和 MacOS。并非所有方法都支持所有平台。
  • Uuid - 一个简单快速的 RFC4122 UUID 生成器。

请注意,你必须遵循这些包的安装说明,因为有些需要修改你的 Info.plist 或 AndroidManifest.xml。

代码

import 'dart:io';

import 'package:example/components/circular_icon_button.dart';
import 'package:extended_image/extended_image.dart';
import 'package:flutter/material.dart';
import 'package:gallery_saver/gallery_saver.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:stick_it/stick_it.dart';
import 'package:uuid/uuid.dart';

class AdvancedExample extends StatefulWidget {
  AdvancedExample({Key? key}) : super(key: key);
  static String routeName = 'advanced-example';
  static String routeTitle = 'Advanced Example';

  [@override](/user/override)
  _AdvancedExampleState createState() => _AdvancedExampleState();
}

class _AdvancedExampleState extends State<AdvancedExample> {
  /// 背景图像
  final String _background =
      'https://images.unsplash.com/photo-1545147986-a9d6f2ab03b5?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=934&q=80';

  /// 用于从相册或相机获取图像
  final _picker = ImagePicker();

  /// 用于调用 exportImage 函数的引用
  late StickIt _stickIt;

  /// 用户选择的图像文件
  File? _image;

  [@override](/user/override)
  Widget build(BuildContext context) {
    double bottomPadding = MediaQuery.of(context).size.height / 4;
    double rightPadding = MediaQuery.of(context).size.width / 12;
    double boxSize = 56.0;
    _stickIt = StickIt(
      child: _image == null ? Image.network(_background) : Image.file(_image!, fit: BoxFit.cover),
      stickerList: [
        Image.asset(
          'assets/icons8-anubis-48.png',
          height: 100,
          width: 100,
          fit: BoxFit.cover,
        ),
        Image.asset('assets/icons8-bt21-shooky-48.png'),
        Image.asset('assets/icons8-fire-48.png'),
        Image.asset('assets/icons8-jake-48.png'),
        Image.asset('assets/icons8-keiji-akaashi-48.png'),
        Image.asset('assets/icons8-mate-48.png'),
        Image.asset('assets/icons8-pagoda-48.png'),
        Image.asset('assets/icons8-spring-48.png'),
        Image.asset('assets/icons8-totoro-48.png'),
        Image.asset('assets/icons8-year-of-dragon-48.png'),
      ],
      key: UniqueKey(),
      panelHeight: 175,
      panelBackgroundColor: Colors.white,
      panelStickerBackgroundColor: Theme.of(context).primaryColorLight,
      stickerSize: 100,
    );

    return Scaffold(
      appBar: AppBar(
        title: Text(AdvancedExample.routeTitle),
      ),
      body: Stack(
        children: [
          _stickIt,
          Positioned(
            bottom: bottomPadding,
            right: rightPadding,
            child: Column(
              children: [
                ////////////////////////////////////////////////////////
                //               SAVE IMAGE TO GALLERY                //
                ////////////////////////////////////////////////////////
                CircularIconButton(
                  onTap: () async {
                    final image = await _stickIt.exportImage();
                    final directory = await getApplicationDocumentsDirectory();
                    final path = directory.path;
                    final uniqueIdentifier = Uuid().v1();
                    final file = await new File('$path/$uniqueIdentifier.png').create();
                    file.writeAsBytesSync(image);
                    GallerySaver.saveImage(file.path, albumName: 'Stick It').then((value) {
                      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                        content: Text("Image saved in the gallery album 'Stick It', go take a look!"),
                      ));
                    });
                  },
                  boxColor: Theme.of(context).primaryColorDark,
                  boxWidth: boxSize,
                  boxHeight: boxSize,
                  iconWidget: Icon(
                    Icons.check,
                    color: Colors.white,
                    size: 36,
                  ),
                ),
                SizedBox(
                  height: 12,
                ),
                ////////////////////////////////////////////////////////
                //                  SELECT BACKGROUND                 //
                ////////////////////////////////////////////////////////
                CircularIconButton(
                  onTap: () {
                    generateModal(context);
                  },
                  boxWidth: boxSize,
                  boxHeight: boxSize,
                  iconWidget: Icon(
                    Icons.camera,
                    color: Colors.white,
                  ),
                  boxColor: Theme.of(context).primaryColorDark,
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

  /// 方法用于从相册或相机获取图像
  Future<void> getImage(ImageSource source) async {
    final pickedFile = await _picker.pickImage(source: source);
    if (pickedFile != null) {
      setState(() {
        _image = File(pickedFile.path);
      });
    } else {
      print('No image selected.');
    }
  }

  /// 生成模态对话框,用户可以选择从相册或相机中选择图片
  void generateModal(BuildContext context) {
    showModalBottomSheet<void>(
      context: context,
      builder: (BuildContext context) {
        return Container(
          height: 128,
          color: Colors.white,
          child: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              mainAxisSize: MainAxisSize.min,
              children: [
                ////////////////////////////////////////////////////////
                //                  IMAGE FROM GALLERY                //
                ////////////////////////////////////////////////////////
                Expanded(
                  child: InkWell(
                    onTap: () {
                      getImage(ImageSource.gallery);
                      Navigator.pop(context);
                    },
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Icon(
                          Icons.photo,
                          color: Theme.of(context).primaryColor,
                        ),
                        SizedBox(
                          width: 12,
                        ),
                        Container(
                          child: Text('Select img from gallery'),
                          width: 200,
                        )
                      ],
                    ),
                  ),
                ),
                Divider(
                  height: 2,
                  indent: 64,
                  endIndent: 64,
                ),
                ////////////////////////////////////////////////////////
                //                 IMAGE FROM CAMERA                  //
                ////////////////////////////////////////////////////////
                Expanded(
                  child: InkWell(
                    onTap: () {
                      getImage(ImageSource.camera);
                      Navigator.pop(context);
                    },
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Icon(
                          Icons.camera_alt,
                          color: Theme.of(context).primaryColor,
                        ),
                        SizedBox(
                          width: 12,
                        ),
                        Container(
                          child: Text('Select img from camera'),
                          width: 200,
                        )
                      ],
                    ),
                  ),
                ),
              ],
            ),
          ),
        );
      },
    );
  }
}

更多关于Flutter粘性元素管理插件stick_it的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter粘性元素管理插件stick_it的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


stick_it 是一个 Flutter 插件,用于在滚动视图中创建粘性元素(Sticky Headers)。它允许你在滚动时使某些元素固定在屏幕的顶部或底部,类似于表格中的表头或页脚。

以下是 stick_it 的基本使用方法:

1. 添加依赖

首先,在 pubspec.yaml 文件中添加 stick_it 依赖:

dependencies:
  flutter:
    sdk: flutter
  stick_it: ^1.0.0  # 请检查最新版本

然后运行 flutter pub get 来安装依赖。

2. 导入包

在需要使用 stick_it 的地方导入包:

import 'package:stick_it/stick_it.dart';

3. 使用 StickIt 组件

StickIt 是一个包裹组件,用于创建粘性元素。你可以在 StickIt 中包裹需要固定的部分,并将其与其他部分组合在一起。

class MyStickyHeaderPage extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Sticky Header Example'),
      ),
      body: ListView(
        children: [
          StickIt(
            stickOn: StickOn.top,  // 固定在顶部
            child: Container(
              color: Colors.blue,
              padding: EdgeInsets.all(16.0),
              child: Text(
                'Sticky Header',
                style: TextStyle(color: Colors.white, fontSize: 20),
              ),
            ),
          ),
          Container(
            height: 1000,
            color: Colors.grey[300],
            child: Center(child: Text('Scroll Content')),
          ),
        ],
      ),
    );
  }
}

4. 滚动时粘性元素的效果

在上面的代码中,StickIt 包裹的 Container 会在滚动时固定在屏幕顶部,直到用户滚动到下一个粘性元素或到达列表的末尾。

5. 更多配置

StickIt 还有其他配置选项,例如:

  • stickOn: 定义粘性元素固定的位置(StickOn.top 或 StickOn.bottom)。
  • visibilityFactor: 控制粘性元素的可见性因子。
  • controller: 使用 ScrollController 来控制滚动行为。

6. 示例代码

以下是一个更复杂的示例,展示如何在 StickIt 中使用多个粘性元素:

class MyStickyHeaderPage extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Sticky Header Example'),
      ),
      body: ListView(
        children: [
          StickIt(
            stickOn: StickOn.top,
            child: Container(
              color: Colors.blue,
              padding: EdgeInsets.all(16.0),
              child: Text(
                'Header 1',
                style: TextStyle(color: Colors.white, fontSize: 20),
              ),
            ),
          ),
          Container(
            height: 200,
            color: Colors.green,
            child: Center(child: Text('Section 1 Content')),
          ),
          StickIt(
            stickOn: StickOn.top,
            child: Container(
              color: Colors.red,
              padding: EdgeInsets.all(16.0),
              child: Text(
                'Header 2',
                style: TextStyle(color: Colors.white, fontSize: 20),
              ),
            ),
          ),
          Container(
            height: 200,
            color: Colors.yellow,
            child: Center(child: Text('Section 2 Content')),
          ),
        ],
      ),
    );
  }
}
回到顶部