Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 260 Vote(s) - 3.51 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How to add drop shadow to TextFormField In Flutter

#1
I have a text form field in flutter I want to add a drop shadow to it. how should I do that?

final password = TextFormField(
obscureText: true,
autofocus: false,
decoration: InputDecoration(
icon: new Icon(Icons.lock, color: Color(0xff224597)),
hintText: 'Password',
fillColor: Colors.white,
filled: true,
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
enabledBorder: OutlineInputBorder(borderRadius:BorderRadius.circular(5.0),
borderSide: BorderSide(color: Colors.white, width: 3.0))
),
);
Reply

#2
You can Wrap your `TextFormField` with a `Material` widget and edit its properties such as `elevation` and `shadowColor`.

Example:

Material(
elevation: 20.0,
shadowColor: Colors.blue,
child: TextFormField(
obscureText: true,
autofocus: false,
decoration: InputDecoration(
icon: new Icon(Icons.lock, color: Color(0xff224597)),
hintText: 'Password',
fillColor: Colors.white,
filled: true,
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
enabledBorder: OutlineInputBorder(borderRadius:BorderRadius.circular(5.0),
borderSide: BorderSide(color: Colors.white, width: 3.0))
),
),
)

You will Get something similar to the image below.
[![enter image description here][1]][1]


[1]:
Reply

#3
- You can wrap *TextFormField* into *Container* add shadow too *Container* this will add shadow to you *TextFormFieldbut* it also adds color to *TextFormField*.

- To remove Color from *TextFormField* use fillColor and filled property on TextFormField.

- You Can control the opacity of a color line **Colors.black.withOpacity(0.3)**.

**Checkout Code Below:**

final Widget password = Container(
decoration: BoxDecoration(
boxShadow: [
const BoxShadow(
blurRadius: 8,
),
],
borderRadius: BorderRadius.circular(5.0),
),
child: TextFormField(
obscureText: true,
decoration: InputDecoration(
fillColor: Colors.white,
filled: true,
prefixIcon: const Icon(
Icons.lock,
color: Color(0xff224597),
),
hintText: 'Password',
contentPadding: const EdgeInsets.fromLTRB(
20.0,
10.0,
20.0,
10.0,
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
borderSide: const BorderSide(
color: Colors.white,
width: 3.0,
),
),
),
),
);


[YOU CAN CHECKOUT THE OUTPUT HERE][1]


[1]:
Reply

#4
Here is a possible solution where the `BoxShadow` is only displayed behind the `TextField`, but is not expanding vertically if an error text is displayed.

[![enter image description here][1]][1]

My solution was to use the `Stack` widget to create an additional `Container` behind the actual `TextField` that is responsible for displaying the shadow.

A `TextPainter` is used to determine the height of the error text depending on its style:

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

class TextFieldWithBoxShadow extends StatelessWidget {
final String? errorText;
final String? labelText;
final TextEditingController? controller;
final double height;

const TextFieldWithBoxShadow({
Key? key,
this.errorText,
this.labelText,
this.controller,
this.height = 40,
}) : super(key: key);

@override
Widget build(BuildContext context) {
final errorStyle = const TextStyle(
fontSize: 14,
);

// Wrap everything in LayoutBuilder so that the available maxWidth is taken into account for the height calculation (important if you error text exceeds one line)
return LayoutBuilder(builder: (context, constraints) {
// Use tp to calculate the height of the errorText
final textPainter = TextPainter()
..text = TextSpan(text: errorText, style: errorStyle)
..textDirection = TextDirection.ltr
..layout(maxWidth: constraints.maxWidth);

final heightErrorMessage = textPainter.size.height + 8;
return Stack(
children: [
// Separate container with identical height of text field which is placed behind the actual textfield
Container(
height: height,
decoration: BoxDecoration(
boxShadow: const [
BoxShadow(
color: Colors.black,
blurRadius: 3,
offset: Offset(3, 3),
),
],
borderRadius: BorderRadius.circular(
10.0,
),
),
),
Container(
// Add height of error message if it is displayed
height: errorText != null ? height + heightErrorMessage : height,
child: TextField(
decoration: InputDecoration(
fillColor: Colors.black,
filled: true,
errorStyle: errorStyle,
errorText: errorText,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(
10.0,
),
),
labelText: labelText,
),
controller: controller,
),
),
],
);
});
}
}
```


[1]:
Reply

#5
The problem when we use a Container, Material or any other Widget to wrap the input text field in order to apply the shadow is if we use the hint text, error text or any other property that change the size of our textbox, the design would be broken.

Intead of wrapping the input in another widget you could use custom painter extending the InputBorder class.
For example:

class MyInputBorder extends OutlineInputBorder {}


Copy the following methods from the OutlineInputBorder implementation (Used for this example) to your new class:
_gapBorderPath
_cornersAreCircular
paint

Then in the paint method you could add the following lines

Path path = Path();
path.addRRect(center);
canvas.drawShadow(path, Colors.black, 4, true);

The above lines must be included before the canvas.drawRRect line:
Example:

if (gapStart == null || gapExtent <= 0.0 || gapPercentage == 0.0) {
// paint the shadow for the outlined shape
Path path = Path();
path.addRRect(center);
canvas.drawShadow(path, shadowColor!, elevation, true);

canvas.drawRRect(center, paint);
} else {... other code omitted to keep simple}

Then, in your Widget, use the new Input border:

TextField(
decoration: InputDecoration(
border: MyInputBorder()
),
)

The result produced looks like the following without any of the issues of wrapper solutions:

[text box with shadow][1]



Here is a complete sample implementation, the post is in spanish but it has the idea explained: [Full article for reference][2]


[1]:

[2]:

[To see links please register here]

Reply

#6
@mrramos answer was almost complete but this code wouldn't give the desired result, I read the article suggested and implemented my own class, my use case is only a shadow for the text field for when its selected therefore the naming of it.
Quick explanation of this as its a lot to read and most of it is not necessary to understand just to implement a simple shadow.

paint() method is copied from OutlineInputBorder as _cornersAreCircular() and _gapBorderPath()

There is an addition of these few lines in the paint method for it to give the shadow.

```
Path path = Path();
path.addRRect(center);
canvas.drawShadow(path, Colors.black, 5, true);
final shadowPaint = Paint();
shadowPaint.strokeWidth = 0;
shadowPaint.color = Colors.white;
shadowPaint.style = PaintingStyle.fill;
canvas.drawRRect(center, shadowPaint);
canvas.drawRRect(center, paint);
```
Complete file class.
```
import 'package:flutter/material.dart';
import 'dart:ui' show lerpDouble;
import 'dart:math' as math;

class SelectedInputBorderWithShadow extends OutlineInputBorder {
const SelectedInputBorderWithShadow({
BorderSide borderSide = const BorderSide(),
borderRadius = const BorderRadius.all(Radius.circular(5)),
gapPadding = 4.0,
}) : super(
borderSide: borderSide,
borderRadius: borderRadius,
gapPadding: gapPadding,
);

static bool _cornersAreCircular(BorderRadius borderRadius) {
return borderRadius.topLeft.x == borderRadius.topLeft.y &&
borderRadius.bottomLeft.x == borderRadius.bottomLeft.y &&
borderRadius.topRight.x == borderRadius.topRight.y &&
borderRadius.bottomRight.x == borderRadius.bottomRight.y;
}

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,
);

// This assumes that the radius is circular (x and y radius are equal).
// Currently, BorderRadius only supports circular radii.
const double cornerArcSweep = math.pi / 2.0;
final double tlCornerArcSweep = math.acos(
(1 - start / scaledRRect.tlRadiusX).clamp(0.0, 1.0),
);

final Path path = Path()..addArc(tlCorner, math.pi, tlCornerArcSweep);

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.moveTo(scaledRRect.left + start + extent, scaledRRect.top);
path.lineTo(scaledRRect.right - scaledRRect.trRadiusX, scaledRRect.top);
path.addArc(trCorner, trCornerArcStart, trCornerArcSweep);
} else if (start + extent < scaledRRect.width) {
final double dx = scaledRRect.width - (start + extent);
final double sweep = math.asin(
(1 - dx / scaledRRect.trRadiusX).clamp(0.0, 1.0),
);
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);
}

@override
void paint(
Canvas canvas,
Rect rect, {
double? gapStart,
double gapExtent = 0.0,
double gapPercentage = 0.0,
TextDirection? textDirection,
}) {
assert(gapExtent != null);
assert(gapPercentage >= 0.0 && gapPercentage <= 1.0);
assert(_cornersAreCircular(borderRadius));

final Paint paint = borderSide.toPaint();
final RRect outer = borderRadius.toRRect(rect);
final RRect center = outer.deflate(borderSide.width / 2.0);
if (gapStart == null || gapExtent <= 0.0 || gapPercentage == 0.0) {
Path path = Path();
path.addRRect(center);
canvas.drawShadow(path, Colors.black, 5, true);
final shadowPaint = Paint();
shadowPaint.strokeWidth = 0;
shadowPaint.color = Colors.white;
shadowPaint.style = PaintingStyle.fill;
canvas.drawRRect(center, shadowPaint);
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;
}
}
}
}
```
and my result looks like this.

[![enter image description here][1]][1]


[1]:
Reply

#7
You can use this class as a wrapper for an element's border. It takes the border of a control and draws a shadow to that border above the control. To create an illusion that the shadow is behind the control, the shadow's area above the control gets cut off.

``` dart
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

class DecoratedInputBorder extends InputBorder {
DecoratedInputBorder({
required this.child,
required this.shadow,
}) : super(borderSide: child.borderSide);

final InputBorder child;

final BoxShadow shadow;

@override
bool get isOutline => child.isOutline;

@override
Path getInnerPath(Rect rect, {TextDirection? textDirection}) => child.getInnerPath(rect, textDirection: textDirection);

@override
Path getOuterPath(Rect rect, {TextDirection? textDirection}) => child.getOuterPath(rect, textDirection: textDirection);

@override
EdgeInsetsGeometry get dimensions => child.dimensions;

@override
InputBorder copyWith({BorderSide? borderSide, InputBorder? child, BoxShadow? shadow, bool? isOutline}) {
return DecoratedInputBorder(
child: (child ?? this.child).copyWith(borderSide: borderSide),
shadow: shadow ?? this.shadow,
);
}

@override
ShapeBorder scale(double t) {
final scalledChild = child.scale(t);

return DecoratedInputBorder(
child: scalledChild is InputBorder ? scalledChild : child,
shadow: BoxShadow.lerp(null, shadow, t)!,
);
}

@override
void paint(Canvas canvas, Rect rect, {double? gapStart, double gapExtent = 0.0, double gapPercentage = 0.0, TextDirection? textDirection}) {
final clipPath = Path()
..addRect(const Rect.fromLTWH(-5000, -5000, 10000, 10000))
..addPath(getInnerPath(rect), Offset.zero)
..fillType = PathFillType.evenOdd;
canvas.clipPath(clipPath);

final Paint paint = shadow.toPaint();
final Rect bounds = rect.shift(shadow.offset).inflate(shadow.spreadRadius);

canvas.drawPath(getOuterPath(bounds), paint);

child.paint(canvas, rect, gapStart: gapStart, gapExtent: gapExtent, gapPercentage: gapPercentage, textDirection: textDirection);
}

@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType) return false;
return other is DecoratedInputBorder && other.borderSide == borderSide && other.child == child && other.shadow == shadow;
}

@override
int get hashCode => hashValues(borderSide, child, shadow);

@override
String toString() {
return '${objectRuntimeType(this, 'DecoratedInputBorder')}($borderSide, $shadow, $child)';
}
}
```

```
MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
inputDecorationTheme: InputDecorationTheme(
border: DecoratedInputBorder(
child: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(16.0)),
),
shadow: const BoxShadow(
color: Colors.blue,
blurRadius: 15,
),
),
),
),
```

It should looks this way:

[![enter image description here][1]][1]


Interactive example:

[To see links please register here]


Alternatively, you can use my package [control_style][2]. It implements a deeper realisation of this approach.


[1]:

[2]:

[To see links please register here]

Reply

#8
You can Use `PhysicalModel` to add shadow on each widget like this:

PhysicalModel(
borderRadius: BorderRadius.circular(25),
color: Colors.white,
elevation: 5.0,
shadowColor: Color(0xff44BD32),
child: CustomTextField(...
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through