diff --git a/examples/api/lib/widgets/sliver/decorated_sliver.1.dart b/examples/api/lib/widgets/sliver/decorated_sliver.1.dart new file mode 100644 index 00000000000..13f59c53d12 --- /dev/null +++ b/examples/api/lib/widgets/sliver/decorated_sliver.1.dart @@ -0,0 +1,158 @@ +// 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 example for [DecoratedSliver] +/// with clipping turned off in a parent [CustomScrollView]. + +void main() => runApp(const DecoratedSliverClipExampleApp()); + +class DecoratedSliverClipExampleApp extends StatelessWidget { + const DecoratedSliverClipExampleApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'DecoratedSliver Clip Example', + theme: ThemeData( + colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), + useMaterial3: true, + ), + home: const DecoratedSliverClipExample(), + ); + } +} + +class DecoratedSliverClipExample extends StatefulWidget { + const DecoratedSliverClipExample({super.key}); + + @override + State createState() => _DecoratedSliverClipExampleState(); +} + +class _DecoratedSliverClipExampleState extends State { + double _height = 225.0; + bool _isClipped = false; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: const Color(0xFF1C1C1C), + body: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Switch( + inactiveTrackColor: Colors.cyan, + activeColor: Colors.pink, + onChanged: (bool value) { + setState(() { + _isClipped = value; + }); + }, + value: _isClipped, + ), + Slider( + activeColor: Colors.pink, + inactiveColor: Colors.cyan, + onChanged: (double value) { + setState(() { + _height = value; + }); + }, + value: _height, + min: 150, + max: 225, + ), + ], + ), + const SizedBox( + height: 20.0, + ), + Stack( + children: [ + Padding( + padding: const EdgeInsets.all(24.0), + child: SizedBox( + width: 400, + height: _height, + child: ResizableCustomScrollView(isClipped: _isClipped), + ), + ), + Positioned( + top: _height, + left: 0, + right: 0, + child: SizedBox( + height: MediaQuery.of(context).size.height - _height, + width: double.infinity, + ), + ), + ], + ), + ], + ), + ); + } +} + +class ResizableCustomScrollView extends StatelessWidget { + const ResizableCustomScrollView({ + super.key, + required this.isClipped, + }); + + final bool isClipped; + + @override + Widget build(BuildContext context) { + return CustomScrollView( + // The clip behavior defaults to Clip.hardEdge if no argument is provided. + clipBehavior: isClipped ? Clip.hardEdge : Clip.none, + slivers: [ + DecoratedSliver( + decoration: const ShapeDecoration( + color: Color(0xFF2C2C2C), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(6), + ), + ), + shadows: [ + BoxShadow( + color: Colors.cyan, + offset: Offset(3, 3), + blurRadius: 24, + ), + ], + ), + sliver: SliverList.builder( + itemCount: 5, + itemBuilder: (_, int index) => Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + const Icon( + Icons.add_box, + color: Color(0xFFA8A8A8), + ), + Flexible( + child: Text( + 'Item $index', + style: const TextStyle( + color: Color(0xFFA8A8A8), + ), + ), + ), + ], + ), + ), + ), + ), + ], + ); + } +} diff --git a/examples/api/test/widgets/sliver/decorated_sliver.1_test.dart b/examples/api/test/widgets/sliver/decorated_sliver.1_test.dart new file mode 100644 index 00000000000..7f3611216cf --- /dev/null +++ b/examples/api/test/widgets/sliver/decorated_sliver.1_test.dart @@ -0,0 +1,42 @@ +// 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_api_samples/widgets/sliver/decorated_sliver.1.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('CustomScrollView clipBehavior is Clip.none when is Clipped is false', (WidgetTester tester) async { + await tester.pumpWidget( + const MaterialApp( + home: example.DecoratedSliverClipExample(), + ), + ); + + final CustomScrollView customScrollView = tester.widget(find.byType(CustomScrollView)); + + expect(customScrollView.clipBehavior, equals(Clip.none)); + }); + + testWidgets('Verify the DecoratedSliver has shadow property in decoration', (WidgetTester tester) async { + await tester.pumpWidget( + const MaterialApp( + home: example.ResizableCustomScrollView(isClipped: false), + ), + ); + + final DecoratedSliver decoratedSliver = tester.widget(find.byType(DecoratedSliver)); + final ShapeDecoration shapeDecoration = decoratedSliver.decoration as ShapeDecoration; + + expect(shapeDecoration.shadows, isNotEmpty); + }); + + testWidgets('Verify Slider and Switch widgets', (WidgetTester tester) async { + await tester.pumpWidget(const example.DecoratedSliverClipExampleApp()); + + expect(find.byType(Slider), findsOneWidget); + + expect(find.byType(Switch), findsOneWidget); + }); +} diff --git a/packages/flutter/lib/src/widgets/decorated_sliver.dart b/packages/flutter/lib/src/widgets/decorated_sliver.dart index d51af4812a6..c845d44176c 100644 --- a/packages/flutter/lib/src/widgets/decorated_sliver.dart +++ b/packages/flutter/lib/src/widgets/decorated_sliver.dart @@ -25,8 +25,6 @@ import 'image.dart'; /// /// Commonly used with [BoxDecoration]. /// -/// The [child] is not clipped. To clip a child to the shape of a particular -/// [ShapeDecoration], consider using a [ClipPath] widget. /// /// {@tool dartpad} /// This sample shows a radial gradient that draws a moon on a night sky: @@ -34,6 +32,20 @@ import 'image.dart'; /// ** See code in examples/api/lib/widgets/sliver/decorated_sliver.0.dart ** /// {@end-tool} /// +/// {@tool dartpad} +/// This example demonstrates how the [CustomScrollView.clipBehavior] +/// impacts a decorated sliver's appearance. +/// +/// The [Switch] determines whether clipping is enabled, and +/// the [Slider] adjusts the height of window. +/// +/// ** See code in examples/api/lib/widgets/sliver/decorated_sliver.1.dart ** +/// {@end-tool} +/// +/// This widget does not apply any additional clipping to its [child]. +/// To clip a child based on the [Decoration]'s shape, consider using +/// a [ClipPath] widget. +/// /// See also: /// /// * [DecoratedBox], the version of this class that works with RenderBox widgets.