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.plistAndroidManifest.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.topStickOn.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')),
          ),
        ],
      ),
    );
  }
}
回到顶部