Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

updated horizontal scrolling inside bs #6

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 59 additions & 23 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:example/home_page.dart';
import 'package:flutter/material.dart';
import 'package:tapped_bottom_sheet/scrollable_bottom_sheet.dart';

void main() {
runApp(const MainApp());
Expand All @@ -10,28 +10,64 @@ class MainApp extends StatelessWidget {

@override
Widget build(BuildContext context) {
return const MaterialApp(
home: HomePage(),
);
}
}

class TestHomePage extends StatelessWidget {
const TestHomePage({super.key});

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Test"),
),
body: ListView.builder(
itemBuilder: (context, index) {
return ElevatedButton(
onPressed: () {},
child: Text(index.toString()),
);
},
final maxHeight = MediaQuery.of(context).size.height - kToolbarHeight - 100;
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Bottom Sheet Example'),
),
body: Stack(
children: [
Positioned.fill(
child: Container(
color: Colors.green,
),
),
Align(
alignment: Alignment.bottomCenter,
child: ScrollableBottomSheet(
snapPositions: [maxHeight / 2],
initialPosition: maxHeight / 2,
maxHeight: maxHeight,
minHeight: 100,
builder: (context, scrollController) {
return SingleChildScrollView(
controller: scrollController,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text("Horizontal Scroll"),
const SizedBox(height: 8),
SizedBox(
height: 100,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.only(right: 8.0),
child: Container(
color: Colors.red,
width: 100,
child: Text(index.toString()),
),
);
},
),
),
Container(
height: 200,
),
],
),
);
},
borderRadiusTop: 15,
borderColor: Colors.black,
backgroundColor: Colors.white,
),
),
],
),
),
);
}
Expand Down
92 changes: 59 additions & 33 deletions lib/scrollable_bottom_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ class ScrollableBottomSheetState extends State<ScrollableBottomSheet>

bool get _isPanelOpen => _animationController.value == 1.0;

bool _isHorizontalScrolling = false;

double _pixelToValue(double pixels) {
return (pixels - widget.minHeight) / (widget.maxHeight - widget.minHeight);
}
Expand Down Expand Up @@ -130,41 +132,63 @@ class ScrollableBottomSheetState extends State<ScrollableBottomSheet>
final borderRadius =
BorderRadius.vertical(top: Radius.circular(widget.borderRadiusTop));

return GestureListener(
canDrag: widget.canDrag,
onVerticalDragUpdate: (details) => _onDragUpdate(details),
onVerticalDragEnd: (details) => _onDragEnd(details),
onVerticalDragCancel: () => _handleDragCancel(),
child: MediaQuery.removePadding(
context: context,
removeTop: true,
child: Container(
decoration: BoxDecoration(
boxShadow: widget.shadows,
borderRadius: borderRadius,
color: widget.backgroundColor,
),
// Use a foreground decoration to make sure we don't allocate more height.
foregroundDecoration: ShapeDecoration(
shape: NonUniformBorder(
topWidth: 2,
color: widget.borderColor,
return NotificationListener(
onNotification: (scrollNotification) {
if (scrollNotification is ScrollStartNotification &&
scrollNotification.metrics.axis == Axis.horizontal) {
_isHorizontalScrolling = true;
}

if (scrollNotification is ScrollUpdateNotification &&
scrollNotification.metrics.axis == Axis.horizontal) {
if (scrollNotification.dragDetails == null) {
_isHorizontalScrolling = false;
}
}

if (scrollNotification is ScrollEndNotification &&
scrollNotification.metrics.axis == Axis.horizontal) {
_isHorizontalScrolling = false;
}

return false;
},
Comment on lines +135 to +155
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added some docs to this section because the bottom sheet is already complex :S
You can take the parts that you like.

    return NotificationListener<ScrollNotification>(
      // Disable vertical scrolling when the user is scrolling in a nested
      // horizontal scroll view. Otherwise we should slightly move the bottom
      // sheet vertically up and down which feels buggy.
      onNotification: (notification) {
        if (notification.metrics.axis != Axis.horizontal) {
          return false;
        }

        if (notification is ScrollStartNotification) {
          _isHorizontalScrolling = true;
        }
        if (notification is ScrollEndNotification) {
          _isHorizontalScrolling = false;
        }

        // Drag details are null if the user started a scroll and the
        // scrollview is continue to scroll without the user touching the view.
        if (notification is ScrollUpdateNotification &&
            notification.dragDetails == null) {
          _isHorizontalScrolling = false;
        }

        return false;
      },

child: GestureListener(
canDrag: widget.canDrag,
onVerticalDragUpdate: (details) => _onDragUpdate(details),
onVerticalDragEnd: (details) => _onDragEnd(details),
onVerticalDragCancel: () => _handleDragCancel(),
child: MediaQuery.removePadding(
context: context,
removeTop: true,
child: Container(
decoration: BoxDecoration(
boxShadow: widget.shadows,
borderRadius: borderRadius,
color: widget.backgroundColor,
),
),
child: ClipRRect(
borderRadius: borderRadius,
child: AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return SizedBox(
height: _sizeTween.transform(_animationController.value),
child: child,
);
},
child: Builder(
builder: (context) =>
widget.builder(context, _scrollController),
// Use a foreground decoration to make sure we don't allocate more height.
foregroundDecoration: ShapeDecoration(
shape: NonUniformBorder(
topWidth: 2,
color: widget.borderColor,
borderRadius: borderRadius,
),
),
child: ClipRRect(
borderRadius: borderRadius,
child: AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return SizedBox(
height: _sizeTween.transform(_animationController.value),
child: child,
);
},
child: Builder(
builder: (context) =>
widget.builder(context, _scrollController),
),
),
),
),
Expand All @@ -180,6 +204,8 @@ class ScrollableBottomSheetState extends State<ScrollableBottomSheet>
final primaryDelta = delta.dy;
_didStartScrolling = true;

if (_isHorizontalScrolling) return;

if (_isScrollingEnabled && _isPanelOpen) {
// _drag might be null if the drag activity ended and called _disposeDrag.
assert(_hold == null || _drag == null);
Expand Down