feat: accept edge swipes across the whole margin beside the text column
This commit is contained in:
parent
56f3d959fa
commit
6f9c0e587a
3 changed files with 70 additions and 9 deletions
|
|
@ -21,6 +21,7 @@ class SwipeNavigator extends StatefulWidget {
|
|||
this.forwardView,
|
||||
this.backTitle,
|
||||
this.forwardTitle,
|
||||
this.contentWidth,
|
||||
super.key,
|
||||
});
|
||||
|
||||
|
|
@ -35,6 +36,11 @@ class SwipeNavigator extends StatefulWidget {
|
|||
final String? backTitle;
|
||||
final String? forwardTitle;
|
||||
|
||||
/// Width of the content column; swipes are accepted anywhere in the empty
|
||||
/// margin beside it, plus a base zone at each screen edge. Null keeps only
|
||||
/// the base edge zone.
|
||||
final double? contentWidth;
|
||||
|
||||
final Color background;
|
||||
final VoidCallback onBack;
|
||||
final VoidCallback onForward;
|
||||
|
|
@ -73,10 +79,16 @@ class _SwipeNavigatorState extends State<SwipeNavigator>
|
|||
|
||||
bool get _settledAnimating => _settling != null && _settle.isAnimating;
|
||||
|
||||
/// How close to a screen edge a drag must begin to navigate; horizontal
|
||||
/// drags elsewhere belong to text selection.
|
||||
/// Base zone at each screen edge that always swipes; horizontal drags
|
||||
/// elsewhere belong to text selection.
|
||||
static const _edgeZone = 40.0;
|
||||
|
||||
/// The swipe zone: the whole margin beside the content column, with the
|
||||
/// base zone as the floor.
|
||||
double _stripWidth(double width) => widget.contentWidth == null
|
||||
? _edgeZone
|
||||
: math.max(_edgeZone, (width - widget.contentWidth!) / 2);
|
||||
|
||||
void _onDragStart(DragStartDetails details) {
|
||||
if (_settledAnimating) return;
|
||||
setState(() => _dragging = true);
|
||||
|
|
@ -172,23 +184,23 @@ class _SwipeNavigatorState extends State<SwipeNavigator>
|
|||
offset: Offset(dx, 0),
|
||||
child: widget.child,
|
||||
),
|
||||
// Only horizontal drags that begin at a screen edge navigate;
|
||||
// the strips are translucent, so taps, vertical scrolling and
|
||||
// text selection still pass through everywhere.
|
||||
_edgeStrip(fromLeft: true),
|
||||
_edgeStrip(fromLeft: false),
|
||||
// Horizontal drags in the strips navigate; elsewhere they select
|
||||
// text. The strips are translucent, so taps, vertical scrolling
|
||||
// and mid-page selection still pass through everywhere.
|
||||
_edgeStrip(fromLeft: true, width: _stripWidth(_width)),
|
||||
_edgeStrip(fromLeft: false, width: _stripWidth(_width)),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _edgeStrip({required bool fromLeft}) => Positioned(
|
||||
Widget _edgeStrip({required bool fromLeft, required double width}) => Positioned(
|
||||
left: fromLeft ? 0 : null,
|
||||
right: fromLeft ? null : 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
width: _edgeZone,
|
||||
width: width,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onHorizontalDragStart: _onDragStart,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue