Floating Ribbon In Flutter

Floating Ribbon In Flutter :

Floating Ribbon In Flutter : This flutter tutorial post is new item indicator, student rank display etc.

FloatingRibbon custom widget
1) ribbonSwatch: Colors.black.withOpacity(0.1)
2) ribbonShadowSwatch: Colors.black.withOpacity(0.1)
3) shadowHeight: 5

Screenshot :

Floating Ribbon In Flutter

main.dart

import 'package:flutter/material.dart';

import 'floating_ribbon.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Tutorial',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
      debugShowMaterialGrid: false,
      debugShowCheckedModeBanner: false,
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  List<String> _hotels = [
    'Flutter',
    'React Native',
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey[200],
      appBar: AppBar(
        title: Text('Floating Ribbon'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          children: <Widget>[
            Container(
              color: Colors.white,
              height: 40,
              width: MediaQuery.of(context).size.width,
              child: Center(
                child: Text(
                  'clipper right',
                  style: TextStyle(
                    color: Colors.black54,
                    fontSize: 20,
                  ),
                  textAlign: TextAlign.center,
                ),
              ),
            ),
            ListView(
              shrinkWrap: true,
              children: <Widget>[
                restaurantListTile(_hotels.elementAt(0), true),
                restaurantListTile(_hotels.elementAt(1), true),
              ],
            ),
            Container(
              color: Colors.white,
              height: 40,
              width: MediaQuery.of(context).size.width,
              child: Center(
                child: Text(
                  'clipper equilateral',
                  style: TextStyle(
                    color: Colors.black54,
                    fontSize: 20,
                  ),
                  textAlign: TextAlign.center,
                ),
              ),
            ),
            ListView(
              shrinkWrap: true,
              children: <Widget>[
                restaurantListTile(_hotels.elementAt(0), false),
                restaurantListTile(_hotels.elementAt(1), false),
              ],
            ),
          ],
        ),
      ),
    );
  }

  Widget restaurantListTile(String hotel, bool isRight) {
    double width = MediaQuery.of(context).size.width;
    width = width * 0.30;

    return Container(
      decoration: BoxDecoration(
        borderRadius: BorderRadius.all(
          Radius.circular(10.0),
        ),
        color: Colors.white70,
      ),
      margin: EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
      child: Container(
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            FloatingRibbon(
              ribbonSwatch: Colors.black.withOpacity(0.1),
              ribbonShadowSwatch: Colors.black.withOpacity(0.1),
              height: 85,
              width: 85,
              childHeight: 75,
              childWidth: 75,
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: FlutterLogo(),
              ),
              childDecoration: BoxDecoration(color: Colors.white),
              ribbon: Center(
                child: Text(
                  'Exclusive',
                  style: TextStyle(
                    color: Colors.orange,
                  ),
                  textAlign: TextAlign.center,
                ),
              ),
              clipper: isRight ? Clipper.right : Clipper.equilateral,
              equilateralTriangleWidth: isRight ? null : 5,
              shadowHeight: 5,
            ),
            Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.max,
              children: <Widget>[
                Padding(
                  padding: const EdgeInsets.only(left: 15.0, bottom: 5.0),
                  child: Container(
                    width: MediaQuery.of(context).size.width * 0.6,
                    child: Text(
                      hotel,
                      style: TextStyle(
                        color: Colors.black,
                        fontSize: 15,
                        fontWeight: FontWeight.bold,
                      ),
                      maxLines: 3,
                    ),
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.only(left: 15.0),
                  child: Row(
                    children: <Widget>[
                      Padding(
                        padding: const EdgeInsets.only(right: 5.0),
                        child: Icon(Icons.access_alarms,
                            color: Colors.black54, size: 20),
                      ),
                      Padding(
                        padding: const EdgeInsets.only(top: 2.5),
                        child: Text(
                          "30 min",
                          style: TextStyle(
                            color: Colors.black45,
                            fontSize: 13,
                            fontWeight: FontWeight.w700,
                          ),
                        ),
                      ),
                      Padding(
                        padding: const EdgeInsets.only(
                          left: 5.0,
                          right: 5.0,
                          top: 3.0,
                        ),
                        child: Icon(
                          Icons.fiber_manual_record,
                          color: Colors.black54,
                          size: 8.0,
                        ),
                      ),
                      Padding(
                        padding: const EdgeInsets.only(top: 3.5),
                        child: Text(
                          'Open',
                          style: TextStyle(
                            color: Colors.green,
                            fontWeight: FontWeight.w700,
                            fontSize: 13,
                          ),
                        ),
                      ),
                      Padding(
                        padding: const EdgeInsets.only(
                            left: 5.0, right: 5.0, top: 3.0),
                        child: Icon(Icons.fiber_manual_record,
                            color: Colors.black54, size: 8.0),
                      ),
                      Padding(
                        padding: const EdgeInsets.only(top: 3.0),
                        child: Text(
                          '\$\$',
                          style: TextStyle(
                            color: Colors.black54,
                            fontSize: 13,
                            fontWeight: FontWeight.w900,
                          ),
                        ),
                      )
                    ],
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

floating_ribbon.dart

library floating_ribbon;
import 'package:flutter/material.dart';

import 'equilateral_triangle.dart';
import 'right_triangle.dart';

enum Clipper {
  right,
  equilateral,
}

class FloatingRibbon extends StatelessWidget {
  FloatingRibbon({
    Key key,
    @required this.height,
    @required this.width,
    @required this.childHeight,
    @required this.childWidth,
    @required this.child,
    this.childDecoration,
    this.ribbon,
    this.ribbonHeight = 20,
    this.clipper = Clipper.right,
    this.ribbonSwatch = Colors.redAccent,
    this.ribbonShadowSwatch = Colors.red,
    this.shadowHeight,
    this.equilateralTriangleWidth = 5,
  })  : assert(ribbon != null,
            'A non-null child Widget must be provided to a FloatingRibbon widget.'),
        super(key: key);

  /// [height] defines the height of the box occupied by its children.
  ///
  /// Note: [height] >= [childHeight].
  final double height;

  /// [width] defines the width of the box occupied by its children.
  ///
  /// Note: Make sure your [width] > [childWidth] in order to get better results.
  final double width;

  /// [childHeight] defines the height of you [child] which is typically an
  /// Image Widget.
  ///
  /// Note: [childHeight] <= [height]
  final double childHeight;

  /// [childWidth] defines the width of you [child] which is typically an
  /// Image Widget.
  ///
  /// Note: [childWidth] < [width] always. This is because the ribbon width has
  ///       has to be more than the Image Widget width in order to give an
  ///       alluring effect to the ribbon shadow.
  final double childWidth;

  /// A widget renders the ribbon over [child] widget tree.
  /// [child] is the area occupied by the ribbon. You can build [child]
  /// from whatever [Widget] you like.
  ///
  /// * Suggested [child] ->
  ///   Image(
  ///     image: AssetImage('assets/image.png'),
  ///   ),
  final Widget child;

  /// [childDecoration] sets the decoration for its [child]
  ///
  /// Optional [childDecoration] for the child. If the child is an Image you can
  /// wrap it with [ClipRect], [ClipRRect], or [ClipPath] and set the decoration.
  final Decoration childDecoration;

  /// [ribbon] defines the child widget displayed on the ribbon.
  final Widget ribbon;

  /// If non-null, [clipper] defines what type of shadow you want.
  ///
  /// Default value for [clipper] is [Clipper.right].
  final Clipper clipper;

  /// If non-null, [ribbonHeight] defines the height of the image.
  ///
  /// Default value for the [ribbonHeight] is 20. Typically, this should be
  /// 1/4 of [childHeight].
  final double ribbonHeight;

  /// If non-null, [ribbonSwatch] defines the primary swatch for the ribbon.
  ///
  /// Default value for [ribbonSwatch] is Colors.redAccent. Note that the color
  /// should be lightened for the ribbon and darkened for the shadow to add
  /// a charming effect
  final Color ribbonSwatch;

  /// If non-null, [ribbonShadowSwatch] defines the primary swatch for the ribbon.
  ///
  /// Default value for [ribbonShadowSwatch] is Colors.red.
  final Color ribbonShadowSwatch;

  /// If non-null, [shadowHeight] defines the height of the shadow.
  ///
  /// [shadowHeight] defaults to 5 and is an optional parameter. Note that this
  /// is an extra height given to the shadow.
  ///
  /// The formula for shadow height is -> ([width] - [childWidth]) / 2 + [shadowHeight]
  final double shadowHeight;

  /// If non-null, [equilateralTriangleWidth] defines the width of the shadow.
  ///
  /// Note that this would only affect when [clipper] is set to [Clipper.equilateral].
  /// The formula for shadow width is -> ([width] - [childWidth]) / 2 + [equilateralTriangleWidth]
  ///
  /// [equilateralTriangleWidth] defaults to 5.
  final double equilateralTriangleWidth;

  @override
  Widget build(BuildContext context) {
    return Container(
      key: key,
      height: height,
      width: width,
      child: Stack(
        alignment: Alignment.center,
        children: <Widget>[
          Container(
            width: childWidth,
            height: childHeight,
            child: child,
            decoration: childDecoration,
          ),
          Positioned(
            top: childHeight * 0.1,
            child: Column(
              textDirection: TextDirection.ltr,
              children: <Widget>[
                Container(
                  width: width,
                  height: ribbonHeight,
                  color: ribbonSwatch,
                  child: Directionality(
                      textDirection: TextDirection.ltr, child: ribbon),
                ),
                Container(
                  width: width,
                  height: ribbonHeight,
                  child: Row(
                    textDirection: TextDirection.ltr,
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    mainAxisSize: MainAxisSize.max,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: _getShadow(),
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

  List<Widget> _getShadow() {
    if (clipper == Clipper.right) {
      return <Widget>[
        ClipPath(
          clipper: LeftTriangleClipper(),
          child: Container(
            height: (width - childWidth) / 2 + 5,
            width: (width - childWidth) / 2,
            color: ribbonShadowSwatch,
          ),
        ),
        ClipPath(
          clipper: RightTriangleClipper(),
          child: Container(
            height: (width - childWidth) / 2 + 5,
            width: (width - childWidth) / 2,
            color: ribbonShadowSwatch,
          ),
        ),
      ];
    } else {
      return <Widget>[
        ClipPath(
          clipper: EquilateralTriangleClipper(),
          child: Container(
            height: (width - childWidth) / 2 + shadowHeight,
            width: (width - childWidth) / 2 + equilateralTriangleWidth,
            color: ribbonShadowSwatch,
          ),
        ),
        ClipPath(
          clipper: EquilateralTriangleClipper(),
          child: Container(
            height: (width - childWidth) / 2 + shadowHeight,
            width: (width - childWidth) / 2 + equilateralTriangleWidth,
            color: ribbonShadowSwatch,
          ),
        ),
      ];
    }
  }
}

equilateral_triangle.dart

import 'package:flutter/material.dart';

class EquilateralTriangleClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    final path = Path();
    path.lineTo(size.width, 0.0);
    path.lineTo(size.width / 2, size.height);
    path.close();
    return path;
  }

  @override
  bool shouldReclip(EquilateralTriangleClipper oldClipper) => false;
}

right_triangle.dart

import 'package:flutter/material.dart';

class RightTriangleClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    final path = Path();
    path.lineTo(size.width, 0.0);
    path.lineTo(0.0, size.height);
    path.close();
    return path;
  }

  @override
  bool shouldReclip(RightTriangleClipper oldClipper) => false;
}

class LeftTriangleClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    final path = Path();
    path.lineTo(size.width, 0.0);
    path.lineTo(size.width, size.height);
    path.close();
    return path;
  }

  @override
  bool shouldReclip(LeftTriangleClipper oldClipper) => false;
}

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