Tappable
A collection of highly customizable, tree-shakable Flutter widgets with Material Design integration. Build beautiful, interactive UIs with minimal code while keeping your bundle size optimal.
Features
- π― Tappable - Base widget with flexible tap mechanics system
- π¦ TappableContainer - Combines Tappable with Container, auto-syncing border radius
- β¨ Tap Mechanics - Pluggable tap effects: Ripple, Scale, Press, Opacity, and more
- π Composable - Combine multiple tap mechanics for rich interactions
- π TButton - Fully customizable button with disabled states (DEPRECATED - use tappable_elements)
- βοΈ TCheckbox - Customizable checkbox with builder pattern (DEPRECATED - use tappable_elements)
- π TSwitch - Animated switch with smooth transitions (DEPRECATED - use tappable_elements)
- π³ Tree-shakable - Import only what you need to minimize bundle size
- π¨ Highly customizable - Builder patterns and extensive parameters for complete control
- βΏ Material Design - Proper ink effects, theming, and platform integration
Installation
Add this to your package's pubspec.yaml file:
dependencies:
tappable:
path: ../tappable
Or if published to pub.flutter-io.cn:
dependencies:
tappable: ^0.0.1
Quick Start
Import
// Import all widgets
import 'package:tappable/tappable.dart';
// Or import individually for tree-shaking
import 'package:tappable/widgets/tappable.dart';
import 'package:tappable/widgets/t_button.dart';
Basic Usage
Tappable Widget
// Default ripple effect
Tappable(
onTap: () => print('Tapped!'),
borderRadius: BorderRadius.circular(12),
child: Text('Tap me!'),
)
// With custom tap mechanics
Tappable(
onTap: () => print('Tapped!'),
tapMechanics: [
RippleTapMechanic(
splashColor: Colors.blue.withValues(alpha: 0.3),
),
],
child: Text('Custom ripple!'),
)
// Combine multiple mechanics
Tappable(
onTap: () => print('Tapped!'),
tapMechanics: [
RippleTapMechanic(),
ScaleTapMechanic(scaleFactor: 0.95),
],
child: Text('Ripple + Scale!'),
)
TButton Widget
TButton(
onPressed: () => print('Pressed!'),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(8),
),
child: Text('Click Me', style: TextStyle(color: Colors.white)),
)
TCheckbox Widget
bool isChecked = false;
TCheckbox(
value: isChecked,
onChanged: (value) => setState(() => isChecked = value),
)
TSwitch Widget
bool isSwitched = false;
TSwitch(
value: isSwitched,
onChanged: (value) => setState(() => isSwitched = value),
)
TappableContainer Widget
TappableContainer(
onTap: () => print('Container tapped!'),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(16),
),
padding: EdgeInsets.all(20),
child: Text('Beautiful Card'),
)
Tap Mechanics
Tap mechanics define how widgets respond visually when tapped. Multiple mechanics can be combined to create rich, interactive experiences.
Available Mechanics
| Mechanic | Description | Use Case |
|---|---|---|
| RippleTapMechanic | Material Design ink ripple | Default Material Design apps |
| ScaleTapMechanic | Scales widget on press | iOS-style buttons, modern UIs |
| PressTapMechanic | 3D press effect with shadow | Elevated buttons, realistic interactions |
| OpacityTapMechanic | Fades opacity on press | iOS-style, minimal feedback |
| RaisedEdgeTapMechanic | 3D raised bottom effect with vertical scaling | Keyboard buttons, game UIs, retro interfaces |
| NoneTapMechanic | No visual feedback | Custom interactions, invisible tap areas |
Single Mechanics
// Material ripple (default)
Tappable(
onTap: () {},
tapMechanics: [RippleTapMechanic()],
child: Text('Ripple'),
)
// Scale animation
Tappable(
onTap: () {},
tapMechanics: [ScaleTapMechanic(scaleFactor: 0.95)],
child: Text('Scale'),
)
// 3D press effect
Tappable(
onTap: () {},
tapMechanics: [
PressTapMechanic(
pressDepth: 4.0,
shadowColor: Colors.black26,
),
],
child: Text('Press'),
)
// Opacity fade (iOS-style)
Tappable(
onTap: () {},
tapMechanics: [OpacityTapMechanic(opacity: 0.6)],
child: Text('Fade'),
)
// 3D raised edge effect (raised bottom that lowers on press)
Tappable(
onTap: () {},
borderRadius: BorderRadius.circular(8),
tapMechanics: [
RaisedEdgeTapMechanic(
raisedEdgeHeight: 8.0,
raisedEdgeColor: Colors.blue.shade900,
),
],
child: Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(8),
),
child: Text('3D Button', style: TextStyle(color: Colors.white)),
),
)
Combined Mechanics
The real power comes from combining multiple mechanics:
// Ripple + Scale: Material feel with modern animation
Tappable(
onTap: () {},
tapMechanics: [
RippleTapMechanic(splashColor: Colors.blue.withValues(alpha: 0.3)),
ScaleTapMechanic(scaleFactor: 0.95),
],
child: Text('Ripple + Scale'),
)
// Press + Opacity: Realistic 3D button
Tappable(
onTap: () {},
tapMechanics: [
PressTapMechanic(pressDepth: 4.0, shadowColor: Colors.black26),
OpacityTapMechanic(opacity: 0.8),
],
child: Text('Press + Fade'),
)
// Triple combo: Maximum feedback
Tappable(
onTap: () {},
tapMechanics: [
RippleTapMechanic(),
ScaleTapMechanic(scaleFactor: 0.92),
OpacityTapMechanic(opacity: 0.7),
],
child: Text('All Effects'),
)
Custom Configuration
Each mechanic accepts custom parameters:
ScaleTapMechanic(
scaleFactor: 0.85, // Scale to 85%
duration: Duration(milliseconds: 300), // Slow animation
curve: Curves.elasticOut, // Bouncy curve
)
PressTapMechanic(
pressDepth: 8.0, // Deep press
shadowColor: Colors.red.withValues(alpha: 0.4),
shadowBlurRadius: 12.0, // Large shadow
pressedShadowBlurRadius: 4.0, // Small when pressed
)
RippleTapMechanic(
splashFactory: InkSparkle.splashFactory, // Material 3 sparkle
splashColor: Colors.purple.withValues(alpha: 0.3),
)
RaisedEdgeTapMechanic(
raisedEdgeHeight: 12.0, // Height of raised bottom
raisedEdgeColor: Colors.indigo.shade900, // Bottom edge color
raisedEdgeGradient: LinearGradient( // Optional gradient for bottom
colors: [Colors.indigo.shade900, Colors.indigo.shade700],
),
duration: Duration(milliseconds: 200), // Animation duration
curve: Curves.easeInOut, // Animation curve
)
Advanced Examples
Custom Button with Gradient
TButton(
onPressed: () {},
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.purple, Colors.deepPurple],
),
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.purple.withValues(alpha: 0.4),
blurRadius: 12,
offset: Offset(0, 6),
),
],
),
padding: EdgeInsets.symmetric(horizontal: 32, vertical: 16),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.rocket_launch, color: Colors.white),
SizedBox(width: 8),
Text('Launch', style: TextStyle(color: Colors.white)),
],
),
)
Custom Checkbox with Builders
TCheckbox(
value: isChecked,
onChanged: (value) => setState(() => isChecked = value),
size: 28,
buildBackground: (context, value) {
return Container(
decoration: BoxDecoration(
gradient: value
? LinearGradient(colors: [Colors.purple, Colors.blue])
: null,
color: value ? null : Colors.grey.shade200,
borderRadius: BorderRadius.circular(8),
),
);
},
buildThumb: (context, value) {
return Icon(Icons.check_circle, size: 20, color: Colors.white);
},
)
Documentation
For complete documentation with detailed API reference, advanced usage patterns, and best practices, see CLAUDE.md.
The full documentation includes:
- Complete parameter tables for all widgets
- Multiple examples from basic to advanced
- Design philosophy and architecture decisions
- Advanced usage patterns and combinations
- Best practices and recommendations
Widgets Overview
| Widget | Description |
|---|---|
| Tappable | Base interactive widget with pluggable tap mechanics |
| TappableContainer | Combines Tappable with Container, auto-syncs border radius |
| RippleTapMechanic | Material Design ripple effect |
| ScaleTapMechanic | Scale animation on press |
| PressTapMechanic | 3D press effect with shadow |
| OpacityTapMechanic | Opacity fade on press |
| RaisedEdgeTapMechanic | 3D raised bottom effect with vertical scaling |
| NoneTapMechanic | No visual feedback |
| TButton | Highly customizable button (DEPRECATED) |
| TCheckbox | Customizable checkbox (DEPRECATED) |
| TSwitch | Animated switch (DEPRECATED) |
Why Tappable?
- Tree-shakable: Import only the widgets you use
- Customizable: Every widget is built for maximum flexibility
- Composable: Widgets work together seamlessly
- Material Design: Proper integration with Flutter's Material Design
- Well-documented: Comprehensive documentation and examples
- Type-safe: Full TypeScript-like type safety with Dart
License
This project is licensed under the MIT License - see the LICENSE file for details.
Changelog
See CHANGELOG.md for a detailed history of changes.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Support
For issues, feature requests, or questions, please file an issue on GitHub.