我希望能够将TextField转换为仅与Text之间的过渡,这意味着输入修饰逐渐消失,并且文本本身稍微向左移动(当输入填充变为0时)。
使用TextField的固有动画,以下代码取得了一些有限的成功。但是,文本会向左跳,而不是逐渐向左移动,并且输入的修饰会跳入/跳出以及淡入淡出。
class ExampleScreen extends StatefulWidget {
@override
ExampleScreenState createState() => ExampleScreenState();
}
class ExampleScreenState extends State<ExampleScreen> {
TextEditingController text = TextEditingController();
bool editing = true;
@override
Widget build(BuildContext context) {
return Scaffold(
body: EditableText(controller: text, editing: editing),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() => editing = !editing),
child: Icon(Icons.ac_unit),
),
);
}
}
class EditableText extends StatelessWidget {
final TextEditingController controller;
final bool editing;
EditableText({this.controller, this.editing});
@override Widget build(BuildContext context) {
return TextField(
controller: controller,
enabled: editing,
decoration: InputDecoration().copyWith(
contentPadding: editing ? Theme.of(context).inputDecorationTheme.contentPadding : EdgeInsets.zero,
disabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.transparent))
),
);
}
}
有什么聪明的主意吗?
答案 0 :(得分:1)
我写了一个有效的示例,但是仍然有些闪烁,您可以尝试一些[曲线]来修改动画。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>
with SingleTickerProviderStateMixin {
AnimationController controller;
@override
void initState() {
super.initState();
controller = AnimationController(
duration: Duration(seconds: 1),
vsync: this,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home Page'),
),
body: Center(
child: AnimatedTextField(
controller: controller,
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.opacity),
onPressed: () {
var status = controller.status;
if (status == AnimationStatus.completed) {
controller.reverse();
} else if (status == AnimationStatus.dismissed) {
controller.forward();
}
},
),
);
}
}
class AnimatedTextField extends StatefulWidget {
final AnimationController controller;
final Animation<double> opacity;
final Animation<double> left;
AnimatedTextField({
Key key,
@required this.controller,
}) : opacity = Tween<double>(
begin: 1.0,
end: 0.0,
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(
0.0,
0.5,
curve: Curves.easeInOut,
),
),
),
left = Tween<double>(
begin: 20.0,
end: 0.0,
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(
0.0,
1.0,
curve: Curves.easeIn,
),
),
),
super(key: key);
@override
_AnimatedTextFieldState createState() => _AnimatedTextFieldState();
}
class _AnimatedTextFieldState extends State<AnimatedTextField> {
TextEditingController _textEditingController =
TextEditingController(text: 'hello fluttr');
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: widget.controller,
builder: (context, child) {
var theme = Theme.of(context);
var o = widget.opacity.value;
var _child = o > 0.0
? TextField(
controller: _textEditingController,
style: theme.textTheme.body2,
decoration: InputDecoration(
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color.fromRGBO(0, 0, 0, 1)),
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color.fromRGBO(0, 0, 0, o)),
),
),
)
: Opacity(
opacity: (o - 1).abs(),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
_textEditingController.text,
style: theme.textTheme.body2,
),
),
);
return Padding(
padding: EdgeInsets.only(
left: widget.left.value,
top: 20,
right: 20,
bottom: 20,
),
child: _child,
);
},
);
}
}
答案 1 :(得分:0)
设法解决。创建了一个'AnimatedDouble'窗口小部件,该窗口小部件仅使一个动画值作为参数的构建器,并由ChangeNotifier触发:
class AnimatedDouble extends StatefulWidget {
final Widget child;
final Function(BuildContext context, Widget child, double d) builder;
final Duration duration;
final ChangeNotifier listen;
AnimatedDouble({this.child, this.builder, this.duration, this.listen});
@override
_AnimatedDoubleState createState() => new _AnimatedDoubleState();
}
class _AnimatedDoubleState extends State<AnimatedDouble> with SingleTickerProviderStateMixin{
AnimationController controller;
@override
void initState() {
super.initState();
controller = AnimationController(value: 1.0, vsync: this, duration: widget.duration);
widget.listen.addListener(_go);
}
@override
void dispose() {
controller.dispose();
widget.listen.removeListener(_go);
super.dispose();
}
void _go() {
controller.forward(from: 0.0);
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: controller,
child: widget.child,
builder: (context, child) => widget.builder(context, child, controller.view.value),
);
}
}
然后可以像这样使用它来获得我想要的效果:
AnimatedDouble(
duration: Duration(milliseconds: 200),
listen: something_to_trigger_animation,
builder: (context, child, d) => TextField(
controller: controller,
decoration: InputDecoration(
contentPadding: editing ?
EdgeInsets.symmetric(vertical: 16.0 * d, horizontal: 12.0 * d) :
EdgeInsets.symmetric(vertical: 16.0 * (1 - d), horizontal: 12.0 * (1 - d)),
disabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.transparent)),
),
enabled: editing,
),
),