I'm currently developing scratch-like block-coding application with flutter.
What I want to achieve is to make keyword-blocks listed at PaletteBlocks
Below is what I've implemented so far
// absolute_align.dart
class AbsoluteAlign extends StatelessWidget {
const AbsoluteAlign({
Key? key,
Alignment? alignment,
required this.child,
}) : alignment = alignment ?? Alignment.topLeft,
super(key: key);
final Alignment alignment;
final Widget child;
@override
Widget build(BuildContext context) {
AbsoluteAlignPosition position = AbsoluteAlignPosition(
context: context,
alignment: alignment,
horizontalMovement: 0,
verticalMovement: 0,
isActive: false,
);
return Positioned(
child: child,
top: position.top,
left: position.left,
bottom: position.bottom,
right: position.right,
);
}
}
class AnimatedAbsoluteAlign extends StatelessWidget {
AnimatedAbsoluteAlign({
Key? key,
Alignment? alignment,
required this.isActive,
required this.child,
required this.horizontalMovement,
required this.verticalMovement,
required this.duration,
}) : alignment = alignment ?? Alignment.topLeft,
super(key: key);
final Alignment alignment;
final Widget child;
final bool isActive;
final double horizontalMovement;
final double verticalMovement;
final Duration duration;
@override
Widget build(BuildContext context) {
AbsoluteAlignPosition position = AbsoluteAlignPosition(
context: context,
alignment: alignment,
horizontalMovement: horizontalMovement,
verticalMovement: verticalMovement,
isActive: isActive,
);
return AnimatedPositioned(
duration: duration,
child: child,
top: position.top,
left: position.left,
bottom: position.bottom,
right: position.right,
curve: Curves.ease,
);
}
}
class AbsoluteAlignPosition {
// skipped for brevity
}
// studio.dart
/// Widget structure:
/// [SingleChildScrollView] >> [Stack] >> [List<AbsoluteAlign>]
class Studio extends StatelessWidget {
Studio({
Key? key,
required this.width,
required this.height,
}) : super(key: key);
final ScrollController _scrollController = ScrollController();
final double width;
final double height;
@override
Widget build(BuildContext context) {
final studioBloc = context.read<StudioBloc>();
final paletteBloc = context.watch<PaletteBloc>();
final vm = studioBloc.state.vm;
return SingleChildScrollView(
controller: _scrollController,
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics(),
),
child: Container(
width: width,
height: height,
child: Stack(
fit: StackFit.loose,
children: [
AbsoluteAlign(child: Background()),
AbsoluteAlign(child: Editor()),
AbsoluteAlign(
child: StudioTitle(
title: vm.runtime.current.name,
),
),
AbsoluteAlign(
alignment: Alignment.bottomCenter,
child: Toolbar(),
),
AnimatedAbsoluteAlign(
alignment: Alignment.centerRight,
verticalMovement: 0,
horizontalMovement: TangibleConstant.paletteWidth - 30,
isActive: paletteBloc.state.status == PaletteStatus.closed,
duration: const Duration(milliseconds: 200),
child: Palette(),
),
],
),
),
);
}
}
// palette.dart
class Palette extends StatelessWidget {
const Palette({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => _onTap(context),
onHorizontalDragUpdate: (details) =>
_onHorizontalDragUpdate(context, details),
child: Container(
width: TangibleConstant.paletteWidth,
height: TangibleConstant.paletteHeight,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)),
color: TangibleColors.studioTeal,
),
child: PaletteBlocks(),
),
);
}
// skipped for brevity
}
class PaletteBlocks extends StatelessWidget {
PaletteBlocks({Key? key}) : super(key: key);
final ScrollController _scrollController = ScrollController();
@override
Widget build(BuildContext context) {
return ListView(
padding: EdgeInsets.symmetric(horizontal: 30, vertical: 15),
controller: _scrollController,
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics(),
),
children: _buildPaletteBlocks(context),
);
}
List<Widget> _buildPaletteBlocks(BuildContext context) {
final studioBloc = context.read<StudioBloc>();
final vm = studioBloc.state.vm;
return vm.registeredBlocks
.map((block) => PaletteBlock(block: block))
.fold<List<Widget>>(
<Widget>[],
(previousValue, element) => [
...previousValue,
SizedBox(
height: 5,
),
element
]).toList();
}
}
class PaletteBlock extends StatelessWidget {
PaletteBlock({required this.block});
final Block block;
@override
Widget build(BuildContext context) {
return Draggable(
data: block,
feedback: SizedBox(height: TangibleConstant.paletteBlockHeight),
child: Container(
width: TangibleConstant.paletteBlockWidth,
height: TangibleConstant.paletteBlockHeight,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)),
color: TangibleColors.blockPurple,
border: Border.all(color: Colors.deepPurple),
),
child: Center(
child: Text(
block.opcode,
style: TangibleTheme.standard.textTheme.headline4,
),
),
),
);
}
}
But when I drag that keyword-block, it does not move, although the dragging action seems to be detected by the widget since onDragStarted
method from Draggable
fires when I drag the block. What should I do to fix it?
My dummy mistake. I mistakely understood what feedback
and child
does in Draggable widget. feedback
is the widget attatched to the pointer (a.k.a your finger). child
acts like placeholder in this case.