Skip to content

Instantly share code, notes, and snippets.

@mhadaily
Last active August 14, 2020 13:17
Show Gist options
  • Save mhadaily/90b1ec6cc9d71aee929f6112be58f6a2 to your computer and use it in GitHub Desktop.
Save mhadaily/90b1ec6cc9d71aee929f6112be58f6a2 to your computer and use it in GitHub Desktop.

RepaintBoundary artificially pretends that the child needs its own composited layer which means the effects in sub-tree are then contained. This is a great tip to improve performance in Flutter boosting to 60 FPS.

check in action: https://codepen.io/mhadaily/pen/ZEWWEKp

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

void main() {
  // debugRepaintRainbowEnabled = true;
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      themeMode: ThemeMode.dark,
      darkTheme: ThemeData.dark(),
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter RepaintBountery Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
  int _counter = 0;
  bool isRepaintBoundary;

  @override
  void initState() {
    isRepaintBoundary = false;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    String prefix = isRepaintBoundary ? "With" : "Without";
    return Scaffold(
      body: Stack(
        fit: StackFit.expand,
        children: [
          isRepaintBoundary
              ? RepaintBoundary(
                  child: CustomPaint(
                    painter: ExpensiveBackground(),
                  ),
                )
              : CustomPaint(
                  painter: ExpensiveBackground(),
                ),
          Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                '$_counter',
                style: TextStyle(fontSize: 40),
              ),
              Padding(
                padding: EdgeInsets.all(10),
                child: Text(
                  '$prefix RepaintBoundry',
                  style: TextStyle(
                    fontWeight: FontWeight.bold,
                  ),
                ),
              ),
              SizedBox(
                height: 50,
              ),
              OutlineButton(
                onPressed: () {
                  setState(() {
                    isRepaintBoundary = !isRepaintBoundary;
                  });
                },
                child: Text(
                  'Toggle RepaintBoundry',
                  style: TextStyle(
                    fontWeight: FontWeight.bold,
                  ),
                ),
              ),
            ],
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        backgroundColor: Colors.red,
        onPressed: () {
          setState(() {
            _counter++;
          });
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }

  @override
  void dispose() {
    super.dispose();
  }
}

class ExpensiveBackground extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    double width = size.width;
    double height = size.height;
    final starCount = (width + height) / 8;
    for (int i = 0; i < starCount; i++) {
      final x = Random().nextInt(width.toInt()).toDouble();
      final y = Random().nextInt(height.toInt()).toDouble();

      canvas.drawCircle(
        Offset(x, y),
        2,
        Paint()..color = Colors.primaries[i % Colors.primaries.length].withOpacity(0.5),
      );
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => false;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment