| // 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 <Widget>[ | |
| Padding( | |
| padding: .directional(end: 16.0), | |
| child: CircleAvatar(child: Icon(Icons.account_circle)), | |
| ), | |
| ], | |
| ), | |
| body: const CarouselExample(), | |
| ), | |
| ); | |
| } | |
| } | |
| class CarouselExample extends StatefulWidget { | |
| const CarouselExample({super.key}); | |
| @override | |
| State<CarouselExample> createState() => _CarouselExampleState(); | |
| } | |
| class _CarouselExampleState extends State<CarouselExample> { | |
| 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: <Widget>[ | |
| ConstrainedBox( | |
| constraints: BoxConstraints(maxHeight: height / 2), | |
| child: CarouselView.weighted( | |
| controller: controller, | |
| itemSnapping: true, | |
| flexWeights: const <int>[1, 7, 1], | |
| children: ImageInfo.values.map((ImageInfo image) { | |
| return HeroLayoutCard(imageInfo: image); | |
| }).toList(), | |
| ), | |
| ), | |
| const SizedBox(height: 20), | |
| const Padding( | |
| padding: .directional(top: 8.0, start: 8.0), | |
| child: Text('Multi-browse layout'), | |
| ), | |
| ConstrainedBox( | |
| constraints: const BoxConstraints(maxHeight: 50), | |
| child: CarouselView.weighted( | |
| flexWeights: const <int>[1, 2, 3, 2, 1], | |
| consumeMaxWeight: false, | |
| children: List<Widget>.generate(20, (int index) { | |
| return ColoredBox( | |
| color: Colors.primaries[index % Colors.primaries.length] | |
| .withValues(alpha: 0.8), | |
| child: const SizedBox.expand(), | |
| ); | |
| }), | |
| ), | |
| ), | |
| const SizedBox(height: 20), | |
| ConstrainedBox( | |
| constraints: const BoxConstraints(maxHeight: 200), | |
| child: CarouselView.weighted( | |
| flexWeights: const <int>[3, 3, 3, 2, 1], | |
| consumeMaxWeight: false, | |
| children: CardInfo.values.map((CardInfo info) { | |
| return ColoredBox( | |
| color: info.backgroundColor, | |
| child: Center( | |
| child: Column( | |
| mainAxisAlignment: .center, | |
| children: <Widget>[ | |
| Icon(info.icon, color: info.color, size: 32.0), | |
| Text( | |
| info.label, | |
| style: const TextStyle(fontWeight: .bold), | |
| overflow: .clip, | |
| softWrap: false, | |
| ), | |
| ], | |
| ), | |
| ), | |
| ); | |
| }).toList(), | |
| ), | |
| ), | |
| const SizedBox(height: 20), | |
| const Padding( | |
| padding: .directional(top: 8.0, start: 8.0), | |
| child: Text('Uncontained layout'), | |
| ), | |
| ConstrainedBox( | |
| constraints: const BoxConstraints(maxHeight: 200), | |
| child: CarouselView( | |
| itemExtent: 330, | |
| shrinkExtent: 200, | |
| children: List<Widget>.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: .bottomStart, | |
| children: <Widget>[ | |
| ClipRect( | |
| child: OverflowBox( | |
| maxWidth: width * 7 / 8, | |
| minWidth: width * 7 / 8, | |
| child: Image( | |
| fit: .cover, | |
| image: NetworkImage( | |
| 'https://flutter.github.io/assets-for-api-docs/assets/material/${imageInfo.url}', | |
| ), | |
| ), | |
| ), | |
| ), | |
| Padding( | |
| padding: const .all(18.0), | |
| child: Column( | |
| crossAxisAlignment: .start, | |
| mainAxisSize: .min, | |
| children: <Widget>[ | |
| Text( | |
| imageInfo.title, | |
| overflow: .clip, | |
| softWrap: false, | |
| style: Theme.of( | |
| context, | |
| ).textTheme.headlineLarge?.copyWith(color: Colors.white), | |
| ), | |
| const SizedBox(height: 10), | |
| Text( | |
| imageInfo.subtitle, | |
| overflow: .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].withValues( | |
| alpha: 0.5, | |
| ), | |
| child: Center( | |
| child: Text( | |
| label, | |
| style: const TextStyle(color: Colors.white, fontSize: 20), | |
| overflow: .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; | |
| } |