Skip to content

Commit 20724b1

Browse files
committed
Allow overriding placeholder decoration
1 parent 6a9afc3 commit 20724b1

File tree

1 file changed

+105
-63
lines changed

1 file changed

+105
-63
lines changed

lib/flutter_reorderable_list.dart

Lines changed: 105 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,23 @@ import 'dart:ui' show lerpDouble;
1414
typedef bool ReorderItemCallback(Key draggedItem, Key newPosition);
1515
typedef void ReorderCompleteCallback(Key draggedItem);
1616

17+
// Represents placeholder for currently dragged row including decorations
18+
// (i.e. before and after shadow)
19+
class DecoratedPlaceholder {
20+
DecoratedPlaceholder({
21+
this.offset,
22+
this.widget,
23+
});
24+
25+
// Height of decoration before widget
26+
final double offset;
27+
final Widget widget;
28+
}
29+
30+
// Decorates current placeholder widget
31+
typedef DecoratedPlaceholder DecoratePlaceholder(
32+
Widget widget, double decorationOpacity);
33+
1734
// Can be used to cancel reordering (i.e. when underlying data changed)
1835
class CancellationToken {
1936
void cancelDragging() {
@@ -32,12 +49,14 @@ class ReorderableList extends StatefulWidget {
3249
@required this.onReorder,
3350
this.onReorderDone,
3451
this.cancellationToken,
52+
this.decoratePlaceholder = _defaultDecoratePlaceholder,
3553
}) : super(key: key);
3654

3755
final Widget child;
3856

3957
final ReorderItemCallback onReorder;
4058
final ReorderCompleteCallback onReorderDone;
59+
final DecoratePlaceholder decoratePlaceholder;
4160

4261
final CancellationToken cancellationToken;
4362

@@ -152,7 +171,10 @@ class _ReorderableListState extends State<ReorderableList>
152171
Widget build(BuildContext context) {
153172
return new Stack(
154173
fit: StackFit.passthrough,
155-
children: <Widget>[widget.child, new _DragProxy()],
174+
children: <Widget>[
175+
widget.child,
176+
new _DragProxy(widget.decoratePlaceholder)
177+
],
156178
);
157179
}
158180

@@ -361,7 +383,7 @@ class _ReorderableListState extends State<ReorderableList>
361383
_finalAnimation.addListener(() {
362384
_dragProxy.offset =
363385
lerpDouble(dragProxyOffset, originalOffset, _finalAnimation.value);
364-
_dragProxy.shadowOpacity = 1.0 - _finalAnimation.value;
386+
_dragProxy.decorationOpacity = 1.0 - _finalAnimation.value;
365387
});
366388

367389
_recognizer?.dispose();
@@ -594,8 +616,12 @@ class _ReorderableItemState extends State<ReorderableItem> {
594616
//
595617

596618
class _DragProxy extends StatefulWidget {
619+
final DecoratePlaceholder decoratePlaceholder;
620+
597621
@override
598622
State<StatefulWidget> createState() => new _DragProxyState();
623+
624+
_DragProxy(this.decoratePlaceholder);
599625
}
600626

601627
class _DragProxyState extends State<_DragProxy> {
@@ -608,7 +634,7 @@ class _DragProxyState extends State<_DragProxy> {
608634

609635
void setWidget(Widget widget, RenderBox position) {
610636
setState(() {
611-
_shadowOpacity = 1.0;
637+
_decorationOpacity = 1.0;
612638
_widget = widget;
613639
final state = _ReorderableListState.of(context);
614640
RenderBox renderBox = state.context.findRenderObject();
@@ -633,11 +659,11 @@ class _DragProxyState extends State<_DragProxy> {
633659

634660
get height => _size.height;
635661

636-
double _shadowOpacity;
662+
double _decorationOpacity;
637663

638-
set shadowOpacity(double val) {
664+
set decorationOpacity(double val) {
639665
setState(() {
640-
_shadowOpacity = val;
666+
_decorationOpacity = val;
641667
});
642668
}
643669

@@ -652,63 +678,27 @@ class _DragProxyState extends State<_DragProxy> {
652678
final state = _ReorderableListState.of(context);
653679
state._dragProxy = this;
654680

655-
final double decorationHeight = 10.0;
656-
final mq = MediaQuery.of(context);
657-
658-
return _widget != null && _size != null && _offset != null
659-
? new Positioned.fromRect(
660-
child: Column(
661-
crossAxisAlignment: CrossAxisAlignment.stretch,
662-
children: <Widget>[
663-
Opacity(
664-
opacity: _shadowOpacity,
665-
child: Container(
666-
height: decorationHeight,
667-
decoration: BoxDecoration(
668-
border: Border(
669-
bottom: BorderSide(
670-
color: Color(0x50000000),
671-
width: 1.0 / mq.devicePixelRatio)),
672-
gradient: LinearGradient(
673-
begin: Alignment(0.0, -1.0),
674-
end: Alignment(0.0, 1.0),
675-
colors: <Color>[
676-
Color(0x00000000),
677-
Color(0x10000000),
678-
Color(0x30000000)
679-
])),
680-
)),
681-
IgnorePointer(
682-
child: MediaQuery.removePadding(
683-
context: context,
684-
child: _widget,
685-
removeTop: true,
686-
removeBottom: true,
687-
),
688-
),
689-
Opacity(
690-
opacity: _shadowOpacity,
691-
child: Container(
692-
height: decorationHeight,
693-
decoration: BoxDecoration(
694-
border: Border(
695-
top: BorderSide(
696-
color: Color(0x50000000),
697-
width: 1.0 / mq.devicePixelRatio)),
698-
gradient: LinearGradient(
699-
begin: Alignment(0.0, -1.0),
700-
end: Alignment(0.0, 1.0),
701-
colors: <Color>[
702-
Color(0x30000000),
703-
Color(0x10000000),
704-
Color(0x00000000)
705-
])),
706-
)),
707-
],
708-
),
709-
rect: new Rect.fromLTWH(_offsetX, _offset - decorationHeight,
710-
_size.width, _size.height + decorationHeight * 2 + 1.0))
711-
: new Container(width: 0.0, height: 0.0);
681+
if (_widget != null && _size != null && _offset != null) {
682+
final w = IgnorePointer(
683+
child: MediaQuery.removePadding(
684+
context: context,
685+
child: _widget,
686+
removeTop: true,
687+
removeBottom: true,
688+
),
689+
);
690+
691+
final decoratedPlaceholder =
692+
widget.decoratePlaceholder(w, _decorationOpacity);
693+
return Positioned(
694+
child: decoratedPlaceholder.widget,
695+
left: _offsetX,
696+
width: _size.width,
697+
top: offset - decoratedPlaceholder.offset,
698+
);
699+
} else {
700+
return new Container(width: 0.0, height: 0.0);
701+
}
712702
}
713703

714704
@override
@@ -762,3 +752,55 @@ class _Recognizer extends MultiDragGestureRecognizer<_VerticalPointerState> {
762752
@override
763753
String get debugDescription => "Vertical recognizer";
764754
}
755+
756+
DecoratedPlaceholder _defaultDecoratePlaceholder(
757+
Widget widget, double decorationOpacity) {
758+
final double decorationHeight = 10.0;
759+
760+
final decoratedWidget = Builder(builder: (BuildContext context) {
761+
final mq = MediaQuery.of(context);
762+
return Column(
763+
crossAxisAlignment: CrossAxisAlignment.stretch,
764+
children: <Widget>[
765+
Opacity(
766+
opacity: decorationOpacity,
767+
child: Container(
768+
height: decorationHeight,
769+
decoration: BoxDecoration(
770+
border: Border(
771+
bottom: BorderSide(
772+
color: Color(0x50000000),
773+
width: 1.0 / mq.devicePixelRatio)),
774+
gradient: LinearGradient(
775+
begin: Alignment(0.0, -1.0),
776+
end: Alignment(0.0, 1.0),
777+
colors: <Color>[
778+
Color(0x00000000),
779+
Color(0x10000000),
780+
Color(0x30000000)
781+
])),
782+
)),
783+
widget,
784+
Opacity(
785+
opacity: decorationOpacity,
786+
child: Container(
787+
height: decorationHeight,
788+
decoration: BoxDecoration(
789+
border: Border(
790+
top: BorderSide(
791+
color: Color(0x50000000),
792+
width: 1.0 / mq.devicePixelRatio)),
793+
gradient: LinearGradient(
794+
begin: Alignment(0.0, -1.0),
795+
end: Alignment(0.0, 1.0),
796+
colors: <Color>[
797+
Color(0x30000000),
798+
Color(0x10000000),
799+
Color(0x00000000)
800+
])),
801+
)),
802+
]);
803+
});
804+
return DecoratedPlaceholder(
805+
offset: decorationHeight, widget: decoratedWidget);
806+
}

0 commit comments

Comments
 (0)