highlighter_coachmark 0.0.3

  • README.md
  • CHANGELOG.md
  • Example
  • Installing
  • Versions
  • 83

Highlighter Coach Mark

There are different ways for user on-boarding. It can be a show of screenshots or overlay with directions to features, feature discovery as in Material design or coach mark. This coach mark makes blurred background and highlights desired element.

This coach mark makes blurred background and highlights desired element.

A picture is worth a thousand words, so take a look at gif

And a few tips from UX

Presenting hints one-by-one, at the right moment, makes it a lot easier for users to understand and learn instructions.

To have their full effect, coach marks should focus on particularly innovative or unexpected elements.

Usage

Take a look at example folder. There are also 4 coach marks there. They are all presented in gif above

  CoachMark coachMark = CoachMark();
  RenderBox target = targetGlobalKey.currentContext.findRenderObject();
  Rect markRect = target.localToGlobal(Offset.zero) & target.size;
  markRect = Rect.fromCircle(center: markRect.center, radius: markRect.longestSide * 0.6);
  coachMark.show(
      targetContext: targetGlobalKey.currentContext,
      markRect: markRect,
      children: [
        Positioned(
            top: markRect.top + 5.0,
            right: 10.0,
            child: Text("Long tap on button to see options",
                style: const TextStyle(
                  fontSize: 24.0,
                  fontStyle: FontStyle.italic,
                  color: Colors.white,
                )))
      ],
      duration: null,
      onClose: () {
         appState.setCoachMarkIsShown(true);
      });

Similar packages

Thanks

[0.0.3]

  • fix description and formatting

[0.0.2]

  • add demo gif tp README

[0.0.1]

  • Coach Mark highlights target element and blurs background.
  • It closes on touch anywhere on the screen. Allow any touch event on target element

example/lib/main.dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

import 'package:example/ui/frienddetails/friend_details_page.dart';
import 'package:example/ui/friends/friend.dart';

import 'package:highlighter_coachmark/highlighter_coachmark.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.purple,
        accentColor: const Color(0xFFF850DD),
      ),
      home: FriendsListPage(),
    );
  }
}

class FriendsListPage extends StatefulWidget {
  @override
  _FriendsListPageState createState() => _FriendsListPageState();
}

class _FriendsListPageState extends State<FriendsListPage> {
  List<Friend> _friends = [];
  ScrollController _scrollController;
  GlobalKey _fabKey = GlobalObjectKey("fab");
  GlobalKey _tileKey = GlobalObjectKey("tile_2");

  @override
  void initState() {
    super.initState();
    _scrollController = ScrollController();
    _loadFriends();
  }

  Future<void> _loadFriends() async {
    http.Response response =
        await http.get('https://randomuser.me/api/?results=5');

    setState(() {
      _friends = Friend.allFromResponse(response.body);
    });

    // Here is how you can launch CoachMark.
    // Management of coach mark tutorials is another topic not covered in this lib
    Timer(Duration(seconds: 1), () => showCoachMarkFAB());
  }

  //Here is example of CoachMark usage
  void showCoachMarkFAB() {
    CoachMark coachMarkFAB = CoachMark();
    RenderBox target = _fabKey.currentContext.findRenderObject();

    Rect markRect = target.localToGlobal(Offset.zero) & target.size;
    markRect = Rect.fromCircle(
        center: markRect.center, radius: markRect.longestSide * 0.6);

    coachMarkFAB.show(
        targetContext: _fabKey.currentContext,
        markRect: markRect,
        children: [
          Center(
              child: Text("Tap on button\nto add a friend",
                  style: const TextStyle(
                    fontSize: 24.0,
                    fontStyle: FontStyle.italic,
                    color: Colors.white,
                  )))
        ],
        duration: null,
        onClose: () {
          Timer(Duration(seconds: 3), () => showCoachMarkTile());
        });
  }

  //And here is example of CoachMark usage.
  //One more example you can see in FriendDetailsPage - showCoachMarkBadges()
  void showCoachMarkTile() {
    CoachMark coachMarkTile = CoachMark();
    RenderBox target = _tileKey.currentContext.findRenderObject();

    Rect markRect = target.localToGlobal(Offset.zero) & target.size;
    markRect = markRect.inflate(5.0);

    coachMarkTile.show(
        targetContext: _fabKey.currentContext,
        markRect: markRect,
        markShape: BoxShape.rectangle,
        children: [
          Positioned(
              top: markRect.bottom + 15.0,
              right: 5.0,
              child: Text("Tap on friend to see details",
                  style: const TextStyle(
                    fontSize: 24.0,
                    fontStyle: FontStyle.italic,
                    color: Colors.white,
                  )))
        ],
        duration: Duration(seconds: 3));
  }

  @override
  Widget build(BuildContext context) {
    Widget content;

    if (_friends.isEmpty) {
      content = Center(
        child: CircularProgressIndicator(),
      );
    } else {
      content = ListView.builder(
        itemExtent: 70.0,
        controller: _scrollController,
        itemCount: _friends.length,
        itemBuilder: _buildFriendListTile,
      );
    }

    return Scaffold(
      appBar: AppBar(title: Text('Friends')),
      body: content,
      floatingActionButton: _friends.isEmpty
          ? null
          : FloatingActionButton(
              key: _fabKey,
              child: Icon(Icons.add),
              onPressed: () async {
                Friend friend = await buildShowDialog(context);
                if (friend != null) {
                  setState(() {
                    _friends.add(friend);
                  });
                  Future.delayed(
                      Duration(milliseconds: 200),
                      () => _scrollController.animateTo(
                          _scrollController.position.maxScrollExtent,
                          duration: Duration(seconds: 1),
                          curve: Curves.easeOut));
                }
              },
            ),
    );
  }

  Widget _buildFriendListTile(BuildContext context, int index) {
    var friend = _friends[index];
    GlobalKey key = index == 2 ? _tileKey : null;

    return ListTile(
      key: key,
      onTap: () => _navigateToFriendDetails(friend, index),
      leading: Hero(
        tag: index,
        child: CircleAvatar(
          backgroundImage: NetworkImage(friend.avatar),
        ),
      ),
      title: Text(friend.name),
      subtitle: Text(friend.email),
    );
  }

  void _navigateToFriendDetails(Friend friend, Object avatarTag) {
    Navigator.of(context).push(
      MaterialPageRoute(
        builder: (c) {
          return FriendDetailsPage(friend, avatarTag: avatarTag);
        },
      ),
    );
  }

  Future<Friend> buildShowDialog(BuildContext context) {
    return showDialog<Friend>(
        context: context,
        builder: (BuildContext context) {
          return FutureBuilder<Friend>(
              future: _loadRandomFriend(),
              builder: (BuildContext context, AsyncSnapshot<Friend> snapshot) {
                if (snapshot.connectionState == ConnectionState.done) {
                  return SimpleDialog(
                      title: _buildDialogAddFriend(snapshot.data));
                } else {
                  return SimpleDialog(
                      title: Container(
                          height: 100.0,
                          width: 200.0,
                          alignment: Alignment.center,
                          color: Colors.white,
                          child: CircularProgressIndicator()));
                }
              });
        });
  }

  Future<Friend> _loadRandomFriend() async {
    http.Response response =
        await http.get('https://randomuser.me/api/?results=1');
    var friends = Friend.allFromResponse(response.body);
    return friends.first;
  }

  Widget _buildDialogAddFriend(Friend friend) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      mainAxisSize: MainAxisSize.min,
      children: <Widget>[
        ListTile(
          leading: CircleAvatar(
            backgroundImage: NetworkImage(friend.avatar),
          ),
          title: Text(friend.name),
          subtitle: Text(friend.email),
        ),
        Padding(
            padding: EdgeInsets.all(10.0),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                SimpleDialogOption(
                  onPressed: () {
                    Navigator.pop(context);
                  },
                  child: const Text('Cansel'),
                ),
                SimpleDialogOption(
                  onPressed: () {
                    Navigator.pop(context, friend);
                  },
                  child: const Text('Save'),
                ),
              ],
            )),
      ],
    );
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  highlighter_coachmark: ^0.0.3

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter packages get

Alternatively, your editor might support flutter packages get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:highlighter_coachmark/highlighter_coachmark.dart';
  
Version Uploaded Documentation Archive
0.0.3 Sep 19, 2018 Go to the documentation of highlighter_coachmark 0.0.3 Download highlighter_coachmark 0.0.3 archive
0.0.2 Sep 18, 2018 Go to the documentation of highlighter_coachmark 0.0.2 Download highlighter_coachmark 0.0.2 archive
0.0.1 Sep 18, 2018 Go to the documentation of highlighter_coachmark 0.0.1 Download highlighter_coachmark 0.0.1 archive
Popularity:
Describes how popular the package is relative to other packages. [more]
70
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
90
Overall:
Weighted score of the above. [more]
83
Learn more about scoring.

We analyzed this package on Dec 5, 2018, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.1.0
  • pana: 0.12.7
  • Flutter: 1.0.0

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Maintenance suggestions

Package is pre-v0.1 release. (-10 points)

While there is nothing inherently wrong with versions of 0.0.*, it usually means that the author is still experimenting with the general direction of the API.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0-dev.68.0 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.11
meta 1.1.6
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test