Merge pull request #8 from NikhilVadoliya/dev

Code Refactor and implement swipe feature for open/close drawer
master
NikhilVadoliya 4 years ago committed by GitHub
commit 298a46b22a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -30,12 +30,12 @@ class _MyAppState extends State<MyApp> {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: SliderMenuContainer(
body: Padding(
padding: const EdgeInsets.only(top: 0),
child: SliderMenuContainer(
appBarColor: Colors.white,
key: _key,
appBarPadding: const EdgeInsets.only(top: 20),
sliderMenuOpenOffset: 250,
appBarHeight: 60,
sliderMenuOpenSize: 200,
title: Text(
title,
style: TextStyle(fontSize: 22, fontWeight: FontWeight.w700),
@ -50,6 +50,7 @@ class _MyAppState extends State<MyApp> {
),
sliderMain: MainWidget()),
),
),
);
}
}

@ -27,8 +27,11 @@ class _MainWidgetState extends State<MainWidget> {
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(20),
child: ListView.separated(
padding: const EdgeInsets.symmetric(horizontal: 10),
scrollDirection: Axis.vertical,
// physics: BouncingScrollPhysics(),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
itemBuilder: (builder, index) {
return LimitedBox(
maxHeight: 150,

@ -1,4 +1,4 @@
library flutter_slider_drawer;
export 'package:flutter_slider_drawer/src/slider_open.dart';
export 'package:flutter_slider_drawer/src/slider_direction.dart';
export 'package:flutter_slider_drawer/src/slider.dart';

@ -0,0 +1,76 @@
import 'package:flutter/material.dart';
import 'package:flutter_slider_drawer/src/slider_direction.dart';
class SliderAppBar extends StatelessWidget {
final EdgeInsets appBarPadding;
final Color appBarColor;
final Widget drawerIcon;
final Color splashColor;
final Color drawerIconColor;
final double drawerIconSize;
final double appBarHeight;
final AnimationController animationController;
final VoidCallback onTap;
final Widget title;
final bool isTitleCenter;
final Widget trailing;
final SlideDirection slideDirection;
const SliderAppBar(
{Key key,
this.appBarPadding,
this.appBarColor,
this.drawerIcon,
this.splashColor,
this.drawerIconColor,
this.drawerIconSize,
this.animationController,
this.onTap,
this.title,
this.isTitleCenter,
this.trailing,
this.slideDirection, this.appBarHeight})
: super(key: key);
@override
Widget build(BuildContext context) {
return Container(
height: appBarHeight,
padding: appBarPadding ?? const EdgeInsets.only(top: 24),
color: appBarColor,
child: Row(
children: appBar(),
),
);
}
List<Widget> appBar() {
List<Widget> list = [
drawerIcon ??
IconButton(
splashColor: splashColor ?? Colors.black,
icon: AnimatedIcon(
icon: AnimatedIcons.menu_close,
color: drawerIconColor,
size: drawerIconSize,
progress: animationController),
onPressed: () => onTap()),
Expanded(
child: isTitleCenter
? Center(
child: title,
)
: title,
),
trailing ??
SizedBox(
width: 35,
)
];
if (slideDirection == SlideDirection.RIGHT_TO_LEFT) {
return list.reversed.toList();
}
return list;
}
}

@ -0,0 +1,36 @@
import 'dart:ui';
import 'package:flutter_slider_drawer/flutter_slider_drawer.dart';
class Utils {
///
/// This method get Offset base on [sliderOpen] type
///
static Offset getOffsetValues(SlideDirection direction, double value) {
switch (direction) {
case SlideDirection.LEFT_TO_RIGHT:
return Offset(value, 0);
case SlideDirection.RIGHT_TO_LEFT:
return Offset(-value, 0);
case SlideDirection.TOP_TO_BOTTOM:
return Offset(0, value);
default:
return Offset(value, 0);
}
}
static Offset getOffsetValueForShadow(
SlideDirection direction, double value, double slideOpenWidth) {
switch (direction) {
case SlideDirection.LEFT_TO_RIGHT:
return Offset(value - (slideOpenWidth > 50 ? 20 : 10), 0);
case SlideDirection.RIGHT_TO_LEFT:
return Offset(-value - 5, 0);
case SlideDirection.TOP_TO_BOTTOM:
return Offset(0, value - (slideOpenWidth > 50 ? 15 : 5));
default:
return Offset(value - 30.0, 0);
}
}
}

@ -0,0 +1,34 @@
import 'package:flutter/material.dart';
import 'package:flutter_slider_drawer/src/slider_direction.dart';
///
/// Build and Align the Menu widget based on the slide open type
///
class SlideMenuBar extends StatelessWidget {
final SlideDirection slideDirection;
final double sliderMenuOpenSize;
final Widget sliderMenu;
const SlideMenuBar(
{Key key, this.slideDirection, this.sliderMenuOpenSize, this.sliderMenu})
: super(key: key);
@override
Widget build(BuildContext context) {
var container = Container(
width: sliderMenuOpenSize,
child: sliderMenu,
);
switch (slideDirection) {
case SlideDirection.LEFT_TO_RIGHT:
return container;
break;
case SlideDirection.RIGHT_TO_LEFT:
return Positioned(right: 0, top: 0, bottom: 0, child: container);
case SlideDirection.TOP_TO_BOTTOM:
return Positioned(right: 0, left: 0, top: 0, child: container);
break;
}
return Container();
}
}

@ -1,13 +1,19 @@
import 'package:flutter/animation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_slider_drawer/flutter_slider_drawer.dart';
import 'package:flutter_slider_drawer/src/app_bar.dart';
import 'package:flutter_slider_drawer/src/menu_bar.dart';
import 'package:flutter_slider_drawer/src/helper/utils.dart';
import 'package:flutter_slider_drawer/src/slider_direction.dart';
class SliderMenuContainer extends StatefulWidget {
final Widget sliderMenu;
final Widget sliderMain;
final int sliderAnimationTimeInMilliseconds;
final double sliderMenuOpenOffset;
final double sliderMenuCloseOffset;
final int animationDuration;
final double sliderMenuOpenSize;
final double sliderMenuCloseSize;
final bool isDraggable;
final bool hasAppBar;
final Color drawerIconColor;
final Widget drawerIcon;
final double drawerIconSize;
@ -23,14 +29,15 @@ class SliderMenuContainer extends StatefulWidget {
final Widget trailing;
final Color appBarColor;
final EdgeInsets appBarPadding;
final SliderOpen sliderOpen;
final SlideDirection slideDirection;
const SliderMenuContainer({
Key key,
this.sliderMenu,
this.sliderMain,
this.sliderAnimationTimeInMilliseconds = 200,
this.sliderMenuOpenOffset = 265,
this.isDraggable = true,
this.animationDuration = 200,
this.sliderMenuOpenSize = 265,
this.drawerIconColor = Colors.black,
this.drawerIcon,
this.splashColor,
@ -40,13 +47,14 @@ class SliderMenuContainer extends StatefulWidget {
this.appBarPadding,
this.title,
this.drawerIconSize = 27,
this.appBarHeight,
this.sliderMenuCloseOffset = 0,
this.sliderOpen = SliderOpen.LEFT_TO_RIGHT,
this.appBarHeight = 70,
this.sliderMenuCloseSize = 0,
this.slideDirection = SlideDirection.LEFT_TO_RIGHT,
this.isShadow = false,
this.shadowColor = Colors.grey,
this.shadowBlurRadius = 25.0,
this.shadowSpreadRadius = 5.0,
this.hasAppBar = true,
}) : assert(sliderMenu != null),
assert(sliderMain != null),
super(key: key);
@ -56,236 +64,232 @@ class SliderMenuContainer extends StatefulWidget {
}
class SliderMenuContainerState extends State<SliderMenuContainer>
with SingleTickerProviderStateMixin {
double _slideBarXOffset = 0;
double _slideBarYOffset = 0;
bool _isSlideBarOpen = false;
AnimationController _animationController;
with TickerProviderStateMixin {
static const double WIDTH_GESTURE = 50.0;
static const double HEIGHT_GESTURE = 30.0;
static const double BLUR_SHADOW = 20.0;
double slideAmount = 0.0;
double _percent = 0.0;
AnimationController _animationDrawerController;
Animation animation;
bool dragging = false;
Widget drawerIcon;
/// check whether drawer is open
bool get isDrawerOpen => _isSlideBarOpen;
bool get isDrawerOpen => _animationDrawerController.isCompleted;
/// Toggle drawer
void toggle() {
setState(() {
_isSlideBarOpen
? _animationController.reverse()
: _animationController.forward();
if (widget.sliderOpen == SliderOpen.LEFT_TO_RIGHT ||
widget.sliderOpen == SliderOpen.RIGHT_TO_LEFT) {
_slideBarXOffset = _isSlideBarOpen
? widget.sliderMenuCloseOffset
: widget.sliderMenuOpenOffset;
} else {
_slideBarYOffset = _isSlideBarOpen
? widget.sliderMenuCloseOffset
: widget.sliderMenuOpenOffset;
}
/// it's provide [animationController] for handle and lister drawer animation
AnimationController get animationController => _animationDrawerController;
_isSlideBarOpen = !_isSlideBarOpen;
});
}
/// Toggle drawer
void toggle() => _animationDrawerController.isCompleted
? _animationDrawerController.reverse()
: _animationDrawerController.forward();
/// Open drawer
void openDrawer() {
setState(() {
_animationController.forward();
if (widget.sliderOpen == SliderOpen.LEFT_TO_RIGHT ||
widget.sliderOpen == SliderOpen.RIGHT_TO_LEFT) {
_slideBarXOffset = widget.sliderMenuOpenOffset;
} else {
_slideBarYOffset = widget.sliderMenuOpenOffset;
}
_isSlideBarOpen = true;
});
}
void openDrawer() => _animationDrawerController.forward();
/// Close drawer
void closeDrawer() {
setState(() {
_animationController.reverse();
if (widget.sliderOpen == SliderOpen.LEFT_TO_RIGHT ||
widget.sliderOpen == SliderOpen.RIGHT_TO_LEFT) {
_slideBarXOffset = widget.sliderMenuCloseOffset;
} else {
_slideBarYOffset = widget.sliderMenuCloseOffset;
}
_isSlideBarOpen = false;
});
}
void closeDrawer() => _animationDrawerController.reverse();
@override
void initState() {
super.initState();
_animationController = AnimationController(
_animationDrawerController = AnimationController(
vsync: this,
duration:
Duration(milliseconds: widget.sliderAnimationTimeInMilliseconds));
duration: Duration(milliseconds: widget.animationDuration));
animation = Tween<double>(
begin: widget.sliderMenuCloseSize, end: widget.sliderMenuOpenSize)
.animate(CurvedAnimation(
parent: _animationDrawerController,
curve: Curves.easeIn,
reverseCurve: Curves.easeOut));
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constrain) {
return Container(
child: Stack(children: <Widget>[
/// Display Menu
menuWidget(),
SlideMenuBar(
slideDirection: widget.slideDirection,
sliderMenu: widget.sliderMenu,
sliderMenuOpenSize: widget.sliderMenuOpenSize,
),
/// Displaying the shadow
if (widget.isShadow) ...[
AnimatedContainer(
duration:
Duration(milliseconds: widget.sliderAnimationTimeInMilliseconds),
curve: Curves.easeIn,
AnimatedBuilder(
animation: _animationDrawerController,
builder: (_, child) {
return Transform.translate(
offset: Utils.getOffsetValueForShadow(widget.slideDirection,
animation.value, widget.sliderMenuOpenSize),
child: child,
);
return child;
},
child: Container(
width: double.infinity,
height: double.infinity,
transform: getTranslationValuesForShadow(widget.sliderOpen),
decoration: BoxDecoration(shape: BoxShape.rectangle, boxShadow: [
BoxShadow(
color: widget.shadowColor,
blurRadius: widget.shadowBlurRadius, // soften the shadow
spreadRadius: widget.shadowSpreadRadius, //extend the shadow
blurRadius: widget.shadowBlurRadius,
// soften the shadow
spreadRadius: widget.shadowSpreadRadius,
//extend the shadow
offset: Offset(
15.0, // Move to right 10 horizontally
15.0, // Move to bottom 10 Vertically
15.0, // Move to right 15 horizontally
15.0, // Move to bottom 15 Vertically
),
)
]),
),
),
],
/// Display Main Screen
AnimatedContainer(
duration:
Duration(milliseconds: widget.sliderAnimationTimeInMilliseconds),
curve: Curves.easeIn,
//Display Main Screen
AnimatedBuilder(
animation: _animationDrawerController,
builder: (_, child) {
return Transform.translate(
offset:
Utils.getOffsetValues(widget.slideDirection, animation.value),
child: child,
);
},
child: GestureDetector(
behavior: HitTestBehavior.deferToChild,
onHorizontalDragStart: _onHorizontalDragStart,
onHorizontalDragEnd: _onHorizontalDragEnd,
onHorizontalDragUpdate: (detail) =>
_onHorizontalDragUpdate(detail, constrain),
child: Container(
width: double.infinity,
height: double.infinity,
color: widget.appBarColor,
transform: getTranslationValues(widget.sliderOpen),
child: Column(
children: <Widget>[
Container(
padding: widget.appBarPadding ?? const EdgeInsets.only(top: 24),
color: widget.appBarColor,
child: Row(
children: appBar(),
),
if (widget.hasAppBar)
SliderAppBar(
slideDirection: widget.slideDirection,
onTap: () => toggle(),
appBarHeight: widget.appBarHeight,
animationController: _animationDrawerController,
appBarColor: widget.appBarColor,
appBarPadding: widget.appBarPadding,
drawerIcon: widget.drawerIcon,
drawerIconColor: widget.drawerIconColor,
drawerIconSize: widget.drawerIconSize,
isTitleCenter: widget.isTitleCenter,
splashColor: widget.splashColor,
title: widget.title ?? '',
trailing: widget.trailing,
),
Expanded(child: widget.sliderMain),
],
)),
),
),
),
),
]));
});
}
List<Widget> appBar() {
List<Widget> list = [
widget.drawerIcon ??
IconButton(
splashColor: widget.splashColor ?? Colors.black,
icon: AnimatedIcon(
icon: AnimatedIcons.menu_close,
color: widget.drawerIconColor,
size: widget.drawerIconSize,
progress: _animationController),
onPressed: () {
toggle();
}),
Expanded(
child: widget.isTitleCenter
? Center(
child: widget.title,
)
: widget.title,
),
widget.trailing ??
SizedBox(
width: 35,
)
];
@override
void dispose() {
super.dispose();
_animationDrawerController.dispose();
}
if (widget.sliderOpen == SliderOpen.RIGHT_TO_LEFT) {
return list.reversed.toList();
void _onHorizontalDragStart(DragStartDetails detail) {
if (!widget.isDraggable) return;
//Check use start dragging from left edge / right edge then enable dragging
if ((widget.slideDirection == SlideDirection.LEFT_TO_RIGHT &&
detail.localPosition.dx <= WIDTH_GESTURE) ||
(widget.slideDirection == SlideDirection.RIGHT_TO_LEFT &&
detail.localPosition.dx >=
WIDTH_GESTURE) /*&&
detail.localPosition.dy <= widget.appBarHeight*/
) {
this.setState(() {
dragging = true;
});
}
//Check use start dragging from top edge / bottom edge then enable dragging
if (widget.slideDirection == SlideDirection.TOP_TO_BOTTOM &&
detail.localPosition.dy >= HEIGHT_GESTURE) {
this.setState(() {
dragging = true;
});
}
return list;
}
/// Build and Align the Menu widget based on the slide open type
menuWidget() {
switch (widget.sliderOpen) {
case SliderOpen.LEFT_TO_RIGHT:
return Container(
width: widget.sliderMenuOpenOffset,
child: widget.sliderMenu,
);
break;
case SliderOpen.RIGHT_TO_LEFT:
return Positioned(
right: 0,
top: 0,
bottom: 0,
child: Container(
width: widget.sliderMenuOpenOffset,
child: widget.sliderMenu,
),
);
case SliderOpen.TOP_TO_BOTTOM:
return Positioned(
right: 0,
left: 0,
top: 0,
child: Container(
width: widget.sliderMenuOpenOffset,
child: widget.sliderMenu,
),
);
break;
void _onHorizontalDragEnd(DragEndDetails detail) {
if (!widget.isDraggable) return;
if (dragging) {
openOrClose();
setState(() {
dragging = false;
});
}
}
///
/// This method get Matrix4 data base on [sliderOpen] type
///
Matrix4 getTranslationValues(SliderOpen sliderOpen) {
switch (sliderOpen) {
case SliderOpen.LEFT_TO_RIGHT:
return Matrix4.translationValues(
_slideBarXOffset, _slideBarYOffset, 1.0);
case SliderOpen.RIGHT_TO_LEFT:
return Matrix4.translationValues(
-_slideBarXOffset, _slideBarYOffset, 1.0);
case SliderOpen.TOP_TO_BOTTOM:
return Matrix4.translationValues(0, _slideBarYOffset, 1.0);
void _onHorizontalDragUpdate(
DragUpdateDetails detail,
BoxConstraints constraints,
) {
if (!widget.isDraggable) return;
// open drawer for left/right type drawer
if (dragging && widget.slideDirection == SlideDirection.LEFT_TO_RIGHT ||
widget.slideDirection == SlideDirection.RIGHT_TO_LEFT) {
var globalPosition = detail.globalPosition.dx;
globalPosition = globalPosition < 0 ? 0 : globalPosition;
double position = globalPosition / constraints.maxWidth;
var realPosition = widget.slideDirection == SlideDirection.LEFT_TO_RIGHT
? position
: (1 - position);
move(realPosition);
}
// open drawer for top/bottom type drawer
/*if (dragging && widget.slideDirection == SlideDirection.TOP_TO_BOTTOM) {
var globalPosition = detail.globalPosition.dx;
globalPosition = globalPosition < 0 ? 0 : globalPosition;
double position = globalPosition / constraints.maxHeight;
var realPosition = widget.slideDirection == SlideDirection.TOP_TO_BOTTOM
? position
: (1 - position);
move(realPosition);
}*/
default:
return Matrix4.translationValues(0, 0, 1.0);
// close drawer for left/right type drawer
if (isDrawerOpen &&
(widget.slideDirection == SlideDirection.LEFT_TO_RIGHT ||
widget.slideDirection == SlideDirection.RIGHT_TO_LEFT) &&
detail.delta.dx < 15) {
closeDrawer();
}
}
Matrix4 getTranslationValuesForShadow(SliderOpen sliderOpen) {
switch (sliderOpen) {
case SliderOpen.LEFT_TO_RIGHT:
return Matrix4.translationValues(
_slideBarXOffset - 30, _slideBarYOffset, 1.0);
case SliderOpen.RIGHT_TO_LEFT:
return Matrix4.translationValues(
-_slideBarXOffset - 5, _slideBarYOffset, 1.0);
case SliderOpen.TOP_TO_BOTTOM:
return Matrix4.translationValues(0, _slideBarYOffset - 20, 1.0);
default:
return Matrix4.translationValues(0, 0, 1.0);
}
move(double percent) {
_percent = percent;
_animationDrawerController.value = percent;
_animationDrawerController.notifyListeners();
}
@override
void dispose() {
super.dispose();
_animationController.dispose();
openOrClose() {
if (_percent > 0.3) {
openDrawer();
} else {
closeDrawer();
}
}
}

@ -0,0 +1 @@
enum SlideDirection { LEFT_TO_RIGHT, RIGHT_TO_LEFT, TOP_TO_BOTTOM }

@ -1 +0,0 @@
enum SliderOpen { LEFT_TO_RIGHT, RIGHT_TO_LEFT, TOP_TO_BOTTOM }
Loading…
Cancel
Save