Scratch card widget which temporarily hides content from user.

Overview

scratcher

Scratch card widget which temporarily hides content from user.

Version

Demo

Features

  • Android and iOS support
  • Cover content with full color or custom image
  • Track the scratch progress and threshold
  • Fully configurable

Getting started

  1. First thing you need to do is adding the scratcher as a project dependency in pubspec.yaml:
dependencies:
 scratcher: "^2.0.0"
  1. Now you can install it by running flutter pub get or through code editor.

Setting up

  1. Import the library:
import 'package:scratcher/scratcher.dart';
  1. Cover desired widget with the scratch card:
Scratcher(
  brushSize: 30,
  threshold: 50,
  color: Colors.red,
  onChange: (value) => print("Scratch progress: $value%"),
  onThreshold: () => print("Threshold reached, you won!"),
  child: Container(
    height: 300,
    width: 300,
    color: Colors.blue,
  ),
)

Properties

Property Type Description
child Widget Widget rendered under the scratch area.
enabled bool Whether new scratches can be applied.
threshold double Percentage level of scratch area which should be revealed to complete.
brushSize double Size of the brush. The bigger it is the faster user can scratch the card.
accuracy ScratchAccuracy Determines how accurate the progress should be reported. Lower accuracy means higher performance.
color Color Color used to cover the child widget.
image Image Image widget used to cover the child widget.
onChange Function Callback called when new part of area is revealed (min 0.1% difference).
onThreshold Function Callback called when threshold is reached (only when defined).
onScratchStart Function Callback called when scratching starts.
onScratchUpdate Function Callback called during scratching.
onScratchEnd Function Callback called when scratching ends.

Programmatic access

You can control the Scratcher programmatically by assigning the GlobalKey to the widget.

final scratchKey = GlobalKey<ScratcherState>();

Scratcher(
  key: scratchKey,
  // remaining properties
)

After assigning the key, you can call any exposed methods e.g.:

RaisedButton(
  child: const Text('Reset'),
  onPressed: () {
    scratchKey.currentState.reset(duration: Duration(milliseconds: 2000));
  },
);
Method Description
reset Resets the scratcher state to the initial values.
reveal Reveals the whole scratcher, so than only original child is displayed.

Example Project

There is a crazy example project in the example folder. Check it out to see most of the available options.

Resources

Comments
  • if image is null, crash

    if image is null, crash

    Scratcher(
      ...
      image: null,  // or do not assign this parameter
    )
    

    result:

    type 'Null' is not a subtype of type 'FutureOr<Image>' See also: https://flutter.dev/docs/testing/errors
    

    I found the problem code here:

    // scratcher-2.0.0/lib/widgets.dart
    void initState() {
      if (widget.image == null) {
        final completer = Completer<ui.Image>()..complete();  // <-- here
      }
    }
    

    environment:

    Flutter 2.0.3 • channel stable • https://github.com/flutter/flutter.git
    Framework • revision 4d7946a68d (12 days ago) • 2021-03-18 17:24:33 -0700
    Engine • revision 3459eb2436
    Tools • Dart 2.12.2
    
    Android Sdk API Verison: 30
    Emulator: Pixel XL
    
    bug 
    opened by sleepreading 8
  • App starts to become heavy after one or more scratches

    App starts to become heavy after one or more scratches

    Hi @vintage !

    First of all, thank you very much for creating this plugin and publishing it! If I'm not wrong it's the first Flutter plugin that allows the scratch of an image :)

    I'm integrating the plugin in the app I'm currently working on, which requires the scratch of images in a table (3 x 3 matrix). After scratching one image the app starts to become heavy, which results in low performance when scratching other images. ScratchAccuracy.low is already being used for each Scratcher widget, what can be done to increase the performance?

    Cheers, freitzzz

    bug 
    opened by freitzzz 8
  • Card events are not updated properly

    Card events are not updated properly

    Thanks for the great control.

    I tested this code on Android and it seems like the card events are not updated properly for some reason. It might take them more than few seconds to be updated and even then the percentage value is totally incorrect:

      @override
      Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
              title: Text(
                  AppLocalizations.of(context).translate("scratch_card_title")),
            ),
            body: Container(
                child: Column(children: <Widget>[
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Text(
                  AppLocalizations.of(context).translate("scratch_card_sub_title"),
                  style: TextStyle(fontSize: 30),
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(10.0),
                child: Card(
                    elevation: 10,
                    child: Container(
                      child: Padding(
                        padding: const EdgeInsets.all(10.0),
                        child: Scratcher(
                          brushSize: 30,
                          threshold: 85,
                          color: Color.fromRGBO(192, 192, 192, 1),
                          onChange: (value) {
                            print("value: " + value.toString());
                          },
                          onThreshold: () {
                            print("DONE!!!");
                            //BlocProvider.of<ScratchCardBloc>(context).dispatch(ScratchCardFinalize());
                          },
                          child: Column(children: <Widget>[
                            Padding(
                              padding: const EdgeInsets.all(12.0),
                              child: Opacity(
                                opacity: 1,
                                child: Text(
                                  AppLocalizations.of(context)
                                      .translate("reward_trip"),
                                  style: TextStyle(fontSize: 30),
                                ),
                              ),
                            ),
                            Padding(
                              padding: const EdgeInsets.all(20.0),
                              child: Image(
                                  image: AssetImage("assets/img/rewards/trip.png")),
                            )
                          ]),
                        ),
                      ),
                    )),
              )
            ])));
      }
    

    When I remove the widgets before the Scratcher widgets it all behaves properly.

    bug 
    opened by guybashan 6
  • use image: Image.asset() still show black scratcher

    use image: Image.asset() still show black scratcher

    version 1.3.0 i want to use a image to cover child widget this is my scratcher

    Container(
              width: 200,
              height: 200,
              child: Scratcher(
                key: key,
                brushSize: 30,
                threshold: 50,
                image: Image.asset(
                  'assets/scratcher01.jpg',
                  fit: BoxFit.cover,
                ),
                onChange: (value) {},
                child: Container(
                  height: double.infinity,
                  width: double.infinity,
                  child: Center(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        Text(
                          'Scratch the screen to win',
                          textAlign: TextAlign.center,
                          style: TextStyle(fontSize: 24, color: Colors.amber),
                        ),
                      ],
                    ),
                  ),
                  color: Colors.grey,
                ),
              ),
            ),
    

    Scratcher widget

    Scratcher({
        Key key,
        @required this.child,
        this.threshold,
        this.brushSize = 25,
        this.accuracy = ScratchAccuracy.high,
        this.color = Colors.black,
        this.image,
        this.onChange,
        this.onThreshold,
      }) : super(key: key);
    

    the default black color may cause the scratcher show black so it can't be covered by the image Please check, thank you.

    bug 
    opened by ben060788 5
  • Quality of the image is dropped significantly

    Quality of the image is dropped significantly

    I spent over 3 hours correcting problems I may have with my image, but only to realize that quality of the image is dropped significantly by this widget itself.

    I am using the latest 1.4.0 version. Let's keep the same quality of the image, can we?

    question 
    opened by frankyvij 4
  • Scratch image is not showing.

    Scratch image is not showing.

    I cloned it. everything are good working. But Scratch image is not showing. other asset image is good working but only Scratch image is not showing.

    I did packages get and upgrade. and try change other file. But Scratch image can not change. (other image is good to change. ex. google.png) and It same with other emulator.

    image: Image.asset('assets/scratch.png'), Screen Shot 2020-07-25 at 9 39 45 AM

    Also, Give me some advise for apply network image. Thanks.

    opened by dagulri 4
  • Check how much of a specific area has been scratched

    Check how much of a specific area has been scratched

    Hey Kamil,

    so far I can tell that your package is exactly what I've been looking for and it works great! Thank you so much!

    Now I'm using this package to create a test for users that need to scratch free a picture above a picture. So far so good. But I need to check afterwards how much of a specific rectangular area on that picture a user has scratched free.

    See this image for example: https://www.wiso.uni-hamburg.de/10054699/scraching1-7410709a6d0ee7f6066922f31886f2fc7ed065c1.png

    All five displays would be a different Scratcher and I need to determine how much of those grey areas on those displays have been scratched free.

    So it's like your current threshold but for several, rectangular areas instead of the full image. But it feels like that would need a completely different way of calculating those progress.

    Do you have any ideas or suggestions?

    question 
    opened by rubenaster 3
  • Spiky drawing

    Spiky drawing

    When drawing the circular paint changes to spiky drawings, see screencast below.

    Reproduce:

    • Scratcher 2.2.0 Example Project
    • Flutter (Channel stable, 3.0.0, on macOS 12.3.1 21E258 darwin-x64, locale en-US)
    • Dart SDK version: 2.17.0 (stable) (Mon May 9 10:36:47 2022 +0200) on "macos_x64"

    (Also tested with Flutter 2.10.5, same bug.)

    Tested on iPhone 13, Samsung S21 and Simulators. Same result everywhere.

    https://user-images.githubusercontent.com/13810971/168308646-c36b7a81-5adc-48d8-9fbd-998ff9a71d70.mov

    bug 
    opened by m-mak 2
  • Support Scratcher for web using HTML renderer

    Support Scratcher for web using HTML renderer

    Hi @vintage,

    Currently, the scratcher plugin works well using canvaskit for the web platform. But the problem is that it freezes up the app when the app hits a performance issue and it forces the browser to reload on iOS devices. This is producible on both 2.0.0 and 2.2.0 flutter stable channel. When using html renderer, it only displays the image and it can't be scratch off.

    Are there any workarounds or suggestions to get this plugin working using html renderer?

    Thanks,

    Neel

    opened by ineelp 2
  • Wrong size when using CachedNetworkImage

    Wrong size when using CachedNetworkImage

    Hey,

    I'm using Scratcher with CachedNetworkImage and the issue I have is that on the first call of OnDraw after the image is loaded I get a size of (10, 10). Quickly afterwards OnDraw is called again with the correct size.

    The problem is that the first call of OnDraw already initializes the points lists.

    Now my current workaround is to check in OnDraw if the size has changed and if so I re-initialize the points. Of course this might lead to issues.

    It works for now since the OnDraw calls appear quickly one ofter the other but maybe you have a better idea?

    bug 
    opened by rubenaster 2
  • BrushSize dinamically changing

    BrushSize dinamically changing

    Hi,

    I have this situation in the same screen:

    • the Scratcher widget with a network image that covers its Container widget child;
    • a SeekBar widget that's used to change dynamically the brushSize value of the Scratcher above.

    When I change the brushSize value through the SeekBar, I noticed that all the already scratched portion changes its brush. Instead, I'd like to get only the next scratch with the new brushSize value.

    So, is there a way to prevent this situation?

    (I'm sorry but I'm new with Flutter, maybe this has already been done).

    Thank you very much,

    Dario

    bug 
    opened by dariobrux 2
  • save state

    save state

    is it possible to save the scratched state so if you go back to the view, you can see the same partially scratched pattern as when you first visited it?

    enhancement 
    opened by jtkeyva 0
  • video? blur? opacity?

    video? blur? opacity?

    awesome package!

    can this support a video overlay and reveal another video underneath?

    also, is there any way to smply provide a background blur or frost effect and when you scratch, it unblurs?

    thanks!

    enhancement 
    opened by jtkeyva 4
  • Ability to disable multi touch gesture

    Ability to disable multi touch gesture

    Hi , unless I've missed something within the API - I couldnt see anyway to disallow multi touch gestures ?

    Currently its easy to scratch out the entire widget in just a few gestures by using two fingers, your thumb and an index finger - ensuring that your index finger is at the top of the widget to be scratched out and your thumb is at the bottom ... then you can scratch out the entire widget with one swipe gesture...

    enhancement 
    opened by alexda12 1
  • Replace key with controller approach

    Replace key with controller approach

    I was looking at the docs and I just noticed that the package allows the client to control it programmatically by using keys instead of a controller. Was there any reason to choose one over the other?

    enhancement good first issue 
    opened by Ascenio 1
  • Scratching gesture doesn't carry over to adjacent Scratcher

    Scratching gesture doesn't carry over to adjacent Scratcher

    To better fit the design of an app I'm making for scratch-off tickets, I tried having a grid of Scratcher widgets so I could have an icon centered over each revealed area. However, whichever Scratcher first gets the tap gesture won't let the adjacent widgets get the gesture so the only way I can reveal the whole area is to go cell-by-cell.

    Being able to scratch off multiple areas with one single stroke would be great! Thanks!

    enhancement 
    opened by BOBODDY 2
Owner
Kamil Rykowski
Flutter Developer | @Vaultomb founder
Kamil Rykowski
ID-Card - A Simple ID Card Project Using Flutter

ID-CARD A new Flutter project.A simple demonstration of my time in the Dart lang

edwromero 0 Jan 26, 2022
A simple package that provides you with some widgets and cutom clippers which implements the shape of a coupon card.

Coupon UI Kit A simple package that provides you with some widgets and cutom clippers which implements the shape of a coupon card. The example contain

AbdulMuaz Aqeel 15 Dec 20, 2022
Find out under which card the Flutter logo is hiding.

Flutter Card Flip Game Find out under which card the Flutter logo is hiding. Game Rules The purpose of this game is for the player to find out under w

Nickolas Chong 0 Dec 30, 2021
A flutter widget where a card is expanded ontap.

Expansion card This package provides an easy implementation of a Expansion type card where you can also add gif at the background. How to use import '

null 127 Dec 6, 2022
Flutter Credit Card Input form

This package provides visually beautiful UX through animation of credit card information input form. Preview Installing Add dependency to pubspec.yaml

Jeongtae Kim 426 Jan 5, 2023
A flutter package for building card based forms.

Card Settings NOTE: THIS IS EFFECTIVELY NULLSAFE BUT CANNOT REFLECT THIS UNTIL cupertino_settings IS UPGRADED. A flutter package for building settings

CodeGrue 445 Dec 26, 2022
Flutterwave landing page animated card deck implemented with Flutter

The Flutterwave animated card deck in Flutterwave's landing page implemented with Flutter.

null 38 Nov 10, 2022
This is my card using flutter

Mi Card Our Goal Now that you've seen how to create a Flutter app entirely from scratch, we're going to go further and learn more about how to design

Joshua Uzor 5 Dec 18, 2021
This is simple Ninja ID Card App Code ;)

ninjacard A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if thi

Saini Madhu 4 Oct 17, 2022
Flutter package - Animated Flip Card

Animated Flip Card Animated Flip Card package lets you add an animated flip card to your Flutter app that hide and show more informations. Features Th

Ulfhrafn 8 Dec 4, 2022
Flutter - Special animated flip card

special_card Flutter UI Design | Animated Flip Card. Demo for the app: animated-flip-card.mp4 Getting Started This project is a starting point for a F

Ulfhrafn 2 Dec 4, 2022
Flutter Card Management App(UI/UX)

Flutter Card Managing App - Cardy Bank I uploaded on youtube!! Thanks to Watch Introduction I'm working on a project to launch a simple brand. I tried

Lomio 8 Oct 31, 2022
Credit Card UI For Flutter

TP1 FLUTTER CREDIT CARD UI FIRST step : must enter the number of credit card then the expired date SECONDE step : you enter the CVV in the back of the

null 0 Nov 8, 2021
A flutter port of Cardidy, a package to validate or identify card numbers & cvv with ease.

Flutter Cardidy A plugin to validate or identify card numbers & cvv with ease. This flutter package will help you validate card numbers or CVVs and id

Heyramb Narayan Goyal 1 Nov 28, 2021
A Flutter package to easily create a Credit Card in your application.

Awesome Card A flutter package to create a Credit Card widget in your application. Stay tuned for the latest updates: ?? Screenshots ⚙️ Installation I

Vivek Kaushik 142 Dec 1, 2022
A Dart package that detects credit card types based on their prefixes

credit_card_type_detector | Credit Card Type Detector A Dart package that detects credit card types based on the current credit card number patterns T

Tanner Davis 22 Jan 4, 2023
Mi-card-app flutter project

my_card_app A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if t

null 1 Dec 2, 2021
Allows widgets to be zoomed in and out by inserting a OverlayEntry which allows the widget to be on the front at all times.

zoom_pinch_overlay An instagram style pinch and zoom widget for all platform completely written in pure dart! All other "zoom_pinch" package doesnt di

Samuel 18 Nov 29, 2022
DirectSelect is a selection widget with an ethereal, full-screen modal popup displaying the available choices when the widget is interact with. https://dribbble.com/shots/3876250-DirectSelect-Dropdown-ux

direct-select-flutter DirectSelect is a selection widget with an ethereal, full-screen modal popup displaying the available choices when the widget is

null 582 Jan 4, 2023