fluttercandies / flutter_tilt

👀 Easily apply tilt parallax hover effects for Flutter, which supports tilt, light, shadow effects, and gyroscope sensors | 为 Flutter 轻松创建倾斜视差悬停效果,支持倾斜、光照、阴影效果和陀螺仪传感器
https://pub.dev/packages/flutter_tilt
MIT License
145 stars 6 forks source link

[Feature request] Need to set tilt programmatically. #8

Closed potikorn closed 7 months ago

potikorn commented 8 months ago

Platforms

Android, iOS

Description

Hi, Thank you for your awesome plugin. That's amazing animation. However, I need to know Can I set tilt by not from user interaction? but from code to animate widget.

Thank in advanced.

Why

In case need to animate ifself for interval duration to tilt widget over and over again. Also, Can we add depth to make it look like it has more dimension?

AmosHuKe commented 8 months ago

Thanks for your feature suggestions! 😀

Now that a new version has been released. It provides the TiltStreamController.

# pubspec.yaml

dependencies:
  flutter_tilt: ^2.4.0

Here is an example for you.

TiltStreamController

You can use it through animation or otherwise.

Code

Click to view code ``` dart import 'dart:async'; import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:flutter_tilt/flutter_tilt.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: const Scaffold(body: TiltStreamControllerDemo()), ); } } class TiltStreamControllerDemo extends StatefulWidget { const TiltStreamControllerDemo({super.key}); @override State createState() => _TiltStreamControllerDemoState(); } class _TiltStreamControllerDemoState extends State with TickerProviderStateMixin { final MaterialStateProperty thumbIcon = MaterialStateProperty.resolveWith( (Set states) { return states.contains(MaterialState.selected) ? const Icon(Icons.link) : const Icon(Icons.link_off); }, ); late StreamController tiltStreamController; bool controllerBind = true; AnimationController? animationSelected; /// AnimationController around late AnimationController aroundAnimationController; /// AnimationController leftTop -> rightBottom late AnimationController ltrbAnimationController; /// AnimationController rightTop -> leftBottom late AnimationController rtlbAnimationController; @override void initState() { super.initState(); tiltStreamController = StreamController.broadcast(); aroundAnimation(); ltrbAnimation(); rtlbAnimation(); animationSelected = aroundAnimationController; animationSelected?.repeat(reverse: false); } @override void dispose() { tiltStreamController.close(); aroundAnimationController.dispose(); ltrbAnimationController.dispose(); rtlbAnimationController.dispose(); super.dispose(); } void stopAllAnimation() { aroundAnimationController.stop(); ltrbAnimationController.stop(); rtlbAnimationController.stop(); } /// Animation around void aroundAnimation() { aroundAnimationController = AnimationController( lowerBound: 0.0, upperBound: 1.0, duration: const Duration(milliseconds: 3000), vsync: this, ); aroundAnimationController.addListener(() { final double radian = aroundAnimationController.value * 360 * math.pi / 180; const double r = 75; // P = (cosθ, sinθ) final double x = math.cos(radian) * r + 150; final double y = math.sin(radian) * r + 75; tiltStreamController.add(TiltStreamModel(position: Offset(x, y))); }); } /// Animation leftTop -> rightBottom void ltrbAnimation() { ltrbAnimationController = AnimationController( lowerBound: 0.0, upperBound: 1.0, duration: const Duration(milliseconds: 3000), vsync: this, ); ltrbAnimationController.addListener(() { final double x = ltrbAnimationController.value * 300; final double y = ltrbAnimationController.value * 150; tiltStreamController.add(TiltStreamModel(position: Offset(x, y))); }); } /// Animation rightTop -> leftBottom void rtlbAnimation() { rtlbAnimationController = AnimationController( lowerBound: 0.0, upperBound: 1.0, duration: const Duration(milliseconds: 3000), vsync: this, ); rtlbAnimationController.addListener(() { final double x = (1 - rtlbAnimationController.value) * 300; final double y = (rtlbAnimationController.value) * 150; tiltStreamController.add(TiltStreamModel(position: Offset(x, y))); }); } @override Widget build(BuildContext context) { return Column( children: [ /// Tilt here Tilt( tiltStreamController: controllerBind ? tiltStreamController : null, borderRadius: BorderRadius.circular(30), tiltConfig: const TiltConfig(enableGestureSensors: false), childLayout: const ChildLayout( outer: [ Positioned( child: TiltParallax( size: Offset(10, 10), child: Text( 'Flutter Tilt 1 ✨', style: TextStyle( fontSize: 14, color: Colors.white, ), ), ), ), ], ), child: Container( width: 300, height: 150, decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topRight, end: Alignment.bottomLeft, colors: [Color(0xFF80d0c7), Color(0xFF13547a)], ), ), ), ), /// bind Padding( padding: const EdgeInsets.all(20), child: Switch( thumbIcon: thumbIcon, value: controllerBind, onChanged: (value) { setState(() { controllerBind = value; }); }, ), ), /// Tilt here Tilt( tiltStreamController: controllerBind ? tiltStreamController : null, borderRadius: BorderRadius.circular(30), tiltConfig: const TiltConfig(enableGestureSensors: false), childLayout: const ChildLayout( outer: [ Positioned( child: TiltParallax( size: Offset(10, 10), child: Text( 'Flutter Tilt 2 ✨', style: TextStyle( fontSize: 14, color: Colors.white, ), ), ), ), ], ), child: Container( width: 300, height: 150, decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Color(0xFF8989ba), Color(0xFFa7a6cb)], ), ), ), ), /// Tools /// Animation const Text( "Animation", style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 12), Wrap( spacing: 12, runSpacing: 12, children: [ FilterChip( label: const Text('none'), selected: animationSelected == null, onSelected: (bool value) { setState(() { if (value) { stopAllAnimation(); animationSelected = null; } }); }, ), FilterChip( label: const Text('around'), selected: animationSelected == aroundAnimationController, onSelected: (bool value) { setState(() { if (value) { animationSelected = aroundAnimationController ..repeat(reverse: false); } else { stopAllAnimation(); } }); }, ), FilterChip( label: const Text('leftTop -> rightBottom'), selected: animationSelected == ltrbAnimationController, onSelected: (bool value) { setState(() { if (value) { animationSelected = ltrbAnimationController ..repeat(reverse: true); } else { stopAllAnimation(); } }); }, ), FilterChip( label: const Text('rightTop -> leftBottom'), selected: animationSelected == rtlbAnimationController, onSelected: (bool value) { setState(() { if (value) { animationSelected = rtlbAnimationController ..repeat(reverse: true); } else { stopAllAnimation(); } }); }, ), ], ), ], ); } } ```

Video

https://github.com/fluttercandies/flutter_tilt/assets/32262985/72e134ac-d69b-4fc5-8325-f7f8b054b268

About Depth

The current package mainly applies the relevant effects in 2 dimensions and does not consider 3 dimensions for the time being.

For example, transforming from a card to a box.

potikorn commented 7 months ago

@AmosHuKe That's awesome. Thanks for your effort. 😄👍