Skip to content

Instantly share code, notes, and snippets.

@codebk1
Created September 7, 2023 09:03
Show Gist options
  • Save codebk1/b53d756106fba714988b8b0413ada632 to your computer and use it in GitHub Desktop.
Save codebk1/b53d756106fba714988b8b0413ada632 to your computer and use it in GitHub Desktop.
Flutter Text Glitch Effect
import 'package:flutter/material.dart';
void main() {
runApp(const GlitchApp());
}
class GlitchApp extends StatelessWidget {
const GlitchApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Color.fromARGB(255, 0, 0, 0),
body: Center(
child: Glitch(
text: 'GLITCH',
textStyle: TextStyle(
color: Color.fromARGB(255, 255, 255, 255),
fontSize: 100,
),
),
),
),
);
}
}
class Glitch extends StatefulWidget {
const Glitch({
super.key,
required this.text,
this.textStyle,
this.stacks = 3,
this.duration = const Duration(milliseconds: 100),
this.delay = const Duration(milliseconds: 1500),
this.glitchColor1 = const Color.fromARGB(255, 255, 0, 0),
this.glitchColor2 = const Color.fromARGB(255, 0, 0, 255),
});
final String text;
final TextStyle? textStyle;
final int stacks;
final Duration duration;
final Duration delay;
final Color glitchColor1;
final Color glitchColor2;
@override
State<Glitch> createState() => _GlitchState();
}
class _GlitchState extends State<Glitch> with SingleTickerProviderStateMixin {
@override
Widget build(BuildContext context) {
return _Glitch(
text: widget.text,
textStyle: widget.textStyle,
stacks: widget.stacks,
duration: widget.duration,
delay: widget.delay,
glitchColor1: widget.glitchColor1,
glitchColor2: widget.glitchColor2,
vsync: this,
);
}
}
class _Glitch extends LeafRenderObjectWidget {
const _Glitch({
required this.text,
this.textStyle,
required this.stacks,
required this.duration,
required this.delay,
required this.glitchColor1,
required this.glitchColor2,
required this.vsync,
});
final String text;
final TextStyle? textStyle;
final int stacks;
final Duration duration;
final Duration delay;
final Color glitchColor1;
final Color glitchColor2;
final TickerProvider vsync;
@override
RenderGlitch createRenderObject(BuildContext context) {
return RenderGlitch(
text: text,
textStyle: textStyle ?? DefaultTextStyle.of(context).style,
stacks: stacks,
duration: duration,
delay: delay,
glitchColor1: glitchColor1,
glitchColor2: glitchColor2,
vsync: vsync,
);
}
@override
void updateRenderObject(
BuildContext context,
RenderGlitch renderObject,
) {
renderObject
..text = text
..textStyle = textStyle ?? DefaultTextStyle.of(context).style
..stacks = stacks
..duration = duration
..delay = delay
..glitchColor1 = glitchColor1
..glitchColor2 = glitchColor2
..vsync = vsync;
}
}
class RenderGlitch extends RenderBox {
RenderGlitch({
required String text,
required TextStyle textStyle,
required int stacks,
required Duration duration,
required Duration delay,
required Color glitchColor1,
required Color glitchColor2,
required TickerProvider vsync,
}) : assert(delay.inMilliseconds >= 2 * duration.inMilliseconds),
_text = text,
_textStyle = textStyle,
_stacks = stacks,
_duration = duration,
_delay = delay,
_glitchColor1 = glitchColor1,
_glitchColor2 = glitchColor2,
_vsync = vsync {
_controller = AnimationController(
vsync: _vsync,
duration: _duration,
)
..forward()
..addListener(() {
final value = _controller.value;
textPainter = TextPainter(
text: TextSpan(
text: _text,
style: _textStyle.merge(
TextStyle(
height: 1,
shadows: [
Shadow(
color: _glitchColor1,
offset: Offset(value * -1, value * 2),
),
Shadow(
color: _glitchColor2,
offset: Offset(value * 1, value * -2),
),
],
),
),
),
textDirection: TextDirection.ltr,
);
if (_controller.isCompleted) {
_controller.reverse();
Future.delayed(_delay, () {
_controller.forward();
});
}
});
_animation = Tween<Offset>(
begin: Offset.zero,
end: const Offset(2, 0),
).animate(
CurvedAnimation(
parent: _controller,
curve: Curves.elasticOut,
),
);
_textPainter = TextPainter(
text: TextSpan(
text: _text,
style: _textStyle,
),
textDirection: TextDirection.ltr,
);
}
late final AnimationController _controller;
late final Animation _animation;
late TextPainter _textPainter;
TextPainter get textPainter => _textPainter;
set textPainter(TextPainter value) {
if (value == _textPainter) return;
_textPainter = value;
markNeedsLayout();
}
late String _text;
String get text => _text;
set text(String value) {
if (value == _text) return;
_text = value;
markNeedsLayout();
}
late TextStyle _textStyle;
TextStyle get textStyle => _textStyle;
set textStyle(TextStyle value) {
if (value == _textStyle) return;
_textStyle = value;
markNeedsPaint();
}
int _stacks;
int get stacks => _stacks;
set stacks(int value) {
if (value == _stacks) return;
_stacks = value;
markNeedsPaint();
}
Duration _duration;
Duration get duration => _duration;
set duration(Duration value) {
if (value == _duration) return;
_duration = value;
}
Duration _delay;
Duration get delay => _delay;
set delay(Duration value) {
if (value == _delay) return;
_delay = value;
}
Color _glitchColor1;
Color get glitchColor1 => _glitchColor1;
set glitchColor1(Color value) {
if (value == _glitchColor1) return;
_glitchColor1 = value;
}
Color _glitchColor2;
Color get glitchColor2 => _glitchColor2;
set glitchColor2(Color value) {
if (value == _glitchColor2) return;
_glitchColor2 = value;
}
TickerProvider _vsync;
TickerProvider get vsync => _vsync;
set vsync(TickerProvider value) {
if (value == _vsync) return;
_vsync = value;
_controller.resync(vsync);
}
@override
void detach() {
_controller.stop();
super.detach();
}
@override
void performLayout() {
_textPainter.layout();
size = Size(_textPainter.width, _textPainter.height);
}
@override
bool get isRepaintBoundary => true;
@override
void paint(PaintingContext context, Offset offset) {
final canvas = context.canvas;
final height = _textPainter.height / _stacks;
for (var i = 0; i < _stacks; i++) {
canvas.save();
canvas.clipRect(
Rect.fromLTRB(0, height * i - 0.5, size.width, height * (i + 1) + 0.5),
);
_textPainter.paint(
canvas,
i.isEven ? -_animation.value : _animation.value,
);
canvas.restore();
}
}
}
@codebk1
Copy link
Author

codebk1 commented Sep 7, 2023

glitch

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