Foundation

Tappable

An area that responds to touch.

This widget is typically used to create other high-level widgets, e.g., button. You should prefer those high-level widgets unless you're creating a custom widget.

1@override
2Widget build(BuildContext context) => FTappable(
3 builder: (context, states, child) => Container(
4 decoration: BoxDecoration(
5 color:
6 (states.contains(FTappableVariant.hovered) ||
7 states.contains(FTappableVariant.pressed))
8 ? context.theme.colors.secondary
9 : context.theme.colors.background,
10 borderRadius: .circular(8),
11 border: .all(color: context.theme.colors.border),
12 ),
13 padding: const .symmetric(vertical: 8.0, horizontal: 12),
14 child: child!,
15 ),
16 child: const Text('Tappable'),
17 onPress: () {},
18);
19

Usage

FTappable(...)

1FTappable(
2 style: const .delta(motion: FTappableMotion.none),
3 focusedOutlineStyle: const .delta(color: Colors.black),
4 selected: false,
5 behavior: .translucent,
6 builder: (context, states, child) => child!,
7 child: const Text('Tap me'),
8)

FTappable.static(...)

A variant of FTappable without any animation. This is similar to using FTappableMotion.none.

1FTappable.static(
2 style: const .delta(motion: FTappableMotion.none),
3 focusedOutlineStyle: const .delta(color: Color(0xFF000000)),
4 selected: false,
5 behavior: .translucent,
6 builder: (context, states, child) => child!,
7 child: const Text('Tap me'),
8)

Custom Bounce Animation

You can customize a tappable's bounce animation by passing a FTappableMotion.

1const _motions = {
2 'Default': FTappableMotion(),
3 'Heavy': FTappableMotion(bounceTween: FImmutableTween(begin: 1.0, end: 0.9)),
4 'None': FTappableMotion.none,
5};
6
7class TappableBounceExample extends StatelessWidget {
8 @override
9 Widget build(BuildContext context) => Row(
10 mainAxisSize: .min,
11 spacing: 10,
12 children: [
13 for (final MapEntry(:key, :value) in _motions.entries)
14 FTappable(
15 style: .delta(motion: value),
16 onPress: () {},
17 builder: (context, states, child) => Container(
18 decoration: BoxDecoration(
19 color: states.contains(FTappableVariant.pressed)
20 ? context.theme.colors.secondary
21 : context.theme.colors.background,
22 borderRadius: context.theme.style.borderRadius.md,
23 border: .all(color: context.theme.colors.border),
24 ),
25 padding: const .symmetric(vertical: 8.0, horizontal: 12),
26 child: child!,
27 ),
28 child: Text(key, style: context.theme.typography.sm),
29 ),
30 ],
31 );
32}
33

Slide-across Interaction

Several tappables can be placed in a FTappableGroup to enable slide-across interaction. When you press one tappable and slide across to another, the pressed state transfers to the new tappable.

1@override
2Widget build(BuildContext context) => FTappableGroup(
3 child: Row(
4 mainAxisSize: .min,
5 spacing: 10,
6 children: [
7 for (final label in ['Copy', 'Cut', 'Paste'])
8 FTappable(
9 onPress: () {},
10 builder: (context, states, child) => Container(
11 decoration: BoxDecoration(
12 color: states.contains(FTappableVariant.pressed)
13 ? context.theme.colors.secondary
14 : context.theme.colors.background,
15 borderRadius: context.theme.style.borderRadius.md,
16 border: .all(color: context.theme.colors.border),
17 ),
18 padding: const .symmetric(vertical: 8.0, horizontal: 12),
19 child: child!,
20 ),
21 child: Text(label, style: context.theme.typography.sm),
22 ),
23 ],
24 ),
25);
26

On this page