Corner Decoration In Flutter

Corner Decoration In Flutter :

Screenshot :

Corner Decoration In Flutter

main.dart

import 'package:flutter/material.dart';

import 'demo_grid.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Scaffold(
            backgroundColor: const Color(0xfff0f0f0),
            body: ScrollConfiguration(
              behavior: const DisableOverScroll(),
              child: SafeArea(child: DemoGrid()),
            )));
  }
}

class DisableOverScroll extends ScrollBehavior {
  const DisableOverScroll();

  @override
  Widget buildViewportChrome(BuildContext context, Widget child, AxisDirection axisDirection) => child;
}

demo_grid.dart

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

class DemoGrid extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GridView.count(
        physics: const BouncingScrollPhysics(),
        padding: const EdgeInsets.fromLTRB(4, 8, 4, 8),
        crossAxisCount: 3,
        children: <Widget>[
          Card(
              child: Container(
                  padding: const EdgeInsets.all(12),
                  child: const Text('Apply badge colors and font styles'),
                  foregroundDecoration: const RotatedCornerDecoration(
                      color: Colors.blueGrey,
                      geometry: const BadgeGeometry(width: 48, height: 48),
                      textSpan: const TextSpan(
                          text: 'OMG',
                          style: TextStyle(
                            fontSize: 10,
                            letterSpacing: 1,
                            fontWeight: FontWeight.bold,
                            shadows: [
                              BoxShadow(
                                  color: Colors.yellowAccent, blurRadius: 4)
                            ],
                          ))))),
          Padding(
              padding: const EdgeInsets.all(4),
              child: Material(
                  elevation: 1,
                  child: Container(
                      padding: const EdgeInsets.all(12),
                      decoration: BoxDecoration(
                        color: Colors.white,
//              boxShadow: [BoxShadow(color: Colors.black26)],
                      ),
                      child: const Text('cornerRadius=0',
                          style: TextStyle(fontSize: 12)),
                      foregroundDecoration: const RotatedCornerDecoration(
                        color: Colors.redAccent,
                        geometry: const BadgeGeometry(
                            width: 30, height: 30, cornerRadius: 0),
                      )))),
          Card(
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(16),
              ),
              child: Container(
                  padding: const EdgeInsets.all(12),
                  child: const Text('cornerRadius=16',
                      style: TextStyle(fontSize: 12)),
                  foregroundDecoration: const RotatedCornerDecoration(
                    color: Colors.redAccent,
                    geometry: const BadgeGeometry(
                        width: 32, height: 32, cornerRadius: 16),
                  ))),
          Card(
            child: Container(
              padding: const EdgeInsets.all(12),
              alignment: Alignment.bottomLeft,
              foregroundDecoration: const RotatedCornerDecoration(
                color: Colors.green,
                geometry: const BadgeGeometry(width: 90, height: 90),
                textSpan: const TextSpan(
                  text: 'DEFAULT',
                  style: TextStyle(fontSize: 10, backgroundColor: Colors.black),
                ),
              ),
              child: const Text('By default baselineShift=1'),
            ),
          ),
          Card(
              child: Container(
            padding: const EdgeInsets.all(12),
            alignment: Alignment.bottomLeft,
            foregroundDecoration: const RotatedCornerDecoration(
              color: Colors.green,
              geometry: const BadgeGeometry(width: 90, height: 90),
              textSpan: const TextSpan(
                text: 'BASELINE SHIFT 0',
                style: TextStyle(fontSize: 10, backgroundColor: Colors.black),
              ),
              labelInsets: const LabelInsets(baselineShift: 0),
            ),
            child: const Text('But it can be changed'),
          )),
          Card(
              child: Container(
                  foregroundDecoration: const RotatedCornerDecoration(
            color: Colors.green,
            geometry: const BadgeGeometry(width: 90, height: 90),
            textSpan: const TextSpan(
              text: 'BASELINE SHIFT 3',
              style: TextStyle(fontSize: 10, backgroundColor: Colors.black),
            ),
            labelInsets: const LabelInsets(baselineShift: 3),
          ))),
          Card(
              child: Container(
                  foregroundDecoration: const RotatedCornerDecoration(
                      color: Colors.blue,
                      geometry: const BadgeGeometry(width: 64, height: 64),
                      textSpan: const TextSpan(
                        text: 'Multiline\nbadge',
                        style: TextStyle(fontSize: 10),
                      )))),
          Card(
              child: Container(
                  padding: const EdgeInsets.all(12),
                  child: const Text('Just empty badge on foreground',
                      style: TextStyle(fontSize: 12)),
                  foregroundDecoration: const RotatedCornerDecoration(
                    color: Colors.purpleAccent,
                    geometry: const BadgeGeometry(width: 48, height: 48),
                  ))),
          Card(
              child: Container(
                  padding: const EdgeInsets.all(12),
                  child: const Text('Just empty badge on background',
                      style: TextStyle(fontSize: 12)),
                  decoration: const RotatedCornerDecoration(
                    color: Colors.orange,
                    geometry: const BadgeGeometry(width: 48, height: 48),
                  ))),
          Card(
              child: Container(
                  padding: const EdgeInsets.all(12),
                  alignment: Alignment.bottomLeft,
                  child: const Text('Text Span Example'),
                  foregroundDecoration: const RotatedCornerDecoration(
                    color: Colors.black87,
                    geometry: const BadgeGeometry(width: 64, height: 64),
                    textSpan: const TextSpan(children: [
                      TextSpan(
                        text: 'LOREM\n',
                        style: TextStyle(
                            fontSize: 10,
                            fontWeight: FontWeight.bold,
                            color: Colors.redAccent),
                      ),
                      TextSpan(
                        text: 'IPSUM',
                        style: TextStyle(
                            fontSize: 7,
                            fontStyle: FontStyle.italic,
                            letterSpacing: 5,
                            color: Colors.yellow),
                      )
                    ]),
                    labelInsets: const LabelInsets(baselineShift: 2),
                  ))),
          Card(
              child: Container(
                  padding: const EdgeInsets.all(12),
                  alignment: Alignment.bottomLeft,
                  foregroundDecoration: const RotatedCornerDecoration(
                      color: Colors.brown,
                      geometry: const BadgeGeometry(width: 120, height: 50),
                      textSpan: const TextSpan(
                        text: 'WEIRD BADGE',
                        style: TextStyle(fontSize: 10),
                      )))),
          Card(
              child: Container(
                  padding: const EdgeInsets.all(12),
                  alignment: Alignment.bottomLeft,
                  child: const Text(
                    'Extra space before text OR after.\nNot both!\n\nlabel inset start=8',
                    style: TextStyle(fontSize: 12),
                  ),
                  foregroundDecoration: const RotatedCornerDecoration(
                    color: Colors.blueGrey,
                    geometry: const BadgeGeometry(width: 48, height: 48),
                    textSpan: const TextSpan(
                        text: 'WOW', style: TextStyle(fontSize: 10)),
                    labelInsets: const LabelInsets(start: 8),
                  ))),
          Card(
              child: Container(
                  padding: const EdgeInsets.all(12),
                  alignment: Alignment.bottomLeft,
                  child: const Text('Apply any gradients instead of colors '),
                  foregroundDecoration: const RotatedCornerDecoration(
                    gradient: LinearGradient(
                      begin: Alignment.topRight,
                      end: Alignment.bottomLeft,
                      stops: [0, 0.6],
                      colors: [Colors.blue, Colors.greenAccent],
                    ),
                    geometry: const BadgeGeometry(width: 48, height: 48),
                    labelInsets: const LabelInsets(baselineShift: 2),
                  ))),
          Card(
              child: Container(
                  foregroundDecoration: const RotatedCornerDecoration(
            gradient: LinearGradient(
              begin: Alignment.topLeft,
              end: Alignment.topRight,
              colors: [Colors.purpleAccent, Colors.blue],
            ),
            geometry: const BadgeGeometry(width: 48, height: 48),
          ))),
          Card(
              child: Container(
                  foregroundDecoration: RotatedCornerDecoration(
            gradient: RadialGradient(
              center: Alignment.topRight,
              radius: 1.5,
              stops: [0.1, 0.5],
              colors: [Colors.redAccent, Colors.redAccent.withAlpha(0)],
            ),
            geometry: const BadgeGeometry(width: 48, height: 48),
          ))),
          Card(
              child: Container(
            padding: const EdgeInsets.all(12),
            alignment: Alignment.bottomLeft,
            child: const Text('Add shadow with color and elevation'),
            foregroundDecoration: const RotatedCornerDecoration(
                color: Colors.yellow,
                geometry: const BadgeGeometry(width: 48, height: 48),
                badgeShadow:
                    const BadgeShadow(color: Colors.black87, elevation: 1.5)),
          )),
          Card(
              child: Container(
                  padding: const EdgeInsets.all(12),
                  alignment: Alignment.bottomRight,
                  child: const Text('Apply badge alignment',
                      textAlign: TextAlign.end),
                  foregroundDecoration: const RotatedCornerDecoration(
                    color: Colors.teal,
                    geometry: const BadgeGeometry(
                        width: 48,
                        height: 48,
                        alignment: BadgeAlignment.bottomLeft),
                    textSpan: TextSpan(
                        text: 'o, rly?',
                        style: TextStyle(fontSize: 10, letterSpacing: 0.5)),
                    labelInsets: LabelInsets(baselineShift: 3),
                  ))),
          Card(
              child: Container(
                  foregroundDecoration: const RotatedCornerDecoration(
            color: Colors.lightGreen,
            geometry: const BadgeGeometry(
                width: 48, height: 48, alignment: BadgeAlignment.bottomRight),
            textSpan: TextSpan(text: 'WHY?', style: TextStyle(fontSize: 12)),
            labelInsets: LabelInsets(baselineShift: 3, start: 1),
          ))),
          Card(
              child: Container(
                  foregroundDecoration: const RotatedCornerDecoration(
            color: Colors.pinkAccent,
            geometry: const BadgeGeometry(
                width: 48, height: 48, alignment: BadgeAlignment.topLeft),
            textSpan: TextSpan(text: 'OK', style: TextStyle(fontSize: 12)),
            labelInsets: LabelInsets(baselineShift: 3, start: 1),
          )))
        ]);
  }
}

rotated_corner_decoration.dart

library rotated_corner_decoration;

import 'dart:math' as math;
import 'package:flutter/material.dart';

class RotatedCornerDecoration extends Decoration {
  final BadgeGeometry _geometry;
  final Color _color;
  final Gradient _gradient;
  final TextSpan _textSpan;
  final LabelInsets _insets;
  final BadgeShadow _shadow;

  const RotatedCornerDecoration({
    @required BadgeGeometry geometry,
    Color color,
    Gradient gradient,
    TextSpan textSpan,
    LabelInsets labelInsets,
    BadgeShadow badgeShadow,
  })  : assert(geometry != null),
        assert((color != null && gradient == null) || (color == null && gradient != null)),
        _geometry = geometry,
        _color = color,
        _gradient = gradient,
        _textSpan = textSpan,
        _insets = labelInsets ?? const LabelInsets(),
        _shadow = badgeShadow;

  @override
  BoxPainter createBoxPainter([onChanged]) {
    return _BadgePainter(_geometry, _color, _gradient, _textSpan, _insets, _shadow);
  }
}

class _BadgePainter extends BoxPainter {
  final BadgeGeometry _geometry;
  final Color _color;
  final Gradient _gradient;
  final TextSpan _textSpan;
  final LabelInsets _insets;
  final BadgeShadow _shadow;

  const _BadgePainter(this._geometry, this._color, this._gradient, this._textSpan, this._insets, this._shadow);

  @override
  void paint(Canvas canvas, Offset offset, ImageConfiguration cfg) {
    canvas.clipRRect(_geometry._createRRect(offset, cfg.size.width, cfg.size.height));
    canvas.save();
    final Offset pathOffset = _geometry._calcPathOffset(offset, cfg.size.width, cfg.size.height);
    canvas.translate(pathOffset.dx, pathOffset.dy);
    final Path path = _geometry._createPath();
    if (_shadow != null) {
      canvas.drawShadow(path, _shadow.color, _shadow.elevation, false);
    }
    canvas.drawPath(path, _badgePaint);

    // shift and rotate canvas, draw text
    if (_textSpan != null) {
      final textPainter = _createTextPainter();
      final textTranslate = _geometry._calcTextTranslate(textPainter, _insets);
      canvas.translate(textTranslate.dx, textTranslate.dy);
      canvas.rotate(_geometry._calcAngle());
      textPainter.paint(canvas, _insets._createTextOffset());
    }
    canvas.restore();
  }

  Paint get _badgePaint {
    final Paint paint = Paint();
    if (_color != null) {
      paint.color = _color;
    } else {
      paint.shader = _gradient.createShader(Rect.fromLTWH(0, 0, _geometry.width, _geometry.height));
    }
    return paint..isAntiAlias = true;
  }

  TextPainter _createTextPainter() {
    final hypo = _calcHypo(_geometry.width, _geometry.height);
    return TextPainter(
      text: _textSpan,
      textDirection: TextDirection.ltr,
      textAlign: TextAlign.center,
    )..layout(minWidth: hypo, maxWidth: hypo);
  }
}

class BadgeShadow {
  final Color color;
  final double elevation;

  const BadgeShadow({this.color, this.elevation})
      : assert(color != null),
        assert(elevation != null && elevation > 0);
}

class BadgeGeometry {
  final double width;
  final double height;
  final double cornerRadius;
  final BadgeAlignment alignment;

  const BadgeGeometry({
    @required this.width,
    @required this.height,
    this.cornerRadius = 4,
    this.alignment = BadgeAlignment.topRight,
  })  : assert(width != null && width > 0),
        assert(height != null && height > 0),
        assert(alignment != null),
        assert(cornerRadius != null && cornerRadius >= 0);

  RRect _createRRect(Offset offset, double w, double h) {
    final radius = Radius.circular(cornerRadius);
    return RRect.fromLTRBR(offset.dx, offset.dy, offset.dx + w, offset.dy + h, radius);
  }

  Offset _calcPathOffset(Offset offset, double w, double h) {
    switch (alignment) {
      case BadgeAlignment.bottomLeft:
        return Offset(offset.dx, offset.dy + h - this.height);
      case BadgeAlignment.bottomRight:
        return Offset(offset.dx + w - this.width, offset.dy + h);
      case BadgeAlignment.topLeft:
        return Offset(offset.dx, offset.dy + height);
      default:
        return Offset(offset.dx + w - this.width, offset.dy);
    }
  }

  Offset _calcTextTranslate(TextPainter painter, LabelInsets insets) {
    switch (alignment) {
      case BadgeAlignment.bottomLeft:
        final v = math.sqrt((insets.baselineShift * insets.baselineShift) / 2);
        final textShift = -1 * _calcHypo(v, v);
        return Offset(textShift, -textShift);
      case BadgeAlignment.bottomRight:
        final v = math.sqrt((insets.baselineShift * insets.baselineShift) / 2);
        final textShift = _calcHypo(v, v);
        return Offset(textShift, textShift);
      case BadgeAlignment.topLeft:
        final v = painter.height / 2 + math.sqrt((insets.baselineShift * insets.baselineShift) / 2);
        final textShift = _calcHypo(v, v);
        return Offset(-textShift, -textShift);
      default:
        final v = painter.height / 2 + math.sqrt((insets.baselineShift * insets.baselineShift) / 2);
        final textShift = _calcHypo(v, v);
        return Offset(textShift, -textShift);
    }
  }

  Path _createPath() {
    switch (alignment) {
      case BadgeAlignment.bottomLeft:
        return Path()
          ..lineTo(0, height)
          ..lineTo(width, height)
          ..close();
      case BadgeAlignment.bottomRight:
        return Path()
          ..lineTo(width, 0)
          ..lineTo(width, -height)
          ..close();
      case BadgeAlignment.topLeft:
        return Path()
          ..lineTo(width, -height)
          ..lineTo(0, -height)
          ..close();
      default:
        return Path()
          ..lineTo(width, 0)
          ..lineTo(width, height)
          ..close();
    }
  }

  double _calcAngle() {
    switch (alignment) {
      case BadgeAlignment.bottomLeft:
        return math.atan2(height, width);
      case BadgeAlignment.bottomRight:
        return -math.atan2(height, width);
      case BadgeAlignment.topLeft:
        return -math.atan2(height, width);
      default:
        return math.atan2(height, width);
    }
  }
}

class LabelInsets {
  final double baselineShift;
  final double start;
  final double end;

  const LabelInsets({
    this.baselineShift = 1,
    this.start,
    this.end,
  })  : assert(baselineShift != null && baselineShift >= 0),
        assert((start == null && end == null) ||
            (start != null && start > 0 && end == null) ||
            (end != null && end > 0 && start == null));

  Offset _createTextOffset() {
    return Offset(start == null && end == null ? 0 : start != null ? start : -end, 0);
  }
}

double _calcHypo(double w, double h) => math.sqrt(w * w + h * h);

enum BadgeAlignment { topLeft, topRight, bottomLeft, bottomRight }

The flutter tutorial  is a website that bring you the latest and amazing resources of code. All the languages codes are included in this website. The languages like flutter, android, java,kotlin etc.with the help of this languages any user can develop the beautiful application

For more information about Flutter. visit www.fluttertutorial.in