Feat: Add carousel view theme (#164769)

Feat: Add carousel view theme
fixes: #159679 

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.
diff --git a/packages/flutter/lib/material.dart b/packages/flutter/lib/material.dart
index fff0a91..caab343 100644
--- a/packages/flutter/lib/material.dart
+++ b/packages/flutter/lib/material.dart
@@ -47,6 +47,7 @@
 export 'src/material/card.dart';
 export 'src/material/card_theme.dart';
 export 'src/material/carousel.dart';
+export 'src/material/carousel_theme.dart';
 export 'src/material/checkbox.dart';
 export 'src/material/checkbox_list_tile.dart';
 export 'src/material/checkbox_theme.dart';
diff --git a/packages/flutter/lib/src/material/carousel.dart b/packages/flutter/lib/src/material/carousel.dart
index 1a36f50..daa1a52 100644
--- a/packages/flutter/lib/src/material/carousel.dart
+++ b/packages/flutter/lib/src/material/carousel.dart
@@ -12,6 +12,8 @@
 import 'package:flutter/rendering.dart';
 import 'package:flutter/widgets.dart';
 
+import 'carousel_theme.dart';
+import 'color_scheme.dart';
 import 'colors.dart';
 import 'ink_well.dart';
 import 'material.dart';
@@ -401,25 +403,30 @@
     }
   }
 
-  Widget _buildCarouselItem(ThemeData theme, int index) {
-    final EdgeInsets effectivePadding = widget.padding ?? const EdgeInsets.all(4.0);
+  Widget _buildCarouselItem(int index) {
+    final CarouselViewThemeData carouselTheme = CarouselViewTheme.of(context);
+    final ColorScheme colorScheme = ColorScheme.of(context);
+    final EdgeInsets effectivePadding =
+        widget.padding ?? carouselTheme.padding ?? const EdgeInsets.all(4.0);
     final Color effectiveBackgroundColor =
-        widget.backgroundColor ?? Theme.of(context).colorScheme.surface;
-    final double effectiveElevation = widget.elevation ?? 0.0;
+        widget.backgroundColor ?? carouselTheme.backgroundColor ?? colorScheme.surface;
+    final double effectiveElevation = widget.elevation ?? carouselTheme.elevation ?? 0.0;
     final ShapeBorder effectiveShape =
         widget.shape ??
+        carouselTheme.shape ??
         const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(28.0)));
     final WidgetStateProperty<Color?> effectiveOverlayColor =
         widget.overlayColor ??
+        carouselTheme.overlayColor ??
         WidgetStateProperty.resolveWith((Set<WidgetState> states) {
           if (states.contains(WidgetState.pressed)) {
-            return theme.colorScheme.onSurface.withOpacity(0.1);
+            return colorScheme.onSurface.withOpacity(0.1);
           }
           if (states.contains(WidgetState.hovered)) {
-            return theme.colorScheme.onSurface.withOpacity(0.08);
+            return colorScheme.onSurface.withOpacity(0.08);
           }
           if (states.contains(WidgetState.focused)) {
-            return theme.colorScheme.onSurface.withOpacity(0.1);
+            return colorScheme.onSurface.withOpacity(0.1);
           }
           return null;
         });
@@ -461,7 +468,7 @@
         itemExtent: _itemExtent!,
         minExtent: widget.shrinkExtent,
         delegate: SliverChildBuilderDelegate((BuildContext context, int index) {
-          return _buildCarouselItem(theme, index);
+          return _buildCarouselItem(index);
         }, childCount: widget.children.length),
       );
     }
@@ -475,7 +482,7 @@
       shrinkExtent: widget.shrinkExtent,
       weights: _flexWeights!,
       delegate: SliverChildBuilderDelegate((BuildContext context, int index) {
-        return _buildCarouselItem(theme, index);
+        return _buildCarouselItem(index);
       }, childCount: widget.children.length),
     );
   }
diff --git a/packages/flutter/lib/src/material/carousel_theme.dart b/packages/flutter/lib/src/material/carousel_theme.dart
new file mode 100644
index 0000000..6bc4d58
--- /dev/null
+++ b/packages/flutter/lib/src/material/carousel_theme.dart
@@ -0,0 +1,183 @@
+// 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 'dart:ui' show lerpDouble;
+
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+
+import 'carousel.dart';
+import 'material.dart';
+import 'theme.dart';
+
+/// Defines default property values for descendant [CarouselView] widgets.
+///
+/// Descendant widgets obtain the current [CarouselViewThemeData] object using
+/// `CarouselViewTheme.of(context)`. Instances of [CarouselViewThemeData] can be
+/// customized with [CarouselViewThemeData.copyWith].
+///
+/// Typically a [CarouselViewThemeData] is specified as part of the overall [Theme]
+/// with [ThemeData.carouselViewTheme].
+///
+/// All [CarouselViewThemeData] properties are `null` by default. When null, the [CarouselView]
+/// will provide its own defaults.
+///
+/// See also:
+///
+///  * [CarouselViewTheme], an [InheritedWidget] that propagates the theme to its descendants.
+///  * [ThemeData], which describes the overall theme information for the application.
+@immutable
+class CarouselViewThemeData with Diagnosticable {
+  /// Creates a theme that can be used for [ThemeData.carouselViewTheme].
+  const CarouselViewThemeData({
+    this.elevation,
+    this.backgroundColor,
+    this.overlayColor,
+    this.shape,
+    this.padding,
+  });
+
+  /// The amount of space to surround each carousel item with.
+  ///
+  /// Overrides the default value for [CarouselView.padding].
+  final EdgeInsets? padding;
+
+  /// The background color for each carousel item.
+  ///
+  /// Overrides the default value for [CarouselView.backgroundColor].
+  final Color? backgroundColor;
+
+  /// The z-coordinate of each carousel item.
+  ///
+  /// This controls the size of the shadow below the carousel.
+  ///
+  /// Overrides the default value for [CarouselView.elevation].
+  final double? elevation;
+
+  /// The shape of the carousel item's [Material].
+  ///
+  /// Overrides the default value for [CarouselView.shape].
+  final OutlinedBorder? shape;
+
+  /// The highlight color to indicate the carousel items are in pressed, hovered
+  /// or focused states.
+  ///
+  /// Overrides the default value for [CarouselView.overlayColor].
+  final WidgetStateProperty<Color?>? overlayColor;
+
+  /// Creates a copy of this object with the given fields replaced with the
+  /// new values.
+  CarouselViewThemeData copyWith({
+    Color? backgroundColor,
+    double? elevation,
+    OutlinedBorder? shape,
+    WidgetStateProperty<Color?>? overlayColor,
+    EdgeInsets? padding,
+  }) {
+    return CarouselViewThemeData(
+      backgroundColor: backgroundColor ?? this.backgroundColor,
+      elevation: elevation ?? this.elevation,
+      shape: shape ?? this.shape,
+      overlayColor: overlayColor ?? this.overlayColor,
+      padding: padding ?? this.padding,
+    );
+  }
+
+  /// Linearly interpolate between two carousel themes.
+  ///
+  /// {@macro dart.ui.shadow.lerp}
+  static CarouselViewThemeData lerp(CarouselViewThemeData? a, CarouselViewThemeData? b, double t) {
+    if (identical(a, b) && a != null) {
+      return a;
+    }
+    return CarouselViewThemeData(
+      backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
+      elevation: lerpDouble(a?.elevation, b?.elevation, t),
+      shape: ShapeBorder.lerp(a?.shape, b?.shape, t) as OutlinedBorder?,
+      overlayColor: WidgetStateProperty.lerp<Color?>(
+        a?.overlayColor,
+        b?.overlayColor,
+        t,
+        Color.lerp,
+      ),
+      padding: EdgeInsets.lerp(a?.padding, b?.padding, t),
+    );
+  }
+
+  @override
+  int get hashCode => Object.hash(backgroundColor, elevation, shape, overlayColor, padding);
+
+  @override
+  bool operator ==(Object other) {
+    if (identical(this, other)) {
+      return true;
+    }
+    if (other.runtimeType != runtimeType) {
+      return false;
+    }
+    return other is CarouselViewThemeData &&
+        other.backgroundColor == backgroundColor &&
+        other.elevation == elevation &&
+        other.shape == shape &&
+        other.overlayColor == overlayColor &&
+        other.padding == padding;
+  }
+
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+    properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null));
+    properties.add(DoubleProperty('elevation', elevation, defaultValue: null));
+    properties.add(DiagnosticsProperty<OutlinedBorder>('shape', shape, defaultValue: null));
+    properties.add(
+      DiagnosticsProperty<WidgetStateProperty<Color?>>(
+        'overlayColor',
+        overlayColor,
+        defaultValue: null,
+      ),
+    );
+    properties.add(DiagnosticsProperty<EdgeInsets>('padding', padding, defaultValue: null));
+  }
+}
+
+/// Applies a carousel theme to descendant [CarouselView] widgets.
+///
+/// Descendant widgets obtain the current theme's [CarouselViewThemeData] using
+/// [CarouselViewTheme.of]. When a widget uses [CarouselViewTheme.of], it is automatically
+/// rebuilt if the theme later changes.
+///
+/// A carousel theme can be specified as part of the overall Material theme using
+/// [ThemeData.carouselViewTheme].
+///
+/// See also:
+///
+///  * [CarouselViewThemeData], which describes the actual configuration of a carousel
+///    theme.
+///  * [Theme], which controls the overall theme inheritance.
+class CarouselViewTheme extends InheritedTheme {
+  /// Creates a carousel theme that configures all descendant [CarouselView] widgets.
+  const CarouselViewTheme({super.key, required this.data, required super.child});
+
+  /// The properties for descendant carousel widgets.
+  final CarouselViewThemeData data;
+
+  /// Returns the configuration [data] from the closest [CarouselViewTheme] ancestor.
+  ///
+  /// If there is no ancestor, it returns [ThemeData.carouselViewTheme].
+  static CarouselViewThemeData of(BuildContext context) {
+    final CarouselViewTheme? inheritedTheme =
+        context.dependOnInheritedWidgetOfExactType<CarouselViewTheme>();
+    return inheritedTheme?.data ?? Theme.of(context).carouselViewTheme;
+  }
+
+  /// Wraps the given [child] with a [CarouselViewTheme] containing the [data].
+  @override
+  Widget wrap(BuildContext context, Widget child) {
+    return CarouselViewTheme(data: data, child: child);
+  }
+
+  /// Returns true if the [data] fields of the two themes are different.
+  @override
+  bool updateShouldNotify(CarouselViewTheme oldWidget) => data != oldWidget.data;
+}
diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart
index e11e1ee..bedd45b 100644
--- a/packages/flutter/lib/src/material/theme_data.dart
+++ b/packages/flutter/lib/src/material/theme_data.dart
@@ -21,6 +21,7 @@
 import 'button_bar_theme.dart';
 import 'button_theme.dart';
 import 'card_theme.dart';
+import 'carousel_theme.dart';
 import 'checkbox_theme.dart';
 import 'chip_theme.dart';
 import 'color_scheme.dart';
@@ -324,6 +325,7 @@
     BottomSheetThemeData? bottomSheetTheme,
     ButtonThemeData? buttonTheme,
     CardThemeData? cardTheme,
+    CarouselViewThemeData? carouselViewTheme,
     CheckboxThemeData? checkboxTheme,
     ChipThemeData? chipTheme,
     DataTableThemeData? dataTableTheme,
@@ -528,6 +530,7 @@
     bottomNavigationBarTheme ??= const BottomNavigationBarThemeData();
     bottomSheetTheme ??= const BottomSheetThemeData();
     cardTheme ??= const CardThemeData();
+    carouselViewTheme ??= const CarouselViewThemeData();
     checkboxTheme ??= const CheckboxThemeData();
     chipTheme ??= const ChipThemeData();
     dataTableTheme ??= const DataTableThemeData();
@@ -622,6 +625,7 @@
       bottomSheetTheme: bottomSheetTheme,
       buttonTheme: buttonTheme,
       cardTheme: cardTheme,
+      carouselViewTheme: carouselViewTheme,
       checkboxTheme: checkboxTheme,
       chipTheme: chipTheme,
       dataTableTheme: dataTableTheme,
@@ -733,6 +737,7 @@
     required this.bottomSheetTheme,
     required this.buttonTheme,
     required this.cardTheme,
+    required this.carouselViewTheme,
     required this.checkboxTheme,
     required this.chipTheme,
     required this.dataTableTheme,
@@ -1305,6 +1310,9 @@
   /// This is the value returned from [CardTheme.of].
   final CardThemeData cardTheme;
 
+  /// A theme for customizing the appearance and layout of [CarouselView] widgets.
+  final CarouselViewThemeData carouselViewTheme;
+
   /// A theme for customizing the appearance and layout of [Checkbox] widgets.
   final CheckboxThemeData checkboxTheme;
 
@@ -1516,6 +1524,7 @@
     BottomSheetThemeData? bottomSheetTheme,
     ButtonThemeData? buttonTheme,
     CardThemeData? cardTheme,
+    CarouselViewThemeData? carouselViewTheme,
     CheckboxThemeData? checkboxTheme,
     ChipThemeData? chipTheme,
     DataTableThemeData? dataTableTheme,
@@ -1634,6 +1643,7 @@
       bottomSheetTheme: bottomSheetTheme ?? this.bottomSheetTheme,
       buttonTheme: buttonTheme ?? this.buttonTheme,
       cardTheme: cardTheme ?? this.cardTheme,
+      carouselViewTheme: carouselViewTheme ?? this.carouselViewTheme,
       checkboxTheme: checkboxTheme ?? this.checkboxTheme,
       chipTheme: chipTheme ?? this.chipTheme,
       dataTableTheme: dataTableTheme ?? this.dataTableTheme,
@@ -1954,6 +1964,7 @@
       bottomSheetTheme: BottomSheetThemeData.lerp(a.bottomSheetTheme, b.bottomSheetTheme, t)!,
       buttonTheme: t < 0.5 ? a.buttonTheme : b.buttonTheme,
       cardTheme: CardThemeData.lerp(a.cardTheme, b.cardTheme, t),
+      carouselViewTheme: CarouselViewThemeData.lerp(a.carouselViewTheme, b.carouselViewTheme, t),
       checkboxTheme: CheckboxThemeData.lerp(a.checkboxTheme, b.checkboxTheme, t),
       chipTheme: ChipThemeData.lerp(a.chipTheme, b.chipTheme, t)!,
       dataTableTheme: DataTableThemeData.lerp(a.dataTableTheme, b.dataTableTheme, t),
@@ -2072,6 +2083,7 @@
         other.bottomSheetTheme == bottomSheetTheme &&
         other.buttonTheme == buttonTheme &&
         other.cardTheme == cardTheme &&
+        other.carouselViewTheme == carouselViewTheme &&
         other.checkboxTheme == checkboxTheme &&
         other.chipTheme == chipTheme &&
         other.dataTableTheme == dataTableTheme &&
@@ -2171,6 +2183,7 @@
       bottomSheetTheme,
       buttonTheme,
       cardTheme,
+      carouselViewTheme,
       checkboxTheme,
       chipTheme,
       dataTableTheme,
@@ -2550,6 +2563,14 @@
       DiagnosticsProperty<CardThemeData>('cardTheme', cardTheme, level: DiagnosticLevel.debug),
     );
     properties.add(
+      DiagnosticsProperty<CarouselViewThemeData>(
+        'carouselViewTheme',
+        carouselViewTheme,
+        defaultValue: defaultData.carouselViewTheme,
+        level: DiagnosticLevel.debug,
+      ),
+    );
+    properties.add(
       DiagnosticsProperty<CheckboxThemeData>(
         'checkboxTheme',
         checkboxTheme,
diff --git a/packages/flutter/test/material/carousel_theme_test.dart b/packages/flutter/test/material/carousel_theme_test.dart
new file mode 100644
index 0000000..5c174e1
--- /dev/null
+++ b/packages/flutter/test/material/carousel_theme_test.dart
@@ -0,0 +1,242 @@
+// 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';
+import 'package:flutter/rendering.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+  test('CarouselViewThemeData copyWith, ==, hashCode basics', () {
+    expect(const CarouselViewThemeData(), const CarouselViewThemeData().copyWith());
+    expect(
+      const CarouselViewThemeData().hashCode,
+      const CarouselViewThemeData().copyWith().hashCode,
+    );
+  });
+
+  test('CarouselViewThemeData null fields by default', () {
+    const CarouselViewThemeData carouselViewTheme = CarouselViewThemeData();
+    expect(carouselViewTheme.backgroundColor, null);
+    expect(carouselViewTheme.elevation, null);
+    expect(carouselViewTheme.overlayColor, null);
+    expect(carouselViewTheme.padding, null);
+    expect(carouselViewTheme.shape, null);
+  });
+
+  testWidgets('Default CarouselViewThemeData debugFillProperties', (WidgetTester tester) async {
+    final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
+    const CarouselViewThemeData().debugFillProperties(builder);
+
+    final List<String> description =
+        builder.properties
+            .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
+            .map((DiagnosticsNode node) => node.toString())
+            .toList();
+
+    expect(description, <String>[]);
+  });
+
+  testWidgets('CarouselViewThemeData implements debugFillProperties', (WidgetTester tester) async {
+    final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
+    const CarouselViewThemeData(
+      backgroundColor: Color(0xFFFFFFFF),
+      elevation: 5.0,
+      padding: EdgeInsets.zero,
+      shape: RoundedRectangleBorder(),
+      overlayColor: MaterialStatePropertyAll<Color>(Colors.red),
+    ).debugFillProperties(builder);
+
+    final List<String> description =
+        builder.properties
+            .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
+            .map((DiagnosticsNode node) => node.toString())
+            .toList();
+
+    expect(description, <String>[
+      'backgroundColor: ${const Color(0xffffffff)}',
+      'elevation: 5.0',
+      'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)',
+      'overlayColor: WidgetStatePropertyAll(${Colors.red})',
+      'padding: EdgeInsets.zero',
+    ]);
+  });
+
+  testWidgets('Uses value from CarouselViewThemeData', (WidgetTester tester) async {
+    final CarouselViewThemeData carouselViewTheme = _carouselViewThemeData();
+    await tester.pumpWidget(
+      MaterialApp(
+        theme: ThemeData(carouselViewTheme: carouselViewTheme),
+        home: const Scaffold(
+          body: Center(
+            child: CarouselView(
+              itemExtent: 100,
+              children: <Widget>[SizedBox(width: 100, height: 100)],
+            ),
+          ),
+        ),
+      ),
+    );
+    expect(find.byType(CarouselView), findsOneWidget);
+
+    final Finder padding = find.descendant(
+      of: find.byType(CarouselView),
+      matching: find.byWidgetPredicate(
+        (Widget widget) => widget is Padding && widget.child is Material,
+      ),
+    );
+
+    expect(padding, findsOneWidget);
+    final Padding paddingWidget = tester.widget<Padding>(padding);
+    final Material material = paddingWidget.child! as Material;
+
+    final InkWell inkWell = tester.widget<InkWell>(
+      find.descendant(of: find.byType(CarouselView), matching: find.byType(InkWell)),
+    );
+
+    expect(paddingWidget.padding, carouselViewTheme.padding);
+    expect(material.color, carouselViewTheme.backgroundColor);
+    expect(material.elevation, carouselViewTheme.elevation);
+    expect(material.shape, carouselViewTheme.shape);
+    expect(material.borderRadius, null);
+    expect(material.clipBehavior, Clip.antiAlias);
+    expect(inkWell.overlayColor, carouselViewTheme.overlayColor);
+  });
+
+  testWidgets('Widgets properties override theme', (WidgetTester tester) async {
+    final CarouselViewThemeData carouselViewTheme = _carouselViewThemeData();
+    const Color backgroundColor = Color(0xFFFF0000);
+    const double elevation = 10.0;
+    const EdgeInsets padding = EdgeInsets.all(15.0);
+    const OutlinedBorder shape = RoundedRectangleBorder(
+      borderRadius: BorderRadius.all(Radius.circular(10)),
+    );
+    const WidgetStateProperty<Color?> overlayColor = MaterialStatePropertyAll<Color>(Colors.green);
+    await tester.pumpWidget(
+      MaterialApp(
+        theme: ThemeData(carouselViewTheme: carouselViewTheme),
+        home: const Scaffold(
+          body: Center(
+            child: CarouselView(
+              backgroundColor: backgroundColor,
+              elevation: elevation,
+              padding: padding,
+              shape: shape,
+              overlayColor: overlayColor,
+              itemExtent: 100,
+              children: <Widget>[SizedBox(width: 100, height: 100)],
+            ),
+          ),
+        ),
+      ),
+    );
+    expect(find.byType(CarouselView), findsOneWidget);
+
+    final Finder paddingFinder = find.descendant(
+      of: find.byType(CarouselView),
+      matching: find.byWidgetPredicate(
+        (Widget widget) => widget is Padding && widget.child is Material,
+      ),
+    );
+
+    expect(paddingFinder, findsOneWidget);
+    final Padding paddingWidget = tester.widget<Padding>(paddingFinder);
+    final Material material = paddingWidget.child! as Material;
+
+    final InkWell inkWell = tester.widget<InkWell>(
+      find.descendant(of: find.byType(CarouselView), matching: find.byType(InkWell)),
+    );
+
+    expect(paddingWidget.padding, padding);
+    expect(material.color, backgroundColor);
+    expect(material.elevation, elevation);
+    expect(material.shape, shape);
+    expect(inkWell.overlayColor, overlayColor);
+  });
+
+  testWidgets('CarouselViewTheme can override Theme.carouselViewTheme', (
+    WidgetTester tester,
+  ) async {
+    const Color globalBackgroundColor = Color(0xfffffff1);
+    const Color globalOverlayColor = Color(0xff000000);
+    const double globalElevation = 5.0;
+    const EdgeInsets globalPadding = EdgeInsets.all(10.0);
+    const OutlinedBorder globalShape = RoundedRectangleBorder();
+
+    const Color localBackgroundColor = Color(0xffff0000);
+    const Color localOverlayColor = Color(0xffffffff);
+    const double localElevation = 10.0;
+    const EdgeInsets localPadding = EdgeInsets.all(15.0);
+    const OutlinedBorder localShape = RoundedRectangleBorder(
+      borderRadius: BorderRadius.all(Radius.circular(10)),
+    );
+
+    await tester.pumpWidget(
+      MaterialApp(
+        theme: ThemeData(
+          carouselViewTheme: const CarouselViewThemeData(
+            backgroundColor: globalBackgroundColor,
+            overlayColor: MaterialStatePropertyAll<Color>(globalOverlayColor),
+            elevation: globalElevation,
+            padding: globalPadding,
+            shape: globalShape,
+          ),
+        ),
+        home: const Scaffold(
+          body: Center(
+            child: CarouselViewTheme(
+              data: CarouselViewThemeData(
+                backgroundColor: localBackgroundColor,
+                overlayColor: MaterialStatePropertyAll<Color>(localOverlayColor),
+                elevation: localElevation,
+                padding: localPadding,
+                shape: localShape,
+              ),
+              child: CarouselView(
+                itemExtent: 100,
+                children: <Widget>[SizedBox(width: 100, height: 100)],
+              ),
+            ),
+          ),
+        ),
+      ),
+    );
+
+    final Finder padding = find.descendant(
+      of: find.byType(CarouselView),
+      matching: find.byWidgetPredicate(
+        (Widget widget) => widget is Padding && widget.child is Material,
+      ),
+    );
+
+    expect(padding, findsOneWidget);
+    final Padding paddingWidget = tester.widget<Padding>(padding);
+    final Material material = paddingWidget.child! as Material;
+
+    final InkWell inkWell = tester.widget<InkWell>(
+      find.descendant(of: find.byType(CarouselView), matching: find.byType(InkWell)),
+    );
+
+    expect(paddingWidget.padding, localPadding);
+    expect(material.color, localBackgroundColor);
+    expect(material.elevation, localElevation);
+    expect(material.shape, localShape);
+    expect(inkWell.overlayColor?.resolve(<MaterialState>{}), localOverlayColor);
+  });
+}
+
+CarouselViewThemeData _carouselViewThemeData() {
+  const Color backgroundColor = Color(0xFF0000FF);
+  const double elevation = 5.0;
+  const EdgeInsets padding = EdgeInsets.all(10.0);
+  const OutlinedBorder shape = RoundedRectangleBorder();
+  const WidgetStateProperty<Color?> overlayColor = MaterialStatePropertyAll<Color>(Colors.red);
+
+  return const CarouselViewThemeData(
+    backgroundColor: backgroundColor,
+    elevation: elevation,
+    padding: padding,
+    shape: shape,
+    overlayColor: overlayColor,
+  );
+}
diff --git a/packages/flutter/test/material/theme_data_test.dart b/packages/flutter/test/material/theme_data_test.dart
index 5de641c..328a7c0 100644
--- a/packages/flutter/test/material/theme_data_test.dart
+++ b/packages/flutter/test/material/theme_data_test.dart
@@ -1339,6 +1339,7 @@
       bottomSheetTheme: const BottomSheetThemeData(backgroundColor: Colors.black),
       buttonTheme: const ButtonThemeData(colorScheme: ColorScheme.dark()),
       cardTheme: const CardThemeData(color: Colors.black),
+      carouselViewTheme: const CarouselViewThemeData(),
       checkboxTheme: const CheckboxThemeData(),
       chipTheme: chipTheme,
       dataTableTheme: const DataTableThemeData(),
@@ -1467,6 +1468,7 @@
       bottomSheetTheme: const BottomSheetThemeData(backgroundColor: Colors.white),
       buttonTheme: const ButtonThemeData(colorScheme: ColorScheme.light()),
       cardTheme: const CardThemeData(color: Colors.white),
+      carouselViewTheme: const CarouselViewThemeData(),
       checkboxTheme: const CheckboxThemeData(),
       chipTheme: otherChipTheme,
       dataTableTheme: const DataTableThemeData(),
@@ -1807,6 +1809,7 @@
       'bottomSheetTheme',
       'buttonTheme',
       'cardTheme',
+      'carouselViewTheme',
       'checkboxTheme',
       'chipTheme',
       'dataTableTheme',