// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:flutter/material.dart'; /// Flutter code sample for [CarouselView]. void main() => runApp(const CarouselExampleApp()); class CarouselExampleApp extends StatelessWidget { const CarouselExampleApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: Scaffold( appBar: AppBar( leading: const Icon(Icons.cast), title: const Text('Flutter TV'), actions: const [ Padding( padding: EdgeInsetsDirectional.only(end: 16.0), child: CircleAvatar(child: Icon(Icons.account_circle)), ), ], ), body: const CarouselExample(), ), ); } } class CarouselExample extends StatefulWidget { const CarouselExample({super.key}); @override State createState() => _CarouselExampleState(); } class _CarouselExampleState extends State { final CarouselController controller = CarouselController(initialItem: 1); @override void dispose() { controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final double height = MediaQuery.sizeOf(context).height; return ListView( children: [ ConstrainedBox( constraints: BoxConstraints(maxHeight: height / 2), child: CarouselView.weighted( controller: controller, itemSnapping: true, flexWeights: const [1, 7, 1], children: ImageInfo.values.map((ImageInfo image) { return HeroLayoutCard(imageInfo: image); }).toList(), ), ), const SizedBox(height: 20), const Padding( padding: EdgeInsetsDirectional.only(top: 8.0, start: 8.0), child: Text('Multi-browse layout'), ), ConstrainedBox( constraints: const BoxConstraints(maxHeight: 50), child: CarouselView.weighted( flexWeights: const [1, 2, 3, 2, 1], consumeMaxWeight: false, children: List.generate(20, (int index) { return ColoredBox( color: Colors.primaries[index % Colors.primaries.length].withOpacity(0.8), child: const SizedBox.expand(), ); }), ), ), const SizedBox(height: 20), ConstrainedBox( constraints: const BoxConstraints(maxHeight: 200), child: CarouselView.weighted( flexWeights: const [3, 3, 3, 2, 1], consumeMaxWeight: false, children: CardInfo.values.map((CardInfo info) { return ColoredBox( color: info.backgroundColor, child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(info.icon, color: info.color, size: 32.0), Text( info.label, style: const TextStyle(fontWeight: FontWeight.bold), overflow: TextOverflow.clip, softWrap: false, ), ], ), ), ); }).toList(), ), ), const SizedBox(height: 20), const Padding( padding: EdgeInsetsDirectional.only(top: 8.0, start: 8.0), child: Text('Uncontained layout'), ), ConstrainedBox( constraints: const BoxConstraints(maxHeight: 200), child: CarouselView( itemExtent: 330, shrinkExtent: 200, children: List.generate(20, (int index) { return UncontainedLayoutCard(index: index, label: 'Show $index'); }), ), ), ], ); } } class HeroLayoutCard extends StatelessWidget { const HeroLayoutCard({super.key, required this.imageInfo}); final ImageInfo imageInfo; @override Widget build(BuildContext context) { final double width = MediaQuery.sizeOf(context).width; return Stack( alignment: AlignmentDirectional.bottomStart, children: [ ClipRect( child: OverflowBox( maxWidth: width * 7 / 8, minWidth: width * 7 / 8, child: Image( fit: BoxFit.cover, image: NetworkImage( 'https://flutter.github.io/assets-for-api-docs/assets/material/${imageInfo.url}', ), ), ), ), Padding( padding: const EdgeInsets.all(18.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( imageInfo.title, overflow: TextOverflow.clip, softWrap: false, style: Theme.of(context).textTheme.headlineLarge?.copyWith(color: Colors.white), ), const SizedBox(height: 10), Text( imageInfo.subtitle, overflow: TextOverflow.clip, softWrap: false, style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: Colors.white), ), ], ), ), ], ); } } class UncontainedLayoutCard extends StatelessWidget { const UncontainedLayoutCard({super.key, required this.index, required this.label}); final int index; final String label; @override Widget build(BuildContext context) { return ColoredBox( color: Colors.primaries[index % Colors.primaries.length].withOpacity(0.5), child: Center( child: Text( label, style: const TextStyle(color: Colors.white, fontSize: 20), overflow: TextOverflow.clip, softWrap: false, ), ), ); } } enum CardInfo { camera('Cameras', Icons.video_call, Color(0xff2354C7), Color(0xffECEFFD)), lighting('Lighting', Icons.lightbulb, Color(0xff806C2A), Color(0xffFAEEDF)), climate('Climate', Icons.thermostat, Color(0xffA44D2A), Color(0xffFAEDE7)), wifi('Wifi', Icons.wifi, Color(0xff417345), Color(0xffE5F4E0)), media('Media', Icons.library_music, Color(0xff2556C8), Color(0xffECEFFD)), security('Security', Icons.crisis_alert, Color(0xff794C01), Color(0xffFAEEDF)), safety('Safety', Icons.medical_services, Color(0xff2251C5), Color(0xffECEFFD)), more('', Icons.add, Color(0xff201D1C), Color(0xffE3DFD8)); const CardInfo(this.label, this.icon, this.color, this.backgroundColor); final String label; final IconData icon; final Color color; final Color backgroundColor; } enum ImageInfo { image0('The Flow', 'Sponsored | Season 1 Now Streaming', 'content_based_color_scheme_1.png'), image1( 'Through the Pane', 'Sponsored | Season 1 Now Streaming', 'content_based_color_scheme_2.png', ), image2('Iridescence', 'Sponsored | Season 1 Now Streaming', 'content_based_color_scheme_3.png'), image3('Sea Change', 'Sponsored | Season 1 Now Streaming', 'content_based_color_scheme_4.png'), image4('Blue Symphony', 'Sponsored | Season 1 Now Streaming', 'content_based_color_scheme_5.png'), image5('When It Rains', 'Sponsored | Season 1 Now Streaming', 'content_based_color_scheme_6.png'); const ImageInfo(this.title, this.subtitle, this.url); final String title; final String subtitle; final String url; }