Skip to content

Commit

Permalink
add input border
Browse files Browse the repository at this point in the history
  • Loading branch information
obiwanzenobi committed Dec 31, 2021
1 parent d8e480e commit 42dffbc
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 21 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.2.0

* Added input border

## 0.1.0

* Initial release containing gradient box border
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,22 @@ Works with both: border radius, and with `BoxShape.circle`
![image](screenshots/box_borders.png)

### Input borders
TBW
You can use `GradientOutlineInputBorder` as a part of your input decoration:
```dart
TextField(
decoration: InputDecoration(
border: GradientOutlineInputBorder(
gradient: LinearGradient(colors: [Colors.red, Colors.blue]),
width: 2,
),
focusedBorder: GradientOutlineInputBorder(
gradient: LinearGradient(colors: [Colors.yellow, Colors.green]),
width: 2
),
label: Text("Example")),
),
```
![image](screenshots/outline_input_borders.png)

### Sponsored by
[The Code Brothers](https://thecodebrothers.pl)
40 changes: 26 additions & 14 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:gradient_borders/box_borders/gradient_box_border.dart';
import 'package:gradient_borders/gradient_borders.dart';

void main() {
runApp(const MyApp());
Expand Down Expand Up @@ -29,7 +29,6 @@ class MyHomePage extends StatefulWidget {
}

class _MyHomePageState extends State<MyHomePage> {

@override
Widget build(BuildContext context) {
return Scaffold(
Expand All @@ -44,22 +43,22 @@ class _MyHomePageState extends State<MyHomePage> {
width: 100,
height: 100,
decoration: BoxDecoration(
border: const GradientBoxBorder(
gradient: LinearGradient(colors: [Colors.blue, Colors.red]),
width: 4,
),
borderRadius: BorderRadius.circular(16)
),
border: const GradientBoxBorder(
gradient: LinearGradient(colors: [Colors.blue, Colors.red]),
width: 4,
),
borderRadius: BorderRadius.circular(16)),
),
const SizedBox(height: 16),
Container(
width: 100,
height: 100,
decoration: const BoxDecoration(
border: GradientBoxBorder(
gradient: LinearGradient(colors: [Colors.green, Colors.yellow]),
width: 4,
),
border: GradientBoxBorder(
gradient:
LinearGradient(colors: [Colors.green, Colors.yellow]),
width: 4,
),
),
),
const SizedBox(height: 16),
Expand All @@ -69,15 +68,28 @@ class _MyHomePageState extends State<MyHomePage> {
decoration: const BoxDecoration(
shape: BoxShape.circle,
border: GradientBoxBorder(
gradient: LinearGradient(colors: [Colors.pink, Colors.orange]),
gradient:
LinearGradient(colors: [Colors.pink, Colors.orange]),
width: 4,
),
),
),
const SizedBox(height: 16),
TextField(
decoration: InputDecoration(
border: GradientOutlineInputBorder(
gradient: LinearGradient(colors: [Colors.red, Colors.blue]),
width: 2,
),
focusedBorder: GradientOutlineInputBorder(
gradient: LinearGradient(colors: [Colors.yellow, Colors.green]),
width: 2
),
label: Text("Example")),
),
],
),
),
);
}
}

4 changes: 2 additions & 2 deletions example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ packages:
path: ".."
relative: true
source: path
version: "0.0.1"
version: "0.2.0"
lints:
dependency: transitive
description:
Expand Down Expand Up @@ -164,4 +164,4 @@ packages:
source: hosted
version: "2.1.1"
sdks:
dart: ">=2.15.1 <3.0.0"
dart: ">=2.15.0 <3.0.0"
2 changes: 1 addition & 1 deletion example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1

environment:
sdk: ">=2.15.1 <3.0.0"
sdk: ">=2.15.0 <3.0.0"

dependencies:
flutter:
Expand Down
1 change: 1 addition & 0 deletions lib/gradient_borders.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
library gradient_borders;

export 'box_borders/gradient_box_border.dart';
export 'input_borders/gradient_outline_input_border.dart';
155 changes: 155 additions & 0 deletions lib/input_borders/gradient_outline_input_border.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import 'dart:ui';
import 'dart:math' as math;

import 'package:flutter/material.dart';

class GradientOutlineInputBorder extends InputBorder {
final double width;
final BorderRadius borderRadius;
final Gradient gradient;
final double gapPadding;

const GradientOutlineInputBorder({
required this.gradient,
this.width = 1.0,
this.gapPadding = 4.0,
this.borderRadius = const BorderRadius.all(Radius.circular(4.0)),
});

@override
InputBorder copyWith({BorderSide? borderSide}) {
return this;
}

@override
bool get isOutline => true;

@override
EdgeInsetsGeometry get dimensions => EdgeInsets.all(width);

@override
Path getInnerPath(Rect rect, {TextDirection? textDirection}) {
return Path()
..addRRect(borderRadius
.resolve(textDirection)
.toRRect(rect)
.deflate(borderSide.width));
}

@override
Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
return Path()..addRRect(borderRadius.resolve(textDirection).toRRect(rect));
}

@override
void paint(Canvas canvas, Rect rect,
{double? gapStart,
double gapExtent = 0.0,
double gapPercentage = 0.0,
TextDirection? textDirection}) {
final Paint paint = _getPaint(rect);
final RRect outer = borderRadius.toRRect(rect);
final RRect center = outer.deflate(borderSide.width / 2.0);
if (gapStart == null || gapExtent <= 0.0 || gapPercentage == 0.0) {
canvas.drawRRect(center, paint);
} else {
final double extent =
lerpDouble(0.0, gapExtent + gapPadding * 2.0, gapPercentage)!;
switch (textDirection!) {
case TextDirection.rtl:
final Path path = _gapBorderPath(canvas, center,
math.max(0.0, gapStart + gapPadding - extent), extent);
canvas.drawPath(path, paint);
break;

case TextDirection.ltr:
final Path path = _gapBorderPath(
canvas, center, math.max(0.0, gapStart - gapPadding), extent);
canvas.drawPath(path, paint);
break;
}
}
}

@override
ShapeBorder scale(double t) {
return GradientOutlineInputBorder(
width: width * t,
borderRadius: borderRadius * t,
gradient: gradient,
);
}

Paint _getPaint(Rect rect) {
return Paint()
..strokeWidth = width
..shader = gradient.createShader(rect)
..style = PaintingStyle.stroke;
}

Path _gapBorderPath(
Canvas canvas, RRect center, double start, double extent) {
// When the corner radii on any side add up to be greater than the
// given height, each radius has to be scaled to not exceed the
// size of the width/height of the RRect.
final RRect scaledRRect = center.scaleRadii();

final Rect tlCorner = Rect.fromLTWH(
scaledRRect.left,
scaledRRect.top,
scaledRRect.tlRadiusX * 2.0,
scaledRRect.tlRadiusY * 2.0,
);
final Rect trCorner = Rect.fromLTWH(
scaledRRect.right - scaledRRect.trRadiusX * 2.0,
scaledRRect.top,
scaledRRect.trRadiusX * 2.0,
scaledRRect.trRadiusY * 2.0,
);
final Rect brCorner = Rect.fromLTWH(
scaledRRect.right - scaledRRect.brRadiusX * 2.0,
scaledRRect.bottom - scaledRRect.brRadiusY * 2.0,
scaledRRect.brRadiusX * 2.0,
scaledRRect.brRadiusY * 2.0,
);
final Rect blCorner = Rect.fromLTWH(
scaledRRect.left,
scaledRRect.bottom - scaledRRect.blRadiusY * 2.0,
scaledRRect.blRadiusX * 2.0,
scaledRRect.blRadiusX * 2.0,
);

const double cornerArcSweep = math.pi / 2.0;
final double tlCornerArcSweep = start < scaledRRect.tlRadiusX
? math.asin((start / scaledRRect.tlRadiusX).clamp(-1.0, 1.0))
: math.pi / 2.0;

final Path path = Path()
..addArc(tlCorner, math.pi, tlCornerArcSweep)
..moveTo(scaledRRect.left + scaledRRect.tlRadiusX, scaledRRect.top);

if (start > scaledRRect.tlRadiusX)
path.lineTo(scaledRRect.left + start, scaledRRect.top);

const double trCornerArcStart = (3 * math.pi) / 2.0;
const double trCornerArcSweep = cornerArcSweep;
if (start + extent < scaledRRect.width - scaledRRect.trRadiusX) {
path
..relativeMoveTo(extent, 0.0)
..lineTo(scaledRRect.right - scaledRRect.trRadiusX, scaledRRect.top)
..addArc(trCorner, trCornerArcStart, trCornerArcSweep);
} else if (start + extent < scaledRRect.width) {
final double dx = scaledRRect.width - (start + extent);
final double sweep = math.acos(dx / scaledRRect.trRadiusX);
path.addArc(trCorner, trCornerArcStart + sweep, trCornerArcSweep - sweep);
}

return path
..moveTo(scaledRRect.right, scaledRRect.top + scaledRRect.trRadiusY)
..lineTo(scaledRRect.right, scaledRRect.bottom - scaledRRect.brRadiusY)
..addArc(brCorner, 0.0, cornerArcSweep)
..lineTo(scaledRRect.left + scaledRRect.blRadiusX, scaledRRect.bottom)
..addArc(blCorner, math.pi / 2.0, cornerArcSweep)
..lineTo(scaledRRect.left, scaledRRect.top + scaledRRect.tlRadiusY);
}
}
7 changes: 4 additions & 3 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
name: gradient_borders
description: Gradient borders for inputs and containers
version: 0.1.0
description: Gradient borders for inputs and containers. Borders package integrated with a basic flutter widgets as a container and input decorations. Easy in use, platform independent.
version: 0.2.0
repository: https://github.com/obiwanzenobi/gradient-borders

environment:
sdk: ">=2.15.1 <3.0.0"
sdk: ">=2.15.0 <3.0.0"
flutter: ">=1.17.0"

dependencies:
Expand Down
Binary file added screenshots/outline_input_borders.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 42dffbc

Please sign in to comment.