实现在 flutter 中创建下拉按钮的功能
Implement a function to create dropdown butttons in flutter
我是 dart 编程的新手,我想实现一个创建下拉按钮的功能。
条件是:
-下拉按钮的值应该作为一个变量。
示例函数调用:
buildDropdownField(dropdownHeader:"tank 1", dropdownValue:_tank2)
此函数的预期输出是创建一个下拉按钮并将其值存储到 _tank2 中,以便我以后可以使用它。到目前为止,我尝试了不同的方法,但我似乎无法正确处理。
这是我的最终功能,它不会在屏幕上显示值,但会保存给定的值。
Widget buildDropdownField(
{required String dropdownHeader,
required String? dropdownValue,
required VoidCallback? OnChanged(Value)}) {
return Column(
children: <Widget>[
Text(dropdownHeader),
const SizedBox(
height: 10,
),
StatefulBuilder(
builder: (_, setDropState) {
return DropdownButton<String>(
value: dropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (value){
OnChanged(value);
},
items: <String>['-', 'Geçti', 'Kaldı', 'Belirsiz']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
},
)
],
);
}
最后是我最后一次函数迭代的函数调用:
buildDropdownField(dropdownHeader:"tank 1", dropdownValue:_tank2, OnChanged: (Value) {
setState(() {
tank1 = Value;
});
})
这是我在我的项目中使用的自定义扩展磁贴。它来自一个包的代码,稍微符合我的需要。
import 'package:flutter/material.dart';
const Duration _kExpand = Duration(milliseconds: 200);
class CustomExpansionTile extends StatefulWidget {
const CustomExpansionTile({
Key key,
this.leading,
@required this.title,
this.backgroundColor,
this.children = const <Widget>[],
this.trailing,
@required this.expandedItem,
@required this.expansionCallback,
@required this.onHeaderClick,
this.subtitleWidget,
}) : super(key: key);
/// A widget to display before the title.
///
/// Typically a [CircleAvatar] widget.
final Widget leading;
/// The primary content of the list item.
///
/// Typically a [Text] widget.
final Widget title;
final Widget subtitleWidget;
/// The widgets that are displayed when the tile expands.
///
/// Typically [ListTile] widgets.
final List<Widget> children;
/// The color to display behind the sublist when expanded.
final Color backgroundColor;
/// A widget to display instead of a rotating arrow icon.
final Widget trailing;
final ValueNotifier<Key> expandedItem;
final Function(bool hasExpanded) expansionCallback;
final Function() onHeaderClick;
@override
_CustomExpansionTileState createState() => _CustomExpansionTileState();
}
class _CustomExpansionTileState extends State<CustomExpansionTile>
with SingleTickerProviderStateMixin {
static final Animatable<double> _easeOutTween =
CurveTween(curve: Curves.easeOut);
static final Animatable<double> _easeInTween =
CurveTween(curve: Curves.easeIn);
static final Animatable<double> _halfTween =
Tween<double>(begin: 0.0, end: 0.5);
final ColorTween _borderColorTween = ColorTween();
final ColorTween _headerColorTween = ColorTween();
final ColorTween _iconColorTween = ColorTween();
final ColorTween _backgroundColorTween = ColorTween();
AnimationController _controller;
Animation<double> _iconTurns;
Animation<double> _heightFactor;
Animation<Color> _borderColor;
Animation<Color> _headerColor;
Animation<Color> _iconColor;
Animation<Color> _backgroundColor;
bool _isExpanded = false;
@override
void initState() {
super.initState();
_controller = AnimationController(duration: _kExpand, vsync: this);
_heightFactor = _controller.drive(_easeInTween);
_iconTurns = _controller.drive(_halfTween.chain(_easeInTween));
_borderColor = _controller.drive(_borderColorTween.chain(_easeOutTween));
_headerColor = _controller.drive(_headerColorTween.chain(_easeInTween));
_iconColor = _controller.drive(_iconColorTween.chain(_easeInTween));
_backgroundColor =
_controller.drive(_backgroundColorTween.chain(_easeOutTween));
_isExpanded = widget.expandedItem.value == widget.key;
if (_isExpanded) _controller.value = 1.0;
widget.expandedItem.addListener(listener);
}
void listener() {
setState(() {
_changeState(widget.expandedItem.value == widget.key);
});
}
@override
void dispose() {
_controller.dispose();
widget.expandedItem.removeListener(listener);
super.dispose();
}
void _changeState(bool isExpanded) {
setState(() {
_isExpanded = isExpanded;
if (_isExpanded) {
_controller.forward();
} else {
_controller.reverse().then<void>((void value) {
if (!mounted) return;
setState(() {
// Rebuild without widget.children.
});
});
}
PageStorage.of(context)?.writeState(context, _isExpanded);
});
}
//action to perform when the "expand" icon is pressed
void _onExpansionIconClick() {
widget.expansionCallback(!_isExpanded);
_changeState(!_isExpanded);
widget.expandedItem.value = _isExpanded ? widget.key : null;
}
Widget _buildChildren(BuildContext context, Widget child) {
final Color borderSideColor = _borderColor.value ?? Colors.transparent;
return Container(
decoration: BoxDecoration(
color: _backgroundColor.value ?? Colors.transparent,
border: Border(
top: BorderSide(color: borderSideColor),
bottom: BorderSide(color: borderSideColor),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTileTheme.merge(
iconColor: _iconColor.value,
textColor: _headerColor.value,
child: ListTile(
//if the list isExpanded, the click on the tile is disabled
//otherwise the action defined for the callback
//is performed
onTap: () => _isExpanded ? null : widget.onHeaderClick(),
leading: widget.leading,
title: widget.title,
subtitle: widget.subtitleWidget,
//arrow icon
trailing: InkWell(
onTap: _onExpansionIconClick,
child: Container(
padding: EdgeInsets.all(16),
//rotate arrow icon if the tile is expanded
child: widget.trailing ??
RotationTransition(
turns: _iconTurns,
child: const Icon(Icons.expand_more),
),
),
),
contentPadding: EdgeInsets.only(left: 16),
),
),
ClipRect(
child: Align(
heightFactor: _heightFactor.value,
child: child,
),
),
],
),
);
}
@override
void didChangeDependencies() {
final ThemeData theme = Theme.of(context);
_borderColorTween..end = theme.dividerColor;
_headerColorTween
..begin = theme.textTheme.subtitle1.color
..end = theme.accentColor;
_iconColorTween
..begin = theme.unselectedWidgetColor
..end = theme.accentColor;
_backgroundColorTween..end = widget.backgroundColor;
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
final bool closed = !_isExpanded && _controller.isDismissed;
return AnimatedBuilder(
animation: _controller.view,
builder: _buildChildren,
child: closed ? null : Column(children: widget.children),
);
}
}
我是 dart 编程的新手,我想实现一个创建下拉按钮的功能。 条件是: -下拉按钮的值应该作为一个变量。
示例函数调用:
buildDropdownField(dropdownHeader:"tank 1", dropdownValue:_tank2)
此函数的预期输出是创建一个下拉按钮并将其值存储到 _tank2 中,以便我以后可以使用它。到目前为止,我尝试了不同的方法,但我似乎无法正确处理。 这是我的最终功能,它不会在屏幕上显示值,但会保存给定的值。
Widget buildDropdownField(
{required String dropdownHeader,
required String? dropdownValue,
required VoidCallback? OnChanged(Value)}) {
return Column(
children: <Widget>[
Text(dropdownHeader),
const SizedBox(
height: 10,
),
StatefulBuilder(
builder: (_, setDropState) {
return DropdownButton<String>(
value: dropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (value){
OnChanged(value);
},
items: <String>['-', 'Geçti', 'Kaldı', 'Belirsiz']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
},
)
],
);
}
最后是我最后一次函数迭代的函数调用:
buildDropdownField(dropdownHeader:"tank 1", dropdownValue:_tank2, OnChanged: (Value) {
setState(() {
tank1 = Value;
});
})
这是我在我的项目中使用的自定义扩展磁贴。它来自一个包的代码,稍微符合我的需要。
import 'package:flutter/material.dart';
const Duration _kExpand = Duration(milliseconds: 200);
class CustomExpansionTile extends StatefulWidget {
const CustomExpansionTile({
Key key,
this.leading,
@required this.title,
this.backgroundColor,
this.children = const <Widget>[],
this.trailing,
@required this.expandedItem,
@required this.expansionCallback,
@required this.onHeaderClick,
this.subtitleWidget,
}) : super(key: key);
/// A widget to display before the title.
///
/// Typically a [CircleAvatar] widget.
final Widget leading;
/// The primary content of the list item.
///
/// Typically a [Text] widget.
final Widget title;
final Widget subtitleWidget;
/// The widgets that are displayed when the tile expands.
///
/// Typically [ListTile] widgets.
final List<Widget> children;
/// The color to display behind the sublist when expanded.
final Color backgroundColor;
/// A widget to display instead of a rotating arrow icon.
final Widget trailing;
final ValueNotifier<Key> expandedItem;
final Function(bool hasExpanded) expansionCallback;
final Function() onHeaderClick;
@override
_CustomExpansionTileState createState() => _CustomExpansionTileState();
}
class _CustomExpansionTileState extends State<CustomExpansionTile>
with SingleTickerProviderStateMixin {
static final Animatable<double> _easeOutTween =
CurveTween(curve: Curves.easeOut);
static final Animatable<double> _easeInTween =
CurveTween(curve: Curves.easeIn);
static final Animatable<double> _halfTween =
Tween<double>(begin: 0.0, end: 0.5);
final ColorTween _borderColorTween = ColorTween();
final ColorTween _headerColorTween = ColorTween();
final ColorTween _iconColorTween = ColorTween();
final ColorTween _backgroundColorTween = ColorTween();
AnimationController _controller;
Animation<double> _iconTurns;
Animation<double> _heightFactor;
Animation<Color> _borderColor;
Animation<Color> _headerColor;
Animation<Color> _iconColor;
Animation<Color> _backgroundColor;
bool _isExpanded = false;
@override
void initState() {
super.initState();
_controller = AnimationController(duration: _kExpand, vsync: this);
_heightFactor = _controller.drive(_easeInTween);
_iconTurns = _controller.drive(_halfTween.chain(_easeInTween));
_borderColor = _controller.drive(_borderColorTween.chain(_easeOutTween));
_headerColor = _controller.drive(_headerColorTween.chain(_easeInTween));
_iconColor = _controller.drive(_iconColorTween.chain(_easeInTween));
_backgroundColor =
_controller.drive(_backgroundColorTween.chain(_easeOutTween));
_isExpanded = widget.expandedItem.value == widget.key;
if (_isExpanded) _controller.value = 1.0;
widget.expandedItem.addListener(listener);
}
void listener() {
setState(() {
_changeState(widget.expandedItem.value == widget.key);
});
}
@override
void dispose() {
_controller.dispose();
widget.expandedItem.removeListener(listener);
super.dispose();
}
void _changeState(bool isExpanded) {
setState(() {
_isExpanded = isExpanded;
if (_isExpanded) {
_controller.forward();
} else {
_controller.reverse().then<void>((void value) {
if (!mounted) return;
setState(() {
// Rebuild without widget.children.
});
});
}
PageStorage.of(context)?.writeState(context, _isExpanded);
});
}
//action to perform when the "expand" icon is pressed
void _onExpansionIconClick() {
widget.expansionCallback(!_isExpanded);
_changeState(!_isExpanded);
widget.expandedItem.value = _isExpanded ? widget.key : null;
}
Widget _buildChildren(BuildContext context, Widget child) {
final Color borderSideColor = _borderColor.value ?? Colors.transparent;
return Container(
decoration: BoxDecoration(
color: _backgroundColor.value ?? Colors.transparent,
border: Border(
top: BorderSide(color: borderSideColor),
bottom: BorderSide(color: borderSideColor),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTileTheme.merge(
iconColor: _iconColor.value,
textColor: _headerColor.value,
child: ListTile(
//if the list isExpanded, the click on the tile is disabled
//otherwise the action defined for the callback
//is performed
onTap: () => _isExpanded ? null : widget.onHeaderClick(),
leading: widget.leading,
title: widget.title,
subtitle: widget.subtitleWidget,
//arrow icon
trailing: InkWell(
onTap: _onExpansionIconClick,
child: Container(
padding: EdgeInsets.all(16),
//rotate arrow icon if the tile is expanded
child: widget.trailing ??
RotationTransition(
turns: _iconTurns,
child: const Icon(Icons.expand_more),
),
),
),
contentPadding: EdgeInsets.only(left: 16),
),
),
ClipRect(
child: Align(
heightFactor: _heightFactor.value,
child: child,
),
),
],
),
);
}
@override
void didChangeDependencies() {
final ThemeData theme = Theme.of(context);
_borderColorTween..end = theme.dividerColor;
_headerColorTween
..begin = theme.textTheme.subtitle1.color
..end = theme.accentColor;
_iconColorTween
..begin = theme.unselectedWidgetColor
..end = theme.accentColor;
_backgroundColorTween..end = widget.backgroundColor;
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
final bool closed = !_isExpanded && _controller.isDismissed;
return AnimatedBuilder(
animation: _controller.view,
builder: _buildChildren,
child: closed ? null : Column(children: widget.children),
);
}
}