A great app UI is one that minimizes the friction between a user and app functionality. A way to reduce that friction is to highlight and showcase the parts of your app. This is helpful when a user launches your app for the first time. With the help of the Showcase and ShowCaseWidget
widget, we can showcase the feature in the Flutter app.
The showcase will highlight the most important features of our app. When the user taps on the screen, the widgets we have as part of the showcase will be presented in a predefined order. With the help of the ShowCaseView library, we can easily showcase the app functionality.
You may also check our Flutter app development services.
Steps For Integrating Showcase In App
To Implement showcase in our flutter app, we will have to follow some steps –
Step 1: First start by adding the package dependency to our pubspec.yaml file.
At the time of writing this blog, the version is 1.1.5, you can check the latest version here.
Step 2: Before we implement the showcase for individual widgets, we need to wrap our page that will display the showcase with a ShowCaseWidget
.
Step3: Now finally we set up our showcase widget, There are a few things we should note about the Showcase
widget configuration.The key
, description
and child
parameters are required parameters.
key: It is a unique GlobalKey to identify features showcased.
description
: It is used to display a string about the showcased feature.
child: It is a widget on which we want to perform a showcase.
Full Code:
main.dart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
import 'package:flutter/material.dart'; import 'package:showcase_demo/dataModel.dart'; import 'package:showcase_demo/orderItem.dart'; import 'package:showcaseview/showcaseview.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter ShowCase', debugShowCheckedModeBanner: false, home: Scaffold( body: ShowCaseWidget( builder: Builder(builder: (context) => const OrderList()), ), ), ); } } class OrderList extends StatefulWidget { const OrderList({Key? key}) : super(key: key); @override _OrderListState createState() => _OrderListState(); } class _OrderListState extends State<OrderList> { final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); final GlobalKey _one = GlobalKey(); final GlobalKey _two = GlobalKey(); final GlobalKey _three = GlobalKey(); final GlobalKey _four = GlobalKey(); List<Items> items = [Items( entityId: '00000001', status: 'complete', total: '\$50.00', createdAt: '2022-04-25', billingName: 'Johny Doe', ), Items( entityId: '00000002', status: 'closed', total: '\$150.00', createdAt: '2022-04-25', billingName: 'Mathew ', ), Items( entityId: '00000003', status: 'processing', total: '\$70.00', createdAt: '2022-04-25', billingName: 'Paul', ), Items( entityId: '00000004', status: 'complete', total: '\$128.00', createdAt: '2022-04-25', billingName: 'Johny Doe', ),]; @override void initState() { super.initState(); //Start showcase view after current widget frames are drawn. WidgetsBinding.instance!.addPostFrameCallback( (_) => ShowCaseWidget.of(context)! .startShowCase([_one, _two, _three, _four]), ); } @override Widget build(BuildContext context) { return Scaffold( key: _scaffoldKey, backgroundColor: Colors.white, drawer: Drawer( child: ListView( padding: EdgeInsets.zero, children: const <Widget>[ DrawerHeader( decoration: BoxDecoration( color: Colors.green, ), child: Text( 'Drawer Header', style: TextStyle( color: Colors.white, fontSize: 24, ), ), ), ListTile( leading: Icon(Icons.message), title: Text('Messages'), ), ListTile( leading: Icon(Icons.account_circle), title: Text('Profile'), ), ListTile( leading: Icon(Icons.settings), title: Text('Settings'), ), ], ), ), appBar: AppBar( leading: Showcase( key: _one, description: 'Tap here to open drawer', child: IconButton( onPressed: () { _scaffoldKey.currentState!.openDrawer(); }, icon: const Icon(Icons.menu), ), ), actions: [ Showcase( key: _two, description: 'Tap to see notification', child: IconButton( onPressed: () { // Navigate to notification screen // }, icon: const Icon(Icons.notifications_active))) ], title: const Text('Showcase demo'), ), body: Column( children: <Widget>[ ListView.builder( physics: const BouncingScrollPhysics(), shrinkWrap: true, itemCount: items.length, itemBuilder: (context, index) { if (index == 0) { return Showcase( key: _three, description: 'Long Press to select the Item Or Tap to see order details ', child: OrderListItem( order: items[index], )); } return OrderListItem( order: items[index], ); }, ) ], ), floatingActionButton: Showcase( key: _four, title: 'New Order', description: 'Click here to create new Order', shapeBorder: const CircleBorder(), child: FloatingActionButton( onPressed: () { // Navigate to new Order screen // }, child: const Icon( Icons.add, ), ), ), ); } } |
orderItem.dart:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
import 'package:flutter/material.dart'; import 'dataModel.dart'; class OrderListItem extends StatefulWidget { final Items? order; const OrderListItem( {Key? key, this.order,}) : super(key: key); @override _OrderListItemState createState() => _OrderListItemState(); } class _OrderListItemState extends State<OrderListItem> { @override void initState() { super.initState(); } @override Widget build(BuildContext context) { return GestureDetector( onLongPress: () { // select item // }, onTap: () { // Navigate to order details // }, child: _cardView(), ); } Widget _cardView() { return Card( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 8.0), child: Column( mainAxisSize: MainAxisSize.min, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text("#" + (widget.order?.entityId?.toString() ?? ""), style: Theme.of(context).textTheme.bodyText1), Text(widget.order?.total?.toString() ?? '0', style: Theme.of(context).textTheme.headline6, ), ], ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Container( height: 8, width: 8, decoration: BoxDecoration( borderRadius: BorderRadius.circular(100), color: (widget.order?.status ?? false) == "closed" ? Colors.red : (widget.order?.status ?? false) == "complete" ? Colors.green : (widget.order?.status ?? false) == "processing" ? Colors.blue : Colors.yellow), ), Text(widget.order?.status ?? "", style: Theme.of(context).textTheme.bodyText2), ], ), Flexible( child: Text( widget.order?.createdAt?.toString() ?? '', style: Theme.of(context).textTheme.bodyText2, ), ), ], ), Row( children: [ Flexible( child: Text( widget.order?.billingName?.toString() ?? '', style: Theme.of(context).textTheme.subtitle2, ) ) ], ), ], ), ), ); } } |
Note: In opening some screens you may face context issues.
1 |
Exception: Please provide ShowCaseView context |
When you face the above issue then you need to provide the correct context to the ShowCaseWidget widget.
Output:
Conclusion
In this blog, we have discussed showcasing our app features.
I hope it will help you to understand and get a brief idea about it.
Thank you for reading!! 🙏🏻