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
更多关于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')),
),
],
),
);
}
}