I've searched everywhere and have not so much experience in ClipPath I want is to make a layout similar to a Jigsaw Puzzle. I've already used Draggable and DragTarget for the text kind of puzzle but I want to render the image in the shape of a jigsaw and put the data empty until I drop a widget similar to that shape from the listview.builder, I found not many resources on this topic. below are the code and the layout I want to build.
import 'package:flutter/material.dart';
import 'data_model.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Puzzle Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Puzzle Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String text = '';
List<DataModel> dataModel = [];
List<DataModel> dataModel2 = [];
int rows = 4, columns = 4;
void _incrementCounter() {
for (var i = 1; i <= rows * columns; i++) {
dataModel.add(DataModel(text: 'Hello', number: i));
}
}
@override
void initState() {
super.initState();
_incrementCounter();
for (var model in dataModel) {
dataModel2.add(DataModel(text: model.text, number: model.number));
}
dataModel2.shuffle();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
title: Text(widget.title),
),
body: Column(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: GridView.builder(
itemCount: dataModel.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: rows,
mainAxisSpacing: 5,
crossAxisSpacing: 5),
itemBuilder: (context, index) {
return Center(
child: DragTarget<DataModel>(
builder: (BuildContext context,
List<Object?> candidateData,
List<dynamic> rejectedData) {
return Container(
color: dataModel[index].dataModel == null
? Colors.red
: Colors.green,
child: Center(
child: Text(
dataModel[index].dataModel == null
? 'No Data'
: '${dataModel[index].dataModel!.text} ${dataModel[index].dataModel!.number}',
style: TextStyle(
color: dataModel[index].dataModel == null
? null
: Colors.white,
fontWeight: FontWeight.bold),
),
),
);
},
onAccept: (data) {
setState(() {
if (data.number == dataModel[index].number) {
dataModel[index].dataModel = data;
dataModel2.remove(data);
}
});
},
onWillAccept: (data) {
return data?.number == dataModel[index].number;
},
),
);
}),
),
),
SizedBox(
height: 50,
child: ListView.builder(
itemCount: dataModel2.length,
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: LongPressDraggable<DataModel>(
data: dataModel2[index],
feedback: Material(
child: Text(
"${dataModel2[index].text} ${dataModel2[index].number}",
style: const TextStyle(fontWeight: FontWeight.bold),
),
),
// This is what shows while dragging the widget
childWhenDragging: Container(),
// This is what shows up when dragging
child: Text(
"${dataModel2[index].text} ${dataModel2[index].number}"), // This is the widget you drag
),
);
},
),
),
],
),
);
}
}
datamodel
class DataModel {
String text;
int number;
DataModel? dataModel;
DataModel({
required this.text,
required this.number,
this.dataModel,
});
}
