Skip to content

Instantly share code, notes, and snippets.

@pga61
Forked from liyuqian/main.dart
Created May 29, 2022 12:24
Show Gist options
  • Select an option

  • Save pga61/899f9cefa6da369b8e35344bcf29748d to your computer and use it in GitHub Desktop.

Select an option

Save pga61/899f9cefa6da369b8e35344bcf29748d to your computer and use it in GitHub Desktop.
TightClipper to avoid some AA artifacts
import 'package:flutter/material.dart';
void main() {
runApp(IssueDemoApp());
}
class IssueDemoApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.indigo,
scaffoldBackgroundColor: Colors.grey[100],
buttonTheme: ButtonThemeData(
colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.indigo),
textTheme: ButtonTextTheme.primary,
),
),
debugShowCheckedModeBanner: false,
home: ClipRectIssueDemo(),
);
}
}
class ClipRectIssueDemo extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _ClipRectIssueDemoState();
}
}
class _ClipRectIssueDemoState extends State<ClipRectIssueDemo> {
bool _clipRectOn = false;
double _width = 219.0;
@override
Widget build(BuildContext context) {
final double pixelRatio = MediaQuery.of(context).devicePixelRatio;
return Scaffold(
appBar: AppBar(
title: const Text('ClipRect Issue Demo'),
centerTitle: true,
elevation: 0,
),
body: SingleChildScrollView(
child: Column(
children: [
// And then some gap space too
const SizedBox(height: 20),
Text('ClipRect over Container with BoxShadow (pixel ratio: $pixelRatio)',
style: Theme.of(context).textTheme.headline6),
const SizedBox(height: 20),
SizedBox(
width: 420,
height: 420,
child: Center(
child: SizedBox(
height: _width,
width: _width,
child: ClipRectDecoratedContainer(clipRectOn: _clipRectOn),
),
),
),
const SizedBox(height: 10),
Center(
child: SizedBox(
width: 450,
child: SwitchListTile(
title: const Text('ClipRect ON/OFF'),
subtitle: const Text(
'Turn on ClipRect to see edge remnants. \nIf you resize '
'window/media size or change container size, you can observe the edge '
'remnants appearing and dissapearing at different sizes.'),
value: _clipRectOn,
onChanged: (value) {
setState(() {
_clipRectOn = value;
});
},
),
),
),
const SizedBox(height: 10),
Center(
child: SizedBox(
width: 450,
child: ListTile(
title: const Text('Change Container size'),
subtitle: Slider(
min: 100.0,
max: 400.0,
divisions: (400 - 100).floor(),
label: _width.floor().toString(),
value: _width,
onChanged: (value) {
setState(() {
_width = value;
});
},
),
trailing: Padding(
padding: const EdgeInsets.only(right: 12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
const Text(
'Width',
style: TextStyle(fontSize: 11),
),
Text(
_width.floor().toString(),
style: const TextStyle(fontSize: 15),
),
],
),
),
),
),
),
],
),
),
);
}
}
class ClipRectDecoratedContainer extends StatelessWidget {
const ClipRectDecoratedContainer({
Key key,
this.clipRectOn = false,
}) : super(key: key);
final bool clipRectOn;
@override
Widget build(BuildContext context) {
if (clipRectOn) {
return ClipRect(
clipBehavior: Clip.hardEdge,
clipper: TightClipper(MediaQuery.of(context).devicePixelRatio),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.red[900],
blurRadius: 25.0,
)
],
),
),
);
} else {
return Container(
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.red[900],
blurRadius: 25.0,
)
],
),
);
}
}
}
class TightClipper extends CustomClipper<Rect> {
TightClipper(this.devicePixelRatio, {this.tightFactor = 1});
@override
Rect getClip(Size size) {
final double padding = 1 / devicePixelRatio * tightFactor;
return Rect.fromLTRB(
padding,
padding,
size.width - padding,
size.height - padding,
);
}
@override
bool shouldReclip(CustomClipper<Rect> oldClipper) {
return true;
}
final double devicePixelRatio;
final double tightFactor;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment