├── .github └── workflows │ └── dart.yml ├── .gitignore ├── README.md ├── flutter-counter.iml ├── gif └── App.gif ├── lib ├── example │ └── example.dart ├── src │ └── stepper.dart └── stepper_touch.dart ├── pubspec.lock └── pubspec.yaml /.github/workflows/dart.yml: -------------------------------------------------------------------------------- 1 | name: Dart CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: x64 9 | 10 | container: 11 | image: google/dart:latest 12 | 13 | steps: 14 | - uses: actions/checkout@v1 15 | - name: Install dependencies 16 | run: pub get 17 | - name: Run tests 18 | run: pub run test 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | .gradle 4 | .packages 5 | .pub/ 6 | build/ 7 | ios/.generated/ 8 | ios/Flutter/Generated.xcconfig 9 | ios/Runner/GeneratedPluginRegistrant.* 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flutter Counter App 2 | 3 | 4 | 5 | 6 | Awesome Flutter 7 | 8 |
9 | Just an Counter UI using Flutter 10 | 11 | # UI 12 | ![Preview](./gif/App.gif?raw=true 'android') 13 | 14 | # Thank _You_! 15 | Please :star: this repo and share it with others 16 | 17 | ### Created By 18 | 19 | * [Raj Chowdhury](https://github.com/Rajchowdhury420) 20 | -------------------------------------------------------------------------------- /flutter-counter.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /gif/App.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RajChowdhury240/Flutter-Counter-App/a62c8a1b6e239a4dd84f2cc4872fe241567d1fdb/gif/App.gif -------------------------------------------------------------------------------- /lib/example/example.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:stepper_touch/stepper_touch.dart'; 4 | 5 | void main() => runApp( 6 | MaterialApp( 7 | theme: ThemeData( 8 | scaffoldBackgroundColor: const Color(0xFF6D72FF), 9 | ), 10 | home: MyApp(), 11 | ), 12 | ); 13 | 14 | 15 | // Coded By Raj Chowdhury 16 | 17 | 18 | class MyApp extends StatefulWidget { 19 | @override 20 | _MyAppState createState() => _MyAppState(); 21 | } 22 | 23 | class _MyAppState extends State { 24 | @override 25 | Widget build(BuildContext context) { 26 | return Scaffold( 27 | body: SafeArea( 28 | child: Center( 29 | child: Column( 30 | mainAxisAlignment: MainAxisAlignment.center, 31 | children: [ 32 | Padding( 33 | padding: const EdgeInsets.all(8.0), 34 | child: StepperTouch( 35 | initialValue: 0, 36 | direction: Axis.vertical, 37 | withSpring: false, 38 | onChanged: (int value) => print('new value $value'), 39 | ), 40 | ), 41 | Padding( 42 | padding: const EdgeInsets.all(8.0), 43 | child: StepperTouch( 44 | initialValue: 0, 45 | onChanged: (int value) => print('new value $value'), 46 | ), 47 | ), 48 | ], 49 | ), 50 | ), 51 | ), 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/src/stepper.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/physics.dart'; 3 | 4 | class StepperTouch extends StatefulWidget { 5 | const StepperTouch({ 6 | Key key, 7 | this.initialValue, 8 | this.onChanged, 9 | this.direction = Axis.horizontal, 10 | this.withSpring = true, 11 | }) : super(key: key); 12 | 13 | 14 | /// the orientation of the stepper its horizontal or vertical. 15 | final Axis direction; 16 | 17 | /// the initial value of the stepper 18 | final int initialValue; 19 | 20 | /// called whenever the value of the stepper changed 21 | final ValueChanged onChanged; 22 | 23 | /// if you want a springSimulation to happens the the user let go the stepper 24 | /// defaults to true 25 | final bool withSpring; 26 | 27 | // Coded By Raj Chowdhury 28 | 29 | @override 30 | _Stepper2State createState() => _Stepper2State(); 31 | } 32 | 33 | 34 | class _Stepper2State extends State 35 | with SingleTickerProviderStateMixin { 36 | AnimationController _controller; 37 | Animation _animation; 38 | int _value; 39 | double _startAnimationPosX; 40 | double _startAnimationPosY; 41 | 42 | 43 | @override 44 | void initState() { 45 | super.initState(); 46 | _value = widget.initialValue ?? 0; 47 | _controller = 48 | AnimationController(vsync: this, lowerBound: -0.5, upperBound: 0.5); 49 | _controller.value = 0.0; 50 | _controller.addListener(() {}); 51 | 52 | if (widget.direction == Axis.horizontal) { 53 | _animation = Tween(begin: Offset(0.0, 0.0), end: Offset(1.5, 0.0)) 54 | .animate(_controller); 55 | } else { 56 | _animation = Tween(begin: Offset(0.0, 0.0), end: Offset(0.0, 1.5)) 57 | .animate(_controller); 58 | } 59 | } 60 | 61 | 62 | @override 63 | void dispose() { 64 | _controller?.dispose(); 65 | super.dispose(); 66 | } 67 | 68 | 69 | @override 70 | void didUpdateWidget(oldWidget) { 71 | super.didUpdateWidget(oldWidget); 72 | if (widget.direction == Axis.horizontal) { 73 | _animation = Tween(begin: Offset(0.0, 0.0), end: Offset(1.5, 0.0)) 74 | .animate(_controller); 75 | } else { 76 | _animation = Tween(begin: Offset(0.0, 0.0), end: Offset(0.0, 1.5)) 77 | .animate(_controller); 78 | } 79 | } 80 | 81 | // !test = init(); 82 | 83 | @override 84 | Widget build(BuildContext context) { 85 | return FittedBox( 86 | child: Container( 87 | width: widget.direction == Axis.horizontal ? 280.0 : 120.0, 88 | height: widget.direction == Axis.horizontal ? 120.0 : 280.0, 89 | child: Material( 90 | type: MaterialType.canvas, 91 | clipBehavior: Clip.antiAlias, 92 | borderRadius: BorderRadius.circular(60.0), 93 | color: Colors.white.withOpacity(0.2), 94 | child: Stack( 95 | alignment: Alignment.center, 96 | children: [ 97 | Positioned( 98 | left: widget.direction == Axis.horizontal ? 10.0 : null, 99 | bottom: widget.direction == Axis.horizontal ? null : 10.0, 100 | child: Icon(Icons.remove, size: 40.0, color: Colors.white), 101 | ), 102 | Positioned( 103 | right: widget.direction == Axis.horizontal ? 10.0 : null, 104 | top: widget.direction == Axis.horizontal ? null : 10.0, 105 | child: Icon(Icons.add, size: 40.0, color: Colors.white), 106 | ), 107 | GestureDetector( 108 | onHorizontalDragStart: _onPanStart, 109 | onHorizontalDragUpdate: _onPanUpdate, 110 | onHorizontalDragEnd: _onPanEnd, 111 | child: SlideTransition( 112 | position: _animation, 113 | child: Material( 114 | color: Colors.white, 115 | shape: const CircleBorder(), 116 | elevation: 5.0, 117 | child: Center( 118 | child: AnimatedSwitcher( 119 | duration: const Duration(milliseconds: 500), 120 | transitionBuilder: 121 | (Widget child, Animation animation) { 122 | return ScaleTransition( 123 | child: child, scale: animation); 124 | }, 125 | child: Text( 126 | '$_value', 127 | key: ValueKey(_value), 128 | style: TextStyle( 129 | color: Color(0xFF6D72FF), fontSize: 56.0), 130 | ), 131 | ), 132 | ), 133 | ), 134 | ), 135 | ), 136 | ], 137 | ), 138 | ), 139 | ), 140 | ); 141 | } 142 | 143 | 144 | double offsetFromGlobalPos(Offset globalPosition) { 145 | RenderBox box = context.findRenderObject() as RenderBox; 146 | Offset local = box.globalToLocal(globalPosition); 147 | _startAnimationPosX = ((local.dx * 0.75) / box.size.width) - 0.4; 148 | _startAnimationPosY = ((local.dy * 0.75) / box.size.height) - 0.4; 149 | if (widget.direction == Axis.horizontal) { 150 | return ((local.dx * 0.75) / box.size.width) - 0.4; 151 | } else { 152 | return ((local.dy * 0.75) / box.size.height) - 0.4; 153 | } 154 | } 155 | 156 | 157 | void _onPanStart(DragStartDetails details) { 158 | _controller.stop(); 159 | _controller.value = offsetFromGlobalPos(details.globalPosition); 160 | } 161 | 162 | void _onPanUpdate(DragUpdateDetails details) { 163 | _controller.value = offsetFromGlobalPos(details.globalPosition); 164 | } 165 | 166 | 167 | void _onPanEnd(DragEndDetails details) { 168 | _controller.stop(); 169 | bool isHor = widget.direction == Axis.horizontal; 170 | bool changed = false; 171 | if (_controller.value <= -0.20) { 172 | setState(() => isHor ? _value-- : _value++); 173 | changed = true; 174 | } else if (_controller.value >= 0.20) { 175 | setState(() => isHor ? _value++ : _value--); 176 | changed = true; 177 | } 178 | if (widget.withSpring) { 179 | final SpringDescription _kDefaultSpring = 180 | new SpringDescription.withDampingRatio( 181 | mass: 0.9, 182 | stiffness: 250.0, 183 | ratio: 0.6, 184 | ); 185 | if (widget.direction == Axis.horizontal) { 186 | _controller.animateWith( 187 | SpringSimulation(_kDefaultSpring, _startAnimationPosX, 0.0, 0.0)); 188 | } else { 189 | _controller.animateWith( 190 | SpringSimulation(_kDefaultSpring, _startAnimationPosY, 0.0, 0.0)); 191 | } 192 | } else { 193 | _controller.animateTo(0.0, 194 | curve: Curves.bounceOut, duration: Duration(milliseconds: 500)); 195 | } 196 | 197 | if (changed && widget.onChanged != null) { 198 | widget.onChanged(_value); 199 | } 200 | } 201 | } 202 | 203 | 204 | // != carbon.sh 205 | -------------------------------------------------------------------------------- /lib/stepper_touch.dart: -------------------------------------------------------------------------------- 1 | library stepper_touch; 2 | export 'src/stepper.dart'; 3 | 4 | var aquaticNames = steps 5 | .where((steps) => steps.isAquatic) 6 | .map((steps) => steps.name); 7 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://www.dartlang.org/tools/pub/glossary#lockfile 3 | packages: 4 | analyzer: 5 | dependency: transitive 6 | description: 7 | name: analyzer 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "0.32.4" 11 | args: 12 | dependency: transitive 13 | description: 14 | name: args 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "1.5.0" 18 | async: 19 | dependency: transitive 20 | description: 21 | name: async 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "2.0.8" 25 | boolean_selector: 26 | dependency: transitive 27 | description: 28 | name: boolean_selector 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.0.4" 32 | charcode: 33 | dependency: transitive 34 | description: 35 | name: charcode 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.1.2" 39 | collection: 40 | dependency: transitive 41 | description: 42 | name: collection 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.14.11" 46 | convert: 47 | dependency: transitive 48 | description: 49 | name: convert 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "2.0.2" 53 | crypto: 54 | dependency: transitive 55 | description: 56 | name: crypto 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "2.0.6" 60 | csslib: 61 | dependency: transitive 62 | description: 63 | name: csslib 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "0.14.5" 67 | flutter: 68 | dependency: "direct main" 69 | description: flutter 70 | source: sdk 71 | version: "0.0.0" 72 | flutter_test: 73 | dependency: "direct dev" 74 | description: flutter 75 | source: sdk 76 | version: "0.0.0" 77 | front_end: 78 | dependency: transitive 79 | description: 80 | name: front_end 81 | url: "https://pub.dartlang.org" 82 | source: hosted 83 | version: "0.1.4" 84 | glob: 85 | dependency: transitive 86 | description: 87 | name: glob 88 | url: "https://pub.dartlang.org" 89 | source: hosted 90 | version: "1.1.7" 91 | html: 92 | dependency: transitive 93 | description: 94 | name: html 95 | url: "https://pub.dartlang.org" 96 | source: hosted 97 | version: "0.13.3+3" 98 | http: 99 | dependency: transitive 100 | description: 101 | name: http 102 | url: "https://pub.dartlang.org" 103 | source: hosted 104 | version: "0.11.3+17" 105 | http_multi_server: 106 | dependency: transitive 107 | description: 108 | name: http_multi_server 109 | url: "https://pub.dartlang.org" 110 | source: hosted 111 | version: "2.0.5" 112 | http_parser: 113 | dependency: transitive 114 | description: 115 | name: http_parser 116 | url: "https://pub.dartlang.org" 117 | source: hosted 118 | version: "3.1.3" 119 | io: 120 | dependency: transitive 121 | description: 122 | name: io 123 | url: "https://pub.dartlang.org" 124 | source: hosted 125 | version: "0.3.3" 126 | js: 127 | dependency: transitive 128 | description: 129 | name: js 130 | url: "https://pub.dartlang.org" 131 | source: hosted 132 | version: "0.6.1+1" 133 | json_rpc_2: 134 | dependency: transitive 135 | description: 136 | name: json_rpc_2 137 | url: "https://pub.dartlang.org" 138 | source: hosted 139 | version: "2.0.9" 140 | kernel: 141 | dependency: transitive 142 | description: 143 | name: kernel 144 | url: "https://pub.dartlang.org" 145 | source: hosted 146 | version: "0.3.4" 147 | logging: 148 | dependency: transitive 149 | description: 150 | name: logging 151 | url: "https://pub.dartlang.org" 152 | source: hosted 153 | version: "0.11.3+2" 154 | matcher: 155 | dependency: transitive 156 | description: 157 | name: matcher 158 | url: "https://pub.dartlang.org" 159 | source: hosted 160 | version: "0.12.3+1" 161 | meta: 162 | dependency: transitive 163 | description: 164 | name: meta 165 | url: "https://pub.dartlang.org" 166 | source: hosted 167 | version: "1.1.6" 168 | mime: 169 | dependency: transitive 170 | description: 171 | name: mime 172 | url: "https://pub.dartlang.org" 173 | source: hosted 174 | version: "0.9.6+2" 175 | multi_server_socket: 176 | dependency: transitive 177 | description: 178 | name: multi_server_socket 179 | url: "https://pub.dartlang.org" 180 | source: hosted 181 | version: "1.0.2" 182 | node_preamble: 183 | dependency: transitive 184 | description: 185 | name: node_preamble 186 | url: "https://pub.dartlang.org" 187 | source: hosted 188 | version: "1.4.4" 189 | package_config: 190 | dependency: transitive 191 | description: 192 | name: package_config 193 | url: "https://pub.dartlang.org" 194 | source: hosted 195 | version: "1.0.5" 196 | package_resolver: 197 | dependency: transitive 198 | description: 199 | name: package_resolver 200 | url: "https://pub.dartlang.org" 201 | source: hosted 202 | version: "1.0.4" 203 | path: 204 | dependency: transitive 205 | description: 206 | name: path 207 | url: "https://pub.dartlang.org" 208 | source: hosted 209 | version: "1.6.2" 210 | plugin: 211 | dependency: transitive 212 | description: 213 | name: plugin 214 | url: "https://pub.dartlang.org" 215 | source: hosted 216 | version: "0.2.0+3" 217 | pool: 218 | dependency: transitive 219 | description: 220 | name: pool 221 | url: "https://pub.dartlang.org" 222 | source: hosted 223 | version: "1.3.6" 224 | pub_semver: 225 | dependency: transitive 226 | description: 227 | name: pub_semver 228 | url: "https://pub.dartlang.org" 229 | source: hosted 230 | version: "1.4.2" 231 | quiver: 232 | dependency: transitive 233 | description: 234 | name: quiver 235 | url: "https://pub.dartlang.org" 236 | source: hosted 237 | version: "2.0.0+1" 238 | shelf: 239 | dependency: transitive 240 | description: 241 | name: shelf 242 | url: "https://pub.dartlang.org" 243 | source: hosted 244 | version: "0.7.3+3" 245 | shelf_packages_handler: 246 | dependency: transitive 247 | description: 248 | name: shelf_packages_handler 249 | url: "https://pub.dartlang.org" 250 | source: hosted 251 | version: "1.0.4" 252 | shelf_static: 253 | dependency: transitive 254 | description: 255 | name: shelf_static 256 | url: "https://pub.dartlang.org" 257 | source: hosted 258 | version: "0.2.8" 259 | shelf_web_socket: 260 | dependency: transitive 261 | description: 262 | name: shelf_web_socket 263 | url: "https://pub.dartlang.org" 264 | source: hosted 265 | version: "0.2.2+4" 266 | sky_engine: 267 | dependency: transitive 268 | description: flutter 269 | source: sdk 270 | version: "0.0.99" 271 | source_map_stack_trace: 272 | dependency: transitive 273 | description: 274 | name: source_map_stack_trace 275 | url: "https://pub.dartlang.org" 276 | source: hosted 277 | version: "1.1.5" 278 | source_maps: 279 | dependency: transitive 280 | description: 281 | name: source_maps 282 | url: "https://pub.dartlang.org" 283 | source: hosted 284 | version: "0.10.7" 285 | source_span: 286 | dependency: transitive 287 | description: 288 | name: source_span 289 | url: "https://pub.dartlang.org" 290 | source: hosted 291 | version: "1.4.1" 292 | stack_trace: 293 | dependency: transitive 294 | description: 295 | name: stack_trace 296 | url: "https://pub.dartlang.org" 297 | source: hosted 298 | version: "1.9.3" 299 | stream_channel: 300 | dependency: transitive 301 | description: 302 | name: stream_channel 303 | url: "https://pub.dartlang.org" 304 | source: hosted 305 | version: "1.6.8" 306 | string_scanner: 307 | dependency: transitive 308 | description: 309 | name: string_scanner 310 | url: "https://pub.dartlang.org" 311 | source: hosted 312 | version: "1.0.4" 313 | term_glyph: 314 | dependency: transitive 315 | description: 316 | name: term_glyph 317 | url: "https://pub.dartlang.org" 318 | source: hosted 319 | version: "1.0.1" 320 | test: 321 | dependency: transitive 322 | description: 323 | name: test 324 | url: "https://pub.dartlang.org" 325 | source: hosted 326 | version: "1.3.0" 327 | typed_data: 328 | dependency: transitive 329 | description: 330 | name: typed_data 331 | url: "https://pub.dartlang.org" 332 | source: hosted 333 | version: "1.1.6" 334 | utf: 335 | dependency: transitive 336 | description: 337 | name: utf 338 | url: "https://pub.dartlang.org" 339 | source: hosted 340 | version: "0.9.0+5" 341 | vector_math: 342 | dependency: transitive 343 | description: 344 | name: vector_math 345 | url: "https://pub.dartlang.org" 346 | source: hosted 347 | version: "2.0.8" 348 | vm_service_client: 349 | dependency: transitive 350 | description: 351 | name: vm_service_client 352 | url: "https://pub.dartlang.org" 353 | source: hosted 354 | version: "0.2.6" 355 | watcher: 356 | dependency: transitive 357 | description: 358 | name: watcher 359 | url: "https://pub.dartlang.org" 360 | source: hosted 361 | version: "0.9.7+10" 362 | web_socket_channel: 363 | dependency: transitive 364 | description: 365 | name: web_socket_channel 366 | url: "https://pub.dartlang.org" 367 | source: hosted 368 | version: "1.0.9" 369 | yaml: 370 | dependency: transitive 371 | description: 372 | name: yaml 373 | url: "https://pub.dartlang.org" 374 | source: hosted 375 | version: "2.1.15" 376 | sdks: 377 | dart: ">=2.0.0-dev.68.0 <3.0.0" 378 | 379 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: Counter App 2 | description: a flutter stepper widget with nice aniamtion 3 | version: 0.0.1 4 | author: Raj Chowdhury 5 | homepage: https://github.com/Rajchowdhury420 6 | environment: 7 | sdk: ">=2.0.0-dev.68.0 <3.0.0" 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | 13 | dev_dependencies: 14 | flutter_test: 15 | sdk: flutter 16 | 17 | flutter: 18 | 19 | // add your own requirement if u want 20 | --------------------------------------------------------------------------------