Created
October 22, 2024 15:40
-
-
Save cristinaponcela/3053d28b0ba280e2b61da5e34b8e5203 to your computer and use it in GitHub Desktop.
How to create a custom InnerShadow widget in Flutter. Overrides the RenderProxyBox class to add a smooth inner shadow to any child widget using the canvas' paint and save/restore techniques. MIT License
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Custom widget for adding inner shadow | |
| class InnerShadow extends SingleChildRenderObjectWidget { | |
| const InnerShadow({ | |
| Key? key, | |
| this.blur = 5, // Default blur value for shadow | |
| this.color = Colors.black38, // Default shadow color | |
| this.offset = const Offset(50, 50), // Default shadow offset | |
| Widget? child, | |
| }) : super(key: key, child: child); | |
| final double blur; // Amount of blur for the shadow | |
| final Color color; // Color of the shadow | |
| final Offset offset; // Offset of the shadow | |
| @override | |
| RenderObject createRenderObject(BuildContext context) { | |
| // Create and return the custom render object | |
| final renderObject = _RenderInnerShadow(); | |
| updateRenderObject(context, renderObject); | |
| return renderObject; | |
| } | |
| @override | |
| void updateRenderObject( | |
| BuildContext context, _RenderInnerShadow renderObject) { | |
| // Update the render object with the new values of blur, color, and offset | |
| renderObject | |
| ..color = color | |
| ..blur = blur | |
| ..dx = offset.dx | |
| ..dy = offset.dy; | |
| } | |
| } | |
| // Custom render object class for inner shadow effect | |
| class _RenderInnerShadow extends RenderProxyBox { | |
| double blur = 5; // Default blur for shadow | |
| Color color = Color(0xFFF15923); // Default color for shadow | |
| double dx = 5; // Default x-axis translation for shadow | |
| double dy = 5; // Default y-axis translation for shadow | |
| @override | |
| void paint(PaintingContext context, Offset offset) { | |
| // Ensure there is a child to paint | |
| if (child == null) return; | |
| // Calculate the outer and inner bounds of the shadow | |
| final Rect outerRect = offset & size; | |
| final Rect innerRect = | |
| outerRect.deflate(blur); // Adjust the inner rect for shadow | |
| final Canvas canvas = context.canvas; | |
| // Draw the child widget | |
| canvas.saveLayer(outerRect, Paint()); | |
| context.paintChild(child!, offset); | |
| // Create the paint for the shadow layer | |
| final Paint shadowPaint = Paint() | |
| ..blendMode = BlendMode.srcATop // Apply the shadow over the widget | |
| ..colorFilter = | |
| ColorFilter.mode(color, BlendMode.srcOut) // Set shadow color | |
| ..imageFilter = | |
| ImageFilter.blur(sigmaX: blur, sigmaY: blur); // Apply blur | |
| // Draw the shadow layer on the canvas | |
| canvas.saveLayer(outerRect, shadowPaint); | |
| context.paintChild(child!, offset); | |
| // Restore the canvas stack | |
| canvas.restore(); | |
| canvas.restore(); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'package:flutter/material.dart'; | |
| import 'dart:ui'; | |
| import 'package:flutter/rendering.dart'; | |
| void main() { | |
| runApp(MyApp()); | |
| } | |
| class MyApp extends StatelessWidget { | |
| @override | |
| Widget build(BuildContext context) { | |
| return MaterialApp( | |
| home: Scaffold( | |
| backgroundColor: Colors.white, // White background for contrast | |
| body: Center( | |
| // Center the widget | |
| child: InnerShadow( | |
| blur: 15, | |
| color: Color.fromARGB(255, 70, 70, 70), | |
| offset: const Offset(5, 5), // Apply the shadow offset | |
| child: Container( | |
| decoration: const BoxDecoration( | |
| borderRadius: BorderRadius.all(Radius.circular(8)), | |
| color: Color(0xFFF15923), // The orange background color | |
| ), | |
| height: 100, | |
| width: 200, | |
| child: const Center( | |
| child: Text( | |
| "Test", // Centered white text | |
| style: TextStyle( | |
| color: Colors.white, | |
| fontSize: 24, | |
| fontWeight: FontWeight.bold, | |
| ), | |
| ), | |
| ), | |
| ), | |
| ), | |
| ), | |
| ), | |
| ); | |
| } | |
| } | |
| // Custom widget for adding inner shadow | |
| class InnerShadow extends SingleChildRenderObjectWidget { | |
| const InnerShadow({ | |
| Key? key, | |
| this.blur = 5, // Default blur value for shadow | |
| this.color = Colors.black38, // Default shadow color | |
| this.offset = const Offset(50, 50), // Default shadow offset | |
| Widget? child, | |
| }) : super(key: key, child: child); | |
| final double blur; // Amount of blur for the shadow | |
| final Color color; // Color of the shadow | |
| final Offset offset; // Offset of the shadow | |
| @override | |
| RenderObject createRenderObject(BuildContext context) { | |
| // Create and return the custom render object | |
| final renderObject = _RenderInnerShadow(); | |
| updateRenderObject(context, renderObject); | |
| return renderObject; | |
| } | |
| @override | |
| void updateRenderObject( | |
| BuildContext context, _RenderInnerShadow renderObject) { | |
| // Update the render object with the new values of blur, color, and offset | |
| renderObject | |
| ..color = color | |
| ..blur = blur | |
| ..dx = offset.dx | |
| ..dy = offset.dy; | |
| } | |
| } | |
| // Custom render object class for inner shadow effect | |
| class _RenderInnerShadow extends RenderProxyBox { | |
| double blur = 5; // Default blur for shadow | |
| Color color = Color(0xFFF15923); // Default color for shadow | |
| double dx = 5; // Default x-axis translation for shadow | |
| double dy = 5; // Default y-axis translation for shadow | |
| @override | |
| void paint(PaintingContext context, Offset offset) { | |
| // Ensure there is a child to paint | |
| if (child == null) return; | |
| // Calculate the outer and inner bounds of the shadow | |
| final Rect outerRect = offset & size; | |
| final Rect innerRect = | |
| outerRect.deflate(blur); // Adjust the inner rect for shadow | |
| final Canvas canvas = context.canvas; | |
| // Draw the child widget | |
| canvas.saveLayer(outerRect, Paint()); | |
| context.paintChild(child!, offset); | |
| // Create the paint for the shadow layer | |
| final Paint shadowPaint = Paint() | |
| ..blendMode = BlendMode.srcATop // Apply the shadow over the widget | |
| ..colorFilter = | |
| ColorFilter.mode(color, BlendMode.srcOut) // Set shadow color | |
| ..imageFilter = | |
| ImageFilter.blur(sigmaX: blur, sigmaY: blur); // Apply blur | |
| // Draw the shadow layer on the canvas | |
| canvas.saveLayer(outerRect, shadowPaint); | |
| context.paintChild(child!, offset); | |
| // Restore the canvas stack | |
| canvas.restore(); | |
| canvas.restore(); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment