效果图
主要实现功能
- 选取系统相册图片
- 切割图片
- 打乱图片
- 移动图片
选取系统相册
用的是flutter的image_picker的图片选择器.自己集成一下就可以。不再多说
image_picker: 0.6.7+4
切割图片
新建一个类继承CustomPainter, 去进行图片操作,
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
/// 图片裁剪
class ImageClipper extends CustomPainter {
final ui.Image image;
final double left;
final double top;
final double right;
final double bottom;
final int currentIndex;
ImageClipper(this.image, this.left, this.top, this.right, this.bottom,
this.currentIndex);
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint();
canvas.drawImageRect(
image,
Rect.fromLTRB(image.width * left, image.height * top,
image.width * right, image.height * bottom),
Rect.fromLTWH(0, 0, size.width, size.height),
paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return false;
}
}
然后显示出来
Container(
color: Colors.green,
child: GestureDetector(
child: CustomPaint(
painter: clipper,
size: Size(80, 80),
),
onTap: () {
tapList.add(clipper.currentIndex);
showAnimation(clipper.currentIndex);
},
),
);
上面代码添加了,点击方法。用来进行模块移动, 其中clipper就是切割好的图片,返回来的对象,
比较重要的一点是选择的需要对选择好了的本地图片处理一下
Future _loadImge() async {
ImageStream imageStream = FileImage(imgPath).resolve(ImageConfiguration());
Completer completer = Completer();
void imageListener(ImageInfo info, bool synchronousCall) {
ui.Image image = info.image;
completer.complete(image);
imageStream.removeListener(ImageStreamListener(imageListener));
}
imageStream.addListener(ImageStreamListener(imageListener));
return completer.future;
}
clip(left, top, right, bottom, currentIndex) async {
ui.Image uiImage;
_loadImge().then((image) {
uiImage = image;
}).whenComplete(() {
clipperList
.add(ImageClipper(uiImage, left, top, right, bottom, currentIndex));
setState(() {});
});
}
打乱图片
这个可以用shuffle()函数去处理,但是打乱之后的数组,不一定能够通过移动完成拼图
所以采用了一个相当于比较稳的方法,这里提供一下思路。循环次数去进行点击移动操作,记录点击的图片模块,进行移动,这样自动还原的时候把记录的数组进行倒叙之后,在进行移动就可以还原了。。完美
感兴趣的同学可以用A*搜索算法。
移动图片
更换数组位置即可。这个比较简单了
int emptyIndex = 0;
int currentIndex = 0;
ImageClipper emptyClipper;
for (int i = 0; i < clipperList.length; i++) {
if (clipperList[i].currentIndex == 8) {
emptyIndex = i;
emptyClipper = clipperList[i];
}
if (clipperList[i].currentIndex == current) {
currentIndex = i;
}
}
// 判断是否可以移动
if (isCanMove(emptyIndex, currentIndex)) {
// 不移动
clipperList[emptyIndex] = clipperList[currentIndex];
clipperList[currentIndex] = emptyClipper;
if (mounted) {
setState(() {});
// 判断是否完成
isSuccess();
}
}
针对9宫格来说。没有写通用的。
bool isCanMove(empty, current) {
bool isCanMove = false;
switch (empty) {
case 0:
{
if (current == 1 || current == 3) isCanMove = true;
break;
}
case 1:
{
if (current == 0 || current == 2 || current == 4) isCanMove = true;
break;
}
case 2:
{
if (current == 1 || current == 5) isCanMove = true;
break;
}
case 3:
{
if (current == 0 || current == 4 || current == 6) isCanMove = true;
break;
}
case 4:
{
if (current == 1 || current == 3 || current == 5 || current == 7)
isCanMove = true;
break;
}
case 5:
{
if (current == 2 || current == 4 || current == 8) isCanMove = true;
break;
}
case 6:
{
if (current == 3 || current == 7) isCanMove = true;
break;
}
case 7:
{
if (current == 4 || current == 6 || current == 8) isCanMove = true;
break;
}
case 8:
{
if (current == 5 || current == 7) isCanMove = true;
break;
}
default:
}
return isCanMove;
}