1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'package:flutter/material.dart';
6
7/// Flutter code sample for [CarouselView].
8
9void main() => runApp(const CarouselExampleApp());
10
11class CarouselExampleApp extends StatelessWidget {
12 const CarouselExampleApp({super.key});
13
14 @override
15 Widget build(BuildContext context) {
16 return MaterialApp(
17 debugShowCheckedModeBanner: false,
18 home: Scaffold(
19 appBar: AppBar(
20 leading: const Icon(Icons.cast),
21 title: const Text('Flutter TV'),
22 actions: const <Widget>[
23 Padding(
24 padding: EdgeInsetsDirectional.only(end: 16.0),
25 child: CircleAvatar(child: Icon(Icons.account_circle)),
26 ),
27 ],
28 ),
29 body: const CarouselExample(),
30 ),
31 );
32 }
33}
34
35class CarouselExample extends StatefulWidget {
36 const CarouselExample({super.key});
37
38 @override
39 State<CarouselExample> createState() => _CarouselExampleState();
40}
41
42class _CarouselExampleState extends State<CarouselExample> {
43 final CarouselController controller = CarouselController(initialItem: 1);
44
45 @override
46 void dispose() {
47 controller.dispose();
48 super.dispose();
49 }
50
51 @override
52 Widget build(BuildContext context) {
53 final double height = MediaQuery.sizeOf(context).height;
54
55 return ListView(
56 children: <Widget>[
57 ConstrainedBox(
58 constraints: BoxConstraints(maxHeight: height / 2),
59 child: CarouselView.weighted(
60 controller: controller,
61 itemSnapping: true,
62 flexWeights: const <int>[1, 7, 1],
63 children: ImageInfo.values.map((ImageInfo image) {
64 return HeroLayoutCard(imageInfo: image);
65 }).toList(),
66 ),
67 ),
68 const SizedBox(height: 20),
69 const Padding(
70 padding: EdgeInsetsDirectional.only(top: 8.0, start: 8.0),
71 child: Text('Multi-browse layout'),
72 ),
73 ConstrainedBox(
74 constraints: const BoxConstraints(maxHeight: 50),
75 child: CarouselView.weighted(
76 flexWeights: const <int>[1, 2, 3, 2, 1],
77 consumeMaxWeight: false,
78 children: List<Widget>.generate(20, (int index) {
79 return ColoredBox(
80 color: Colors.primaries[index % Colors.primaries.length].withOpacity(0.8),
81 child: const SizedBox.expand(),
82 );
83 }),
84 ),
85 ),
86 const SizedBox(height: 20),
87 ConstrainedBox(
88 constraints: const BoxConstraints(maxHeight: 200),
89 child: CarouselView.weighted(
90 flexWeights: const <int>[3, 3, 3, 2, 1],
91 consumeMaxWeight: false,
92 children: CardInfo.values.map((CardInfo info) {
93 return ColoredBox(
94 color: info.backgroundColor,
95 child: Center(
96 child: Column(
97 mainAxisAlignment: MainAxisAlignment.center,
98 children: <Widget>[
99 Icon(info.icon, color: info.color, size: 32.0),
100 Text(
101 info.label,
102 style: const TextStyle(fontWeight: FontWeight.bold),
103 overflow: TextOverflow.clip,
104 softWrap: false,
105 ),
106 ],
107 ),
108 ),
109 );
110 }).toList(),
111 ),
112 ),
113 const SizedBox(height: 20),
114 const Padding(
115 padding: EdgeInsetsDirectional.only(top: 8.0, start: 8.0),
116 child: Text('Uncontained layout'),
117 ),
118 ConstrainedBox(
119 constraints: const BoxConstraints(maxHeight: 200),
120 child: CarouselView(
121 itemExtent: 330,
122 shrinkExtent: 200,
123 children: List<Widget>.generate(20, (int index) {
124 return UncontainedLayoutCard(index: index, label: 'Show $index');
125 }),
126 ),
127 ),
128 ],
129 );
130 }
131}
132
133class HeroLayoutCard extends StatelessWidget {
134 const HeroLayoutCard({super.key, required this.imageInfo});
135
136 final ImageInfo imageInfo;
137
138 @override
139 Widget build(BuildContext context) {
140 final double width = MediaQuery.sizeOf(context).width;
141 return Stack(
142 alignment: AlignmentDirectional.bottomStart,
143 children: <Widget>[
144 ClipRect(
145 child: OverflowBox(
146 maxWidth: width * 7 / 8,
147 minWidth: width * 7 / 8,
148 child: Image(
149 fit: BoxFit.cover,
150 image: NetworkImage(
151 'https://flutter.github.io/assets-for-api-docs/assets/material/${imageInfo.url}',
152 ),
153 ),
154 ),
155 ),
156 Padding(
157 padding: const EdgeInsets.all(18.0),
158 child: Column(
159 crossAxisAlignment: CrossAxisAlignment.start,
160 mainAxisSize: MainAxisSize.min,
161 children: <Widget>[
162 Text(
163 imageInfo.title,
164 overflow: TextOverflow.clip,
165 softWrap: false,
166 style: Theme.of(context).textTheme.headlineLarge?.copyWith(color: Colors.white),
167 ),
168 const SizedBox(height: 10),
169 Text(
170 imageInfo.subtitle,
171 overflow: TextOverflow.clip,
172 softWrap: false,
173 style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: Colors.white),
174 ),
175 ],
176 ),
177 ),
178 ],
179 );
180 }
181}
182
183class UncontainedLayoutCard extends StatelessWidget {
184 const UncontainedLayoutCard({super.key, required this.index, required this.label});
185
186 final int index;
187 final String label;
188
189 @override
190 Widget build(BuildContext context) {
191 return ColoredBox(
192 color: Colors.primaries[index % Colors.primaries.length].withOpacity(0.5),
193 child: Center(
194 child: Text(
195 label,
196 style: const TextStyle(color: Colors.white, fontSize: 20),
197 overflow: TextOverflow.clip,
198 softWrap: false,
199 ),
200 ),
201 );
202 }
203}
204
205enum CardInfo {
206 camera('Cameras', Icons.video_call, Color(0xff2354C7), Color(0xffECEFFD)),
207 lighting('Lighting', Icons.lightbulb, Color(0xff806C2A), Color(0xffFAEEDF)),
208 climate('Climate', Icons.thermostat, Color(0xffA44D2A), Color(0xffFAEDE7)),
209 wifi('Wifi', Icons.wifi, Color(0xff417345), Color(0xffE5F4E0)),
210 media('Media', Icons.library_music, Color(0xff2556C8), Color(0xffECEFFD)),
211 security('Security', Icons.crisis_alert, Color(0xff794C01), Color(0xffFAEEDF)),
212 safety('Safety', Icons.medical_services, Color(0xff2251C5), Color(0xffECEFFD)),
213 more('', Icons.add, Color(0xff201D1C), Color(0xffE3DFD8));
214
215 const CardInfo(this.label, this.icon, this.color, this.backgroundColor);
216 final String label;
217 final IconData icon;
218 final Color color;
219 final Color backgroundColor;
220}
221
222enum ImageInfo {
223 image0('The Flow', 'Sponsored | Season 1 Now Streaming', 'content_based_color_scheme_1.png'),
224 image1(
225 'Through the Pane',
226 'Sponsored | Season 1 Now Streaming',
227 'content_based_color_scheme_2.png',
228 ),
229 image2('Iridescence', 'Sponsored | Season 1 Now Streaming', 'content_based_color_scheme_3.png'),
230 image3('Sea Change', 'Sponsored | Season 1 Now Streaming', 'content_based_color_scheme_4.png'),
231 image4('Blue Symphony', 'Sponsored | Season 1 Now Streaming', 'content_based_color_scheme_5.png'),
232 image5('When It Rains', 'Sponsored | Season 1 Now Streaming', 'content_based_color_scheme_6.png');
233
234 const ImageInfo(this.title, this.subtitle, this.url);
235 final String title;
236 final String subtitle;
237 final String url;
238}
239