Reputation: 1125
How to create similar effect using Flutter?
Upvotes: 3
Views: 4531
Reputation:
Well, I use github for some help with my CSS animations. I also am using it for my website's loading screen (this is just an example, ok?):
<!DOCTYPE html>
<html lang="en">
<style>
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
height: 100vh;
display: flex;
background: #ffffff;
}
.circular-slider {
width: 250px;
height: 150px;
margin: auto;
perspective: 1000px;
}
.slider-content {
width: 100%;
height: 100%;
position: relative;
transform-style: preserve-3d;
animation: rotate 20s infinite;
}
.slider-item {
width: 220px;
height: 120px;
position: absolute;
background: rgba(255,255,255,.5);
-webkit-box-reflect: below 15px
-webkit-gradient(linear, left top, left bottom, from(transparent),
color-stop(0.5, transparent), to(rgba(255,255,255,.5)));
}
.slider-item img {
width: 100%;
height: 100%;
}
.slider-item:nth-child(1) { transform: rotateY(0deg) translateZ(216px); }
.slider-item:nth-child(2) { transform: rotateY(60deg) translateZ(216px); }
.slider-item:nth-child(3) { transform: rotateY(120deg) translateZ(216px); }
.slider-item:nth-child(4) { transform: rotateY(180deg) translateZ(216px); }
.slider-item:nth-child(5) { transform: rotateY(240deg) translateZ(216px); }
.slider-item:nth-child(6) { transform: rotateY(300deg) translateZ(216px); }
@keyframes rotate {
0% { transform: translateZ(-216px) rotateY(0deg); }
16.67% { transform: translateZ(-216px) rotateY(-60deg); }
33.33% { transform: translateZ(-216px) rotateY(-120deg); }
50% { transform: translateZ(-216px) rotateY(-180deg); }
66.67% { transform: translateZ(-216px) rotateY(-240deg); }
83.34% { transform: translateZ(-216px) rotateY(-300deg); }
100% { transform: translateZ(-216px) rotateY(-360deg); }
}
</style>
<head>
<meta charset="UTF-8">
<title>Testing CSS capabilities</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="circular-slider">
<div class="slider-content">
<div class="slider-item">
<img src="https://peakvisor.com/img/news/Utah-mountains.jpg">
</div>
<div class="slider-item">
<img src="https://passionpassport-1.s3.amazonaws.com/wp-content/uploads/2017/07/10002009/James-Udall-Utah-Notch-Lake-Uintas-Sunset.jpg">
</div>
<div class="slider-item">
<img src="https://webneel.com/wallpaper/sites/default/files/images/08-2018/3-nature-wallpaper-mountain.jpg">
</div>
<div class="slider-item">
<img src="https://www.teahub.io/photos/full/186-1868092_1080p-galaxy-wallpaper-hd.jpg">
</div>
<div class="slider-item">
<img src="https://www.teahub.io/photos/full/13-137126_1920x1152-free-download-nature-hd-wallpapers-nature-nature.jpg">
</div>
<div class="slider-item">
<img src="https://thumbs.gfycat.com/PlayfulSoreGroundbeetle-max-1mb.gif">
</div>
</div>
</div>
</body>
</html>
Code from https://github.com/marina-ferreira/circular-slider
Upvotes: 3
Reputation: 1243
I made a quick demo for you, tweak the Matrix4 params. (blur/depth of field doesn't work well on browser).
import 'dart:math';
import 'dart:ui';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
darkTheme:
ThemeData(platform: TargetPlatform.iOS, brightness: Brightness.dark),
home: RotationScene(),
);
}
}
class RotationScene extends StatefulWidget {
@override
_RotationSceneState createState() => _RotationSceneState();
}
class _RotationSceneState extends State<RotationScene> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'carrousel',
style: TextStyle(fontSize: 13),
),
centerTitle: false,
elevation: 12,
backgroundColor: Colors.transparent,
),
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Color(0xff74ABE4), Color(0xffA892ED)],
stops: [0, 1],
)),
child: Center(child: MyScener()),
),
);
}
}
class CardData {
Color color;
double x, y, z, angle;
final int idx;
double alpha = 0;
Color get lightColor {
var val = HSVColor.fromColor(color);
return val.withSaturation(.5).withValue(.8).toColor();
}
CardData(this.idx) {
color = Colors.primaries[idx % Colors.primaries.length];
x = 0;
y = 0;
z = 0;
}
}
class MyScener extends StatefulWidget {
@override
_MyScenerState createState() => _MyScenerState();
}
class _MyScenerState extends State<MyScener>
with SingleTickerProviderStateMixin {
AnimationController _animationController;
List<CardData> cardData = [];
int numItems = 9;
double radio = 200.0;
double radioStep;
int centerIdx = 1;
@override
void initState() {
cardData = List.generate(numItems, (index) => CardData(index)).toList();
radioStep = (pi * 2) / numItems;
_animationController =
AnimationController(vsync: this, duration: Duration(seconds: 1));
_animationController.addListener(() => setState(() {}));
_animationController.addStatusListener((status) async {
if (status == AnimationStatus.completed) {
_animationController.value = 0;
_animationController.animateTo(1);
++centerIdx;
}
});
_animationController.forward();
super.initState();
}
@override
Widget build(BuildContext context) {
var ratio = _animationController.value;
double animValue = centerIdx + ratio;
// process positions.
for (var i = 0; i < cardData.length; ++i) {
var c = cardData[i];
double ang = c.idx * radioStep + animValue;
c.angle = ang + pi / 2;
c.x = cos(ang) * radio;
// c.y = sin(ang) * 10;
c.z = sin(ang) * radio;
}
// sort in Z axis.
cardData.sort((a, b) => a.z.compareTo(b.z));
var list = cardData.map((vo) {
var c = addCard(vo);
var mt2 = Matrix4.identity();
mt2.setEntry(3, 2, 0.001);
mt2.translate(vo.x, vo.y, -vo.z);
mt2.rotateY(vo.angle + pi);
c = Transform(
alignment: Alignment.center,
origin: Offset(0.0, -0.0),
transform: mt2,
child: c,
);
// depth of field... doesnt work on web.
// var blur = .4 + ((1 - vo.z / radio) / 2) * 2;
// c = BackdropFilter(
// filter: ImageFilter.blur(sigmaX: blur, sigmaY: blur),
// child: c,
// );
return c;
}).toList();
return Container(
alignment: Alignment.center,
child: Stack(
alignment: Alignment.center,
children: list,
),
);
}
Widget addCard(CardData vo) {
var alpha = ((1 - vo.z / radio) / 2) * .6;
Widget c;
c = Container(
margin: EdgeInsets.all(12),
width: 120,
height: 80,
alignment: Alignment.center,
foregroundDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.black.withOpacity(alpha),
),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
stops: [0.1, .9],
colors: [vo.lightColor, vo.color],
),
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(.2 + alpha * .2),
spreadRadius: 1,
blurRadius: 12,
offset: Offset(0, 2))
],
),
child: Text('ITEM ${vo.idx}'),
);
return c;
}
}
Upvotes: 13