I have a stack of positioned containers like this:
I would like to scroll them horizontally and bring that container to the front accordingly namely bring blue one to the front when scrolled right and yellow one when scrolled left.
Something like this but a scroll instead of clicks:
I tried using SingleChildScrollView with horizontal scroll but unsurprisingly it didn't work. The code I tried was:
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Stack(
clipBehavior: Clip.none,
children: [
Container(),
Positioned(
top: 145.h,
left: 100.w,
height: 300.h,
width: 250.w,
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
elevation: 3.h,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(5.r), //// <-- Radius
),
),
child: Text("pp"),
),
),
Positioned(
top: 145.h,
left: 20.w,
height: 300.h,
width: 250.w,
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.yellow,
elevation: 3.h,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(5.r), //// <-- Radius
),
),
child: Text("Demo 3"),
),
),
Positioned(
top: 145.h,
left: 60.w,
height: 300.h,
width: 250.w,
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
elevation: 3.h,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(5.r), //// <-- Radius
),
),
child: Text(
"Demo 2",
style: TextStyle(
fontSize: 20.sp,
fontWeight: FontWeight.w500,
),
),
),
),
Positioned(
top: 145.h,
left: 60.w,
height: 300.h,
width: 250.w,
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
elevation: 3.h,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(5.r), //// <-- Radius
),
),
child: Text(
"Demo",
style: TextStyle(
fontSize: 20.sp,
fontWeight: FontWeight.w500,
),
),
),
),
],
),
One solution I do know is to use InkWell and use onTap/ElevatedButton onPress to tweak the positioning and bring the corresponding container to the front but the user experience won't be as good as a horizontal scroll.
I also tried using ListWheelScrollView with RotatedBox to simulate horizontal scrolling but it was not good enough.
Any help on this would be greatly appreciated!
Well I found a solution with PageView.builder not with Stack
, which is pretty close to what you are trying to make,
home page where we call our carousel:
import 'dart:math' as math;
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
List items = List.generate(
20,
(index) => Color((math.Random().nextDouble() * 0xFFFFFF).toInt())
.withOpacity(1.0)); // list for test
late PageController _pageController; // controller of pageview
@override
void initState() {
_pageController = PageController(initialPage: 0, viewportFraction: 0.8);
super.initState();
}
@override
void dispose() {
_pageController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return ScrollConfiguration(
behavior: CustomScrollBehavior(),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: CardCarousel(pageController: _pageController, items: items),
),
);
}
}
this is Carousel:
class CardCarousel extends StatelessWidget {
final PageController pageController;
final List items;
const CardCarousel(
{super.key, required this.pageController, required this.items});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 400.0,
width: 300,
child: PageView.builder(
controller: pageController,
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
return _cardBuilder(context, index);
},
),
),
],
);
}
_cardBuilder(BuildContext context, int index) {
var item = items[index];
return AnimatedBuilder(
animation: pageController,
builder: (context, child) {
double value = 1;
if (pageController.position.haveDimensions) {
value = (pageController.page! - index);
value = (1 - (value.abs() * 0.25)).clamp(0.0, 1.0);
// you can change these values to change the size
// transformation that i found it
}
return Center(
child: Container(
color: item,
// change animation right here
// the value for transform have got above
height: Curves.easeInOut.transform(value) * 400.0,
child: child,
),
);
},
);
}
}
I hope this was helpful, the result be like: