From 42f25615aa1a108207f7a8468c88769a455c895b Mon Sep 17 00:00:00 2001 From: Dhaval Kansara Date: Thu, 7 Jul 2022 15:04:00 +0530 Subject: [PATCH] fixes #235(https://github.com/SimformSolutionsPvtLtd/flutter_showcaseview/issues/235) added flag to enable auto scroll --- CHANGELOG.md | 4 + README.md | 8 + example/android/app/build.gradle | 4 +- example/lib/main.dart | 269 +++++++++++-------------------- lib/src/showcase.dart | 91 ++++++----- lib/src/showcase_widget.dart | 4 + pubspec.yaml | 2 +- 7 files changed, 162 insertions(+), 220 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1e294e0..bc17dc3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## [1.1.7] - June 7, 2022 + +- Fixed [#235](https://github.com/SimformSolutionsPvtLtd/flutter_showcaseview/issues/235) - While using ShowCase widget, not scrolling to respective widget when its not visible. + ## [1.1.6] - June 23, 2022 - Fixed [#62](https://github.com/SimformSolutionsPvtLtd/flutter_showcaseview/issues/62) - While using ShowCase widget, not scrolling to respective widget when its not visible. diff --git a/README.md b/README.md index 1822288b..2b8ea308 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,14 @@ ShowCaseWidget( ); ``` +## Disable Auto Scrolling +By default aut scrooling behaviour is on to disable it we can set ``enableAutoScroll`` flag to false in ``showCaseWidget``. +```dart +ShowCaseWidget( + enableAutoScroll: false, +); +``` + ## Main Contributors diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index efa45dfa..1b66a242 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -26,7 +26,7 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 30 + compileSdkVersion 31 sourceSets { main.java.srcDirs += 'src/main/kotlin' @@ -39,7 +39,7 @@ android { defaultConfig { applicationId "com.simform.example" minSdkVersion 16 - targetSdkVersion 30 + targetSdkVersion 31 versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" diff --git a/example/lib/main.dart b/example/lib/main.dart index 9aaf61ad..81ba7433 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -21,6 +21,7 @@ class MyApp extends StatelessWidget { debugShowCheckedModeBanner: false, home: Scaffold( body: ShowCaseWidget( + enableAutoScroll: true, onStart: (index, key) { log('onStart: $index, $key'); }, @@ -77,63 +78,56 @@ class _MailPageState extends State { sender: 'Medium', sub: 'Showcase View', msg: 'Check new showcase View', - date: '25 May', + date: '1 May', isUnread: false, ), Mail( sender: 'Quora', sub: 'New Question for you', msg: 'Hi, There is new question for you', - date: '22 May', + date: '2 May', isUnread: false, ), Mail( sender: 'Google', sub: 'Flutter 1.5', msg: 'We have launched Flutter 1.5', - date: '20 May', + date: '3 May', isUnread: true, ), Mail( sender: 'Github', sub: 'Showcase View', msg: 'New star on your showcase view.', - date: '21 May ', + date: '4 May ', isUnread: false, ), Mail( sender: 'Simform', sub: 'Credit card Plugin', msg: 'Check out our credit card plugin', - date: '19 May', + date: '5 May', isUnread: true, ), Mail( sender: 'Flutter', sub: 'Flutter is Future', - msg: 'Flutter laucnhed for Web', - date: '18 Jun', + msg: 'Flutter launched for Web', + date: '6 Jun', isUnread: true, ), Mail( sender: 'Medium', sub: 'Showcase View', msg: 'Check new showcase View', - date: '21 May ', + date: '7 May ', isUnread: false, ), Mail( sender: 'Simform', sub: 'Credit card Plugin', msg: 'Check out our credit card plugin', - date: '19 May', - isUnread: true, - ), - Mail( - sender: 'Flutter', - sub: 'Flutter is Future', - msg: 'Flutter laucnhed for Web', - date: '18 Jun', + date: '8 May', isUnread: true, ), ]; @@ -181,10 +175,12 @@ class _MailPageState extends State { children: [ Showcase( key: _one, - description: 'Tap to see menu options', + description: + 'Tap to see menu options', child: Icon( Icons.menu, - color: Theme.of(context).primaryColor, + color: + Theme.of(context).primaryColor, ), ), const SizedBox( @@ -216,8 +212,9 @@ class _MailPageState extends State { key: _two, title: 'Profile', description: - "Tap to see profile which contains user's name, profile picture, mobile number and country", - showcaseBackgroundColor: Theme.of(context).primaryColor, + "Tap to see profile which contains user's name, profile picture, mobile number and country", + showcaseBackgroundColor: + Theme.of(context).primaryColor, textColor: Colors.white, shapeBorder: const CircleBorder(), child: Container( @@ -256,17 +253,22 @@ class _MailPageState extends State { Expanded( child: ListView.builder( controller: scrollController, + itemCount: mails.length, physics: const BouncingScrollPhysics(), itemBuilder: (context, index) { if (index == 0) { - return showcaseMailTile(_three, true, context); + return showcaseMailTile( + _three, true, context, mails.first); } else if (index == mails.length - 1) { - return showcaseMailTile(_six, false, context); + return showcaseMailTile( + _six, false, context, mails.last); } - return MailTile(mails[index % mails.length]); + return MailTile( + mail: mails[index], + ); }, ), - ) + ), ], ), ), @@ -280,8 +282,8 @@ class _MailPageState extends State { onPressed: () { setState(() { /* reset ListView to ensure that the showcased widgets are - * currently rendered so the showcased keys are available in the - * render tree. */ + * currently rendered so the showcased keys are available in the + * render tree. */ scrollController.jumpTo(0); ShowCaseWidget.of(context) .startShowCase([_one, _two, _three, _four, _five, _six]); @@ -296,7 +298,7 @@ class _MailPageState extends State { } GestureDetector showcaseMailTile(GlobalKey> key, - bool showCaseDetail, BuildContext context) { + bool showCaseDetail, BuildContext context, Mail mail) { return GestureDetector( onTap: () { Navigator.push( @@ -309,133 +311,26 @@ class _MailPageState extends State { child: Container( padding: const EdgeInsets.symmetric(vertical: 8), child: Showcase( - key: key, - description: 'Tap to check mail', - disposeOnTap: true, - onTargetClick: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (_) => const Detail(), - ), - ).then((_) { - setState(() { - ShowCaseWidget.of(context).startShowCase([_four, _five]); - }); - }); - }, - child: Container( - padding: - const EdgeInsets.only(left: 6, right: 16, top: 5, bottom: 5), - color: const Color(0xffFFF6F7), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (showCaseDetail) - Showcase.withWidget( - key: _four, - height: 50, - width: 140, - shapeBorder: const CircleBorder(), - radius: const BorderRadius.all(Radius.circular(150)), - container: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: 45, - height: 45, - decoration: const BoxDecoration( - shape: BoxShape.circle, - color: Color(0xffFCD8DC), - ), - child: Center( - child: Text( - 'S', - style: TextStyle( - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - ), - ), - const SizedBox( - height: 10, - ), - const Text( - "Your sender's profile ", - style: TextStyle(color: Colors.white), - ) - ], - ), - child: const SAvatarExampleChild(), - ) - else - const SAvatarExampleChild(), - const Padding(padding: EdgeInsets.only(left: 8)), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Slack', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 17, - ), - ), - const Text( - 'Flutter Notification', - style: TextStyle( - fontSize: 16, - ), - ), - Text( - 'Hi, you have new Notification', - style: TextStyle( - fontWeight: FontWeight.normal, - color: Theme.of(context).primaryColor, - fontSize: 15, - ), - ), - ], - ) - ], - ), - ), - SizedBox( - width: 50, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: const [ - SizedBox( - height: 5, - ), - Text( - '1 Jun', - style: TextStyle( - fontWeight: FontWeight.normal, - fontSize: 12, - color: Colors.grey, - ), - ), - SizedBox( - height: 10, - ), - Icon( - Icons.star, - color: Color(0xffFBC800), - ) - ], - ), + key: key, + description: 'Tap to check mail', + disposeOnTap: true, + onTargetClick: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => const Detail(), ), - ], - ), - ), - ), + ).then((_) { + setState(() { + ShowCaseWidget.of(context).startShowCase([_four, _five]); + }); + }); + }, + child: MailTile( + mail: mail, + showCaseKey: _four, + showCaseDetail: showCaseDetail, + )), ), ); } @@ -489,8 +384,14 @@ class Mail { } class MailTile extends StatelessWidget { - const MailTile(this.mail, {Key? key}) : super(key: key); - + const MailTile( + {required this.mail, + this.showCaseDetail = false, + this.showCaseKey, + Key? key}) + : super(key: key); + final bool showCaseDetail; + final GlobalKey>? showCaseKey; final Mail mail; @override @@ -505,25 +406,47 @@ class MailTile extends StatelessWidget { child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Container( - margin: const EdgeInsets.all(10), - width: 45, - height: 45, - decoration: const BoxDecoration( - shape: BoxShape.circle, - color: Color(0xffFCD8DC), - ), - child: Center( - child: Text( - mail.sender[0], - style: TextStyle( - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.bold, - fontSize: 16, - ), + if (showCaseDetail) + Showcase.withWidget( + key: showCaseKey!, + height: 50, + width: 140, + shapeBorder: const CircleBorder(), + radius: const BorderRadius.all(Radius.circular(150)), + container: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: 45, + height: 45, + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: Color(0xffFCD8DC), + ), + child: Center( + child: Text( + 'S', + style: TextStyle( + color: Theme.of(context).primaryColor, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + ), + const SizedBox( + height: 10, + ), + const Text( + "Your sender's profile ", + style: TextStyle(color: Colors.white), + ) + ], ), - ), - ), + child: const SAvatarExampleChild(), + ) + else + const SAvatarExampleChild(), const Padding(padding: EdgeInsets.only(left: 8)), Expanded( child: Column( diff --git a/lib/src/showcase.dart b/lib/src/showcase.dart index e8ef51bd..328a4819 100644 --- a/lib/src/showcase.dart +++ b/lib/src/showcase.dart @@ -72,21 +72,21 @@ class Showcase extends StatefulWidget { final double? blurValue; const Showcase({ - required this.key, - required this.child, - this.title, - required this.description, - this.shapeBorder, - this.overlayColor = Colors.black45, - this.overlayOpacity = 0.75, - this.titleTextStyle, - this.descTextStyle, - this.showcaseBackgroundColor = Colors.white, - this.textColor = Colors.black, - this.scrollLoadingWidget = const CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation(Colors.white)), - this.showArrow = true, - this.onTargetClick, + required this.key, + required this.child, + this.title, + required this.description, + this.shapeBorder, + this.overlayColor = Colors.black45, + this.overlayOpacity = 0.75, + this.titleTextStyle, + this.descTextStyle, + this.showcaseBackgroundColor = Colors.white, + this.textColor = Colors.black, + this.scrollLoadingWidget = const CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(Colors.white)), + this.showArrow = true, + this.onTargetClick, this.disposeOnTap, this.animationDuration = const Duration(milliseconds: 2000), this.disableAnimation, @@ -114,34 +114,34 @@ class Showcase extends StatefulWidget { : (onTargetClick == null ? false : true), "onTargetClick is required if you're using disposeOnTap"); - const Showcase.withWidget({ - required this.key, - required this.child, - required this.container, - required this.height, - required this.width, - this.title, - this.description, - this.shapeBorder, - this.overlayColor = Colors.black45, - this.radius, - this.overlayOpacity = 0.75, - this.titleTextStyle, - this.descTextStyle, - this.showcaseBackgroundColor = Colors.white, - this.textColor = Colors.black, - this.scrollLoadingWidget = const CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation(Colors.white)), - this.onTargetClick, - this.disposeOnTap, - this.animationDuration = const Duration(milliseconds: 2000), - this.disableAnimation, - this.contentPadding = const EdgeInsets.symmetric(vertical: 8), - this.overlayPadding = EdgeInsets.zero, - this.blurValue, - this.onTargetLongPress, - this.onTargetDoubleTap, - }) : showArrow = false, + const Showcase.withWidget( + {required this.key, + required this.child, + required this.container, + required this.height, + required this.width, + this.title, + this.description, + this.shapeBorder, + this.overlayColor = Colors.black45, + this.radius, + this.overlayOpacity = 0.75, + this.titleTextStyle, + this.descTextStyle, + this.showcaseBackgroundColor = Colors.white, + this.textColor = Colors.black, + this.scrollLoadingWidget = const CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(Colors.white)), + this.onTargetClick, + this.disposeOnTap, + this.animationDuration = const Duration(milliseconds: 2000), + this.disableAnimation, + this.contentPadding = const EdgeInsets.symmetric(vertical: 8), + this.overlayPadding = EdgeInsets.zero, + this.blurValue, + this.onTargetLongPress, + this.onTargetDoubleTap}) + : showArrow = false, onToolTipClick = null, assert(overlayOpacity >= 0.0 && overlayOpacity <= 1.0, "overlay opacity must be between 0 and 1."); @@ -178,7 +178,10 @@ class _ShowcaseState extends State { }); if (activeStep == widget.key) { - _scrollIntoView(); + if (ShowCaseWidget.of(context).autScroll) { + _scrollIntoView(); + } + if (showCaseWidgetState.autoPlay) { timer = Timer( Duration(seconds: showCaseWidgetState.autoPlayDelay.inSeconds), diff --git a/lib/src/showcase_widget.dart b/lib/src/showcase_widget.dart index faa0b1fc..8f8f503e 100644 --- a/lib/src/showcase_widget.dart +++ b/lib/src/showcase_widget.dart @@ -40,6 +40,7 @@ class ShowCaseWidget extends StatefulWidget { /// /// Default value is 0. final double blurValue; + final bool enableAutoScroll; const ShowCaseWidget({ required this.builder, @@ -52,6 +53,7 @@ class ShowCaseWidget extends StatefulWidget { this.blurValue = 0, this.scrollDuration = const Duration(milliseconds: 300), this.disableAnimation = false, + this.enableAutoScroll = true, }); static GlobalKey? activeTargetWidget(BuildContext context) { @@ -80,6 +82,7 @@ class ShowCaseWidgetState extends State { late bool disableAnimation; late Duration autoPlayDelay; late bool autoPlayLockEnable; + late bool autScroll; /// Returns value of [ShowCaseWidget.blurValue] double get blurValue => widget.blurValue; @@ -91,6 +94,7 @@ class ShowCaseWidgetState extends State { autoPlay = widget.autoPlay; disableAnimation = widget.disableAnimation; autoPlayLockEnable = widget.autoPlayLockEnable; + autScroll = widget.enableAutoScroll; } void startShowCase(List widgetIds) { diff --git a/pubspec.yaml b/pubspec.yaml index a837812d..242f6176 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: showcaseview description: A Flutter package to Showcase/Highlight widgets step by step. -version: 1.1.6 +version: 1.1.7 homepage: https://github.com/simformsolutions/flutter_showcaseview issue_tracker: https://github.com/simformsolutions/flutter_showcaseview/issues