Skip to content

Instantly share code, notes, and snippets.

@liyuqian
Created June 6, 2020 18:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save liyuqian/65680f25573bb4339030ddecaf236232 to your computer and use it in GitHub Desktop.
Save liyuqian/65680f25573bb4339030ddecaf236232 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;
}
@goderbauer
Copy link

In line 189: I would expect that you only need to reclip if the provided oldClipper has a different runtime type or if devicePixelRatio / tightFactor have changed.

@liyuqian
Copy link
Author

Ah yes. I'll revise this quick hack if we're going to put this piece of code in our doc, or code base.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment