Nic*_*leZ 7 flutter flutter-layout
我在颤抖中有文本形式的领域,我想向其中添加阴影。我该怎么做?
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))
),
);
Run Code Online (Sandbox Code Playgroud)
Vic*_*r K 17
您可以使用此类作为元素边框的包装器。它采用控件的边框并在控件上方的边框上绘制阴影。为了产生阴影位于控件后面的错觉,控件上方的阴影区域会被切除。
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)';
}
}
Run Code Online (Sandbox Code Playgroud)
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,
),
),
),
),
Run Code Online (Sandbox Code Playgroud)
它应该看起来像这样:
交互示例:https://dartpad.dev/?id =35f1249b52d177d47bc91c87d0a8c08c
或者,您可以使用我的包control_style。它实现了这种方法的更深入的实现。
say*_*bir 10
您可以使用PhysicalModel在每个小部件上添加阴影,如下所示:
PhysicalModel(
borderRadius: BorderRadius.circular(25),
color: Colors.white,
elevation: 5.0,
shadowColor: Color(0xff44BD32),
child: CustomTextField(...
Run Code Online (Sandbox Code Playgroud)
这是一个可能的解决方案,其中BoxShadow只显示在 后面TextField,但如果显示错误文本则不会垂直扩展。
我的解决方案是使用该小部件在实际后面Stack创建一个额外的部件,负责显示阴影。ContainerTextField
ATextPainter用于根据错误文本的样式确定其高度:
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,
),
),
],
);
});
}
}
Run Code Online (Sandbox Code Playgroud)
您可以TextFormField用Material小部件包装并编辑其属性,例如elevation和shadowColor。
例:
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))
),
),
)
Run Code Online (Sandbox Code Playgroud)
小智 5
当我们使用容器、材质或任何其他小部件来包装输入文本字段以应用阴影时,问题是如果我们使用提示文本、错误文本或任何其他更改文本框大小的属性,设计将被打破。
您可以使用扩展 InputBorder 类的自定义画家,而不是将输入包装在另一个小部件中。例如:
class MyInputBorder extends OutlineInputBorder {}
Run Code Online (Sandbox Code Playgroud)
将以下方法从 OutlineInputBorder 实现(用于本示例)复制到您的新类: _gapBorderPath _cornersAreCircular Paint
然后在paint方法中你可以添加以下几行
Path path = Path();
path.addRRect(center);
canvas.drawShadow(path, Colors.black, 4, true);
Run Code Online (Sandbox Code Playgroud)
上述行必须包含在 canvas.drawRRect 行之前: 示例:
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}
Run Code Online (Sandbox Code Playgroud)
然后,在您的小部件中,使用新的输入边框:
TextField(
decoration: InputDecoration(
border: MyInputBorder()
),
)
Run Code Online (Sandbox Code Playgroud)
生成的结果如下所示,不存在包装解决方案的任何问题:
这是一个完整的示例实现,该帖子是西班牙语的,但它解释了想法:完整文章供参考
| 归档时间: |
|
| 查看次数: |
1580 次 |
| 最近记录: |