Download as pdf or txt
Download as pdf or txt
You are on page 1of 81

Lecture 6 : Interaction

Interfaces in Flutter
T. Fatima Al-azazi
Agenda

● Creating forms in Flutter


● User interaction with gesture detectors
● Draggable and DragTarget widget.
● Inkwell and InkResponse
● Special interaction widgets like Dismissible
● AnimatedContainer
● CrossFade
● AnimatedObacity

2
The Form widget

● The Form widget is a wrapper of sorts that provides some handy


methods and integrates with all the form field widgets in its subtree.
● The Form widget needs a unique key to identify it and is created by
using GlobalKey.
● This GlobalKey value is unique across the entire app.
● the form manages the state of all the fields in the form, removing the
need to handle state for each field individually.
● The Form widget is optional, but the benefits of using a Form widget
are to validate each text field as a group.
● Like all widgets, Form is managed by an associated Element .
● That element has a reference to a FormState object, which is created
internally in Flutter.
3
FormState Object

● A FormState object can be used to save, reset, and validate every


FormField that is a descendant of the associated Form.
● The built-in Flutter way to interact with Form is by passing it a key of
type FormState.
● The widget associates that global key with this particular form’s state
object, giving you access to the state object anywhere.
● This state object is an instance of the State class created for any
StatefulWidget with more functionality.
● The difference is that this state object is created internally, when you
create the global key. In practice, this means you can access it
throughout your form with this key reference.
4
FormState in the Element Tree

5
Form Example

6
VALIDATE TEXT FIELDS USING THE FORM WIDGET

● You can group TextFormField widgets to manually or automatically


validate them.
● The TextFormField widget wraps a TextField widget to provide
validation when enclosed in a Form widget.
● If all text fields pass the FormState validate method, then it returns
true.
● If any text fields contain errors, it displays the appropriate error
message for each text field, and the FormState validate method returns
false and not allowing the posting of invalid data.

7
Form Example 2

● In this example, you’ll create a


form with two TextFormFields to
enter an item and quantity to
order.
● create an Order class to hold the
item and quantity and fill the
order once the validation passes

8
Form with Children 1

3
4

9
State Class Data Model

State Class
Form Key

Data Model Object

Validate Method for Item

Validate Method for Quantity

10
SubmitOrder Method

11
12
Standard and Material Interactive Widgets

Material Components
● Checkbox
● DropdownButton
Standard widgets ● TextButton
● Form ● FloatingActionButton
● FormField ● IconButton
● Radio
● ElevatedButton
● Slider
● Switch
● TextField
13
GestureDetector

14
Adding Interactivity Using Gestures

● Gestures are any kind of interaction event: taps, drags, pans, and more
● In a mobile application, gestures are the heart of listening to user
interaction.
● Making use of gestures can define an app with a great UX.
● Overusing gestures when they don’t add value or convey an action
creates a poor UX.
● Flutter allows you to add gesture detectors to any location of the
widget tree.
● All the button widgets that have onPressed and onTap are just
convenient wrappers around gesture detectors.

15
The GestureDetector widget

● The core user-interaction widget is called a GestureDetector.


● You can wrap this widget around any other widget and make that child
widget listen for interaction from the user.
● you tell a widget to listen for interaction, and you give it a callback to
execute when interaction is detected.
● GestureDetector needs only two things passed to it: a widget (its child)
and a callback to correspond to a gesture.
● Although GestureDetector needs only one gesture callback, it can be
passed many different callbacks and will respond differently based on
the gesture it detects.

16
Gestures That You Can Listen for

● Tap ● Scale ● Vertical drag


○ onTapDown ○ onScaleStart ○ onVerticalDragStart
○ onTapUp ○ onScaleUpdate ○ onVerticalDragUpdate
○ onTap ○ onScaleEnd ○ onVerticalDragEnd
○ onTapCancel ● Pan ● Horizontal drag
● Double tap ○ onPanStart ○ onHorizontalDragStart
○ onDoubleTap ○ onPanUpdate ○ onHorizontalDragUpdate
○ Long press ○ onPanEnd ○ onHorizontalDragEnd
○ onLongPress

17
Gesture Arguments and Callbacks

● All of these arguments will call the callback you pass, and some will
pass back “details.”
● onTapUp, for example, passes back an instance of the TapUpDetails
object, which exposes the globalPosition, or location on the screen
that was tapped.
● Some of the more complicated gestures, like the drag-related ones,
pass back more interesting properties.
● You can get details about the time a drag started, the position where
it started, the position where it ended, and the velocity of the drag.
● This lets you manipulate drags based on direction, speed, and so on.

18
19
SETTING UP GESTUREDETECTOR

● The GestureDetector widget detects gestures such as tap, double tap,


long press, pan, vertical drag, horizontal drag, and scale.
● It has an optional child property, and if a child widget is specified, the
gestures apply only to the child widget.
● If the child widget is omitted, then the GestureDetector fills the entire
parent instead.
● If you need to catch vertical drag and horizontal drag at the same time,
use the pan gesture.
● If you need to catch a single-axis drag, then use either the vertical drag
or horizontal drag gesture

20
Incorrect GestureDetector Arguments

● Using vertical drag, horizontal drag, and pan gestures at the same time,
causes an Incorrect GestureDetector Arguments error.
● However, if you use either vertical or horizontal drag with a pan
gesture, you’ll not receive any errors.
● The reason you receive the error is that simultaneously having a
vertical and horizontal drag gesture and a pan gesture results in the
pan gesture being ignored since the vertical and horizontal drag will
first catch all of the drags.
● You’ll get the same kind of error if you try to use vertical drag,
horizontal drag, and scale gestures at the same time.

21
DRAGGABLE AND DRAGTARGET
WIDGETS

22
DRAGGABLE AND DRAGTARGET WIDGETS

● To implement a drag-and-drop feature, you drag the Draggable widget


to a DragTarget widget.
● use the data property to pass any custom data
● use the child property to display a widget like an Icon and remains
visible while not being dragged as long as the childWhenDragging
property is null.
● Set the childWhenDragging property to display a widget while
dragging.
● Use the feedback property to display a widget showing the user visual
feedback where the widget is being dragged.

23
DRAGGABLE AND DRAGTARGET WIDGETS

● Once the user lifts their finger on top of the DragTarget, the target can
accept the data.
● To reject accepting the data, the user moves away from the DragTarget
without releasing touch.
● If you need to restrict the dragging vertically or horizontally, you
optionally set the Draggable axis property.
● To catch a single axis drag, you set the axis property to either
Axis.vertical or Axis.horizontal.

24
DRAGTARGET WIDGET

● The DragTarget widget listens for a Draggable widget and receives data
if dropped.
● The DragTarget builder property accepts three parameters: the
BuildContext, List acceptedData (candidateData), and List of
rejectedData.
● The acceptedData is the data passed from the Draggable widget, and it
expects it to be a List of values. The rejectedData contains the List of
data that will not be accepted.

25
Example Draggable

26
DragTarget

27
GESTUREDETECTOR FOR MOVING
AND SCALING

28
Gestures for Moving and Scaling

● The GestureDetector gives you the ability to accomplish scaling by


using onScaleStart and onScaleUpdate.
● Use onDoubleTap to increase the zoom, and use onLongPress to reset
the zoom to the original default size
● When the user taps the image, the image can be dragged around to
change position or scaled by zooming in/out.
● To accomplish both requirements, you’ll use the Transform widget.
● Use the Transform.scale constructor to resize the image
● use the Transform.translate constructor to move the image

29
Transform widget
● The Transform widget applies a transformation before the child is
painted.
● Using the Transform default constructor, the transform argument is set
by using the Matrix4 (4D Matrix) class, and this transformation matrix
is applied to the child during painting.
● the default constructor uses the Matrix4 to execute multiple cascading
(..scale()..translate()) transformations.
● The double dots (..) are used to cascade multiple transformations.
● the cascade notation allows you to make a sequence of operations on
the same object.

30
The Transform widget constructors.

● Transform: Default constructor taking a Matrix4 for the transform


argument.
● Transform.rotate: Constructor to rotate a child widget around the
center by using an angle.
○ The angle argument rotates clockwise by radians.
○ To rotate counterclockwise, pass a negative radian.

31
The Transform widget constructors.

● Transform.scale: Constructor to evenly scale a child widget on the


x-axis and y-axis.
○ The widget is scaled by its center alignment.
○ The scale argument value of 1.0 is the original widget size.
○ Any values above 1.0 scale the widget larger, and values below 1.0
scale the widget smaller.
○ A value of 0.0 makes the widget invisible.
● Transform.translate: Constructor to move/position a child widget by
using a translation, an offset.
○ The offset argument takes the Offset(double dx, double dy) class
by positioning the widget on the x-axis and y-axis.
32
Example

● Imagine if this is a journal app and the user


navigated to this page to view the selected
image with the ability to zoom for more
details.
● The image is moved by a single touch drag
and can be zoomed in/out (pinching) by using
multitouch.
● Double tapping allows the image to zoom in
at the tapped location, and a single long press
resets the image location and zoom level
back to default values.
33
34
Widgets Structure

● The GestureDetector is the body (property) base widget and is


listening for the onScaleStart, onScaleUpdate, onDoubleTap, and
onLongPress gestures (properties).
● The GestureDetector child is a Stack that shows the image and a
gesture status bar display.
● To apply the moving and scaling of the image, use the Transform
widget.
● To show different ways to apply changes to a widget, you make use of
three different Transform constructors: default, scale, and translate.

35
Moving and Scaling Techniques

● You’ll take a look at two techniques to accomplish the same moving and
scaling results.
● The first technique involves nesting the scale and translate
constructors.
● The second technique uses the default constructor with the Matrix4 to
apply transformations.

36
The first technique

37
The second technique

38
39
40
onScaleStart

41
42
43
onLongPress

44
INKWELL AND INKRESPONSE
GESTURES

45
InkWell and InkResponse widgets
● Both the InkWell and InkResponse widgets are Material Components
that respond to touch gestures.
● The InkWell class extends (subclass) the InkResponse class.
● The InkResponse class extends a StatefulWidget class.
● For the InkWell, the area that responds to touch is rectangular in
shape and shows a “splash” effect—though it really looks like a ripple.
● The splash effect is clipped to the rectangular area of the widget (so as
not go outside it).
● If you need to expand the splash effect outside the rectangular area,
the InkResponse has a configurable shape.
● By default, the InkResponse shows a circular splash effect that can
expand outside its shape (Figure 11.3). 46
● The following are the InkWell and
InkResponse gestures that you can
listen for action.
● The gestures captured are taps on the
screen except for the
onHighlightChanged property, which is
called when part of the material starts or
stops being highlighted.
● The main benefits of using the InkWell
and InkResponse are to capture taps on
the screen and have a beautiful splash.
This kind of reaction makes for a good
UX, correlating an animation to a user’s
action. 47
Properties

● Tap ● Long press


○ onTap ○ onLongPress
○ onTapDown ● Highlight changed
○ onTapCancel ○ onHighlightChanged
● Double tap
○ onDoubleTap

48
49
50
HOW IT WORKS

● Both the InkWell and InkResponse widgets listen to the same gesture
callbacks.
● The widgets capture the onTap, onDoubleTap, and onLongPress
gestures (properties).
● When a single tap is captured, the onTap calls the _setScaleSmall()
method to scale the image to half the original size.
● When a double tap is captured, the onDoubleTap calls the
_setScaleBig() method to scale the image to 16 times the original size.
● When a long press is captured, the onLongPress calls the
_onLongPress() method to reset all values to the original positions and
sizes.
51
DISMISSIBLE WIDGET

52
USING THE DISMISSIBLE WIDGET
● The Dismissible widget is dismissed by a dragging gesture.
● The direction of the drag can be changed by using DismissDirection for
the direction property.
● The Dismissible child widget slides out of view and automatically
animates the height or width (depending on dismiss direction) down to
zero.
● This animation happens in two steps; first the Dismissible child slides
out of view, and second, the size animates down to zero.

53
onDismissed callback

● Once the Dismissible is dismissed, you can use the onDismissed


callback to perform any necessary actions such as removing a data
record from the database or marking a to-do item complete .
● If you do not handle the onDismissed callback, you’ll receive the error
“A dismissed Dismissible widget is still part of the tree.”
● For example, if you use a List of items, once the Dismissible is removed
you need to remove the item from the List by implementing the
onDismissed callback.
● The Dismissible handles all the animations such as sliding, resizing to
remove the selected row, and sliding the next item on the list upward.

54
Dismissible widget showing the swiped row
dismissed animation to complete the item

55
DismissDirection Dismiss Options

56
Example

● In this example, you’ll build a list of


vacation trips
● when you drag from left to right, the
Dismissible shows a checkbox icon
with a green background to mark the
trip completed.
● When swiping from right to left, the
Dismissible shows a delete icon with a
red background to remove the trip.

57
Data Model

58
State class

59
60
buildRemoveTrip method

buildCompleteTrip method

61
markTripCompleted method

deleteTrip method

buildListTile method

62
63
Animation Widgets

64
ANIMATEDCONTAINER

● Let’s start with a simple animation by using the AnimatedContainer


widget.
● This is a Container widget that gradually changes values over a period
of time.
● The AnimatedContainer constructor has arguments called duration,
curve, color, height, width, child, decoration, transform, and many
others.

65
ANIMATEDCONTAINER

● The AnimatedContainer constructor takes a duration argument, and


you use the Duration class to specify 500 milliseconds.
● The curve argument gives the animation a spring effect by using
Curves.elasticOut.
● The onPressed argument calls the _increaseWidth() method to change
the _width variable dynamically.
● The setState() method notifies the Flutter framework that the internal
state of the object changed and causes the framework to schedule a
build for this State object.
● The AnimatedContainer widget automatically animates between the
old _width value and the new _width value.
66
ANIMATEDCONTAINER Example

67
USING ANIMATEDCROSSFADE

● The AnimatedCrossFade widget provides a great cross-fade between


two children widgets.
● The AnimatedCrossFade constructor takes duration, firstChild,
secondChild, crossFadeState, sizeCurve, and many other arguments.

68
USING ANIMATEDOPACITY

● If you need to hide or partially hide a widget, AnimatedOpacity is a


great way to animate fading over time.
● The AnimatedOpacity constructor the takes duration, opacity, curve,
and child arguments. For this example, you do not use a curve; since
you want a smooth fade-out and fade-in.

69
Adding interactivity to your
Flutter app

70
Creating a stateful widget

Step 1: Decide which object manages the widget’s state

Step 2: Subclass StatefulWidget

Step 3: Subclass State

Step 4: Plug the stateful widget into the widget tree

71
Example
● When the app first launches, the star is solid red, indicating that this
lake has previously been favorited.
● The number next to the star indicates that 41 people have favorited
this lake.
● tapping the star removes its favorited status,
○ replacing the solid star with an outline and
○ decreasing the count.
● Tapping again favorites the lake,
○ drawing a solid star and
○ increasing the count.

72
Step 1: Decide which object manages the widget’s
state

● A widget’s state can be managed in several ways, but in our example


the widget itself, FavoriteWidget, will manage its own state.
● In this example, toggling the star is an isolated action that doesn’t affect
the parent widget or the rest of the UI, so the widget can handle its
state internally.
● Learn more about the separation of widget and state, and how state
might be managed, in Managing state.

73
Step 2: Subclass StatefulWidget
● The FavoriteWidget class manages its own state, so it overrides
createState() to create a State object.
● The framework calls createState() when it wants to build the
widget.
● In this example, createState() returns an instance of
_FavoriteWidgetState, which you’ll implement in the next step.

74
Step 3: Subclass State

● The _FavoriteWidgetState class stores the mutable data that can


change over the lifetime of the widget.
● When the app first launches, the UI displays a solid red star, indicating
that the lake has “favorite” status, along with 41 likes.
● These values are stored in the _isFavorited and _favoriteCount
fields:

75
76
The _toggleFavorite() method, which is called when the IconButton
is pressed, calls setState().

Calling setState() is critical, because this tells the framework that the
widget’s state has changed and that the widget should be redrawn.

The function argument to setState() toggles the UI between these two


states:

● A star icon and the number 41


● A star_border icon and the number 40

77
Step 4: Plug the stateful widget into the widget tree

Add your custom stateful widget to the widget tree in the app’s build()
method. First, locate the code that creates the Icon and Text, and delete
it. In the same location, create the stateful widget:

78
Managing state

Who manages the stateful widget’s state? The widget itself? The parent
widget? Both? Another object? The answer is… it depends. There are several
valid ways to make your widget interactive. You, as the widget designer,
make the decision based on how you expect your widget to be used. Here
are the most common ways to manage state:

● The widget manages its own state


● The parent manages the widget’s state
● A mix-and-match approach

79
Decide which approach to use

How do you decide which approach to use? The following principles should
help you decide:

● If the state in question is user data, for example the checked or


unchecked mode of a checkbox, or the position of a slider, then the
state is best managed by the parent widget.
● If the state in question is aesthetic, for example an animation, then the
state is best managed by the widget itself.

If in doubt, start by managing state in the parent widget.

80
Assignment 4

● What are:
○ ANIMATIONCONTROLLER with example
○ Staggered Animations with example
● Design and build your app with Interactive Screens

81

You might also like