Skip to content

Instantly share code, notes, and snippets.

@hectorAguero
Last active September 5, 2025 15:52
Show Gist options
  • Select an option

  • Save hectorAguero/bea2c87897f3554e0fc4304d9d5a90c8 to your computer and use it in GitHub Desktop.

Select an option

Save hectorAguero/bea2c87897f3554e0fc4304d9d5a90c8 to your computer and use it in GitHub Desktop.
PageView.builder(Carousel) with Scrollable childs wrapped in ClipRRect
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: PageViewScreen(),
);
}
}
class PageViewScreen extends StatefulWidget {
const PageViewScreen({super.key});
@override
State<PageViewScreen> createState() => _PageViewScreenState();
}
class _PageViewScreenState extends State<PageViewScreen> {
late final PageController _pageController;
final List<Map<String, dynamic>> _pageData = [
{
'color': Colors.red.shade400,
'title': 'Explore New Horizons',
'description':
'Welcome to the first page! This interface demonstrates how to create a dynamic and interactive user experience with custom UI elements.',
},
{
'color': Colors.blue.shade400,
'title': 'Seamless Navigation',
'description':
'Effortlessly swipe between pages. The adjacent cards are partially visible, providing a smooth and intuitive browsing experience.',
},
{
'color': Colors.green.shade400,
'title': 'Responsive Content',
'description':
'Each card is designed to hold rich content. If the content exceeds the card\'s fixed height, it automatically becomes scrollable.',
},
{
'color': Colors.purple.shade400,
'title': 'Elegant Design',
'description':
'Enjoy the clean aesthetic with rounded corners and a clear information hierarchy. Guiding you towards your desired outcome with ease.',
},
{
'color': Colors.orange.shade400,
'title': 'Fully Interactive',
'description':
'This is the fifth page. All UI components are functional and update the data model in real-time. No "submit" buttons needed.',
},
];
@override
void initState() {
super.initState();
_pageController = PageController(viewportFraction: 0.8);
}
@override
void dispose() {
_pageController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Custom Card Carousel'),
backgroundColor: Colors.deepPurple,
foregroundColor: Colors.white,
),
body: Center(
child: SizedBox(
// Constrain the overall height of the PageView to allow it to be centered
// and provide a specific vertical space for the cards.
height:
MediaQuery.of(context).size.height * 0.75, // 75% of screen height
child: PageView.builder(
controller: _pageController,
itemCount: _pageData.length,
itemBuilder: (BuildContext context, int index) {
final page = _pageData[index];
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10.0,
vertical: 20.0,
),
child: ClipRRect(
borderRadius: BorderRadius.circular(
20.0,
), // Rounded corners for the card
child: SizedBox(
height: double
.infinity, // Take the full height from the parent SizedBox
child: SingleChildScrollView(
child: Card(
elevation: 8.0,
color: page['color'] as Color,
margin: EdgeInsets
.zero, // Card margin handled by Padding in PageView.builder
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
20.0,
), // Match ClipRRect
),
child: Column(
mainAxisSize: MainAxisSize.min, // Wrap content height
children: <Widget>[
Image.network(
'https://picsum.photos/200',
width: double.infinity,
height: 150,
fit: BoxFit.cover,
loadingBuilder:
(context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Placeholder(
fallbackHeight: 150,
fallbackWidth: double.infinity,
);
},
),
const SizedBox(height: 15),
Text(
page['title'] as String,
style: const TextStyle(
fontSize: 26,
color: Colors.white,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 15),
Text(
page['description'] as String,
style: const TextStyle(
fontSize: 16,
color: Colors.white70,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 25),
// Simulate more content to demonstrate scrolling within the fixed height
for (int i = 0; i < 10; i++)
Padding(
padding: const EdgeInsets.only(
bottom: 8.0,
right: 24.0,
left: 24.0,
),
child: Text(
'Detail point ${i + 1}: This content is designed to potentially overflow the card\'s view, making the SingleChildScrollView active and functional.',
style: const TextStyle(
fontSize: 14,
color: Colors.white54,
),
textAlign: TextAlign.left,
),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () {
// In a real app, this would trigger an action for the current page
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Action button tapped for "${page['title']}"',
),
duration: const Duration(seconds: 1),
),
);
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
foregroundColor: page['color'] as Color,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
padding: const EdgeInsets.symmetric(
horizontal: 30,
vertical: 12,
),
),
child: const Text(
'Learn More',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
SizedBox(height:24)
],
),
),
),
),
),
);
},
),
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment