Canceling a dropdown menu selects null value
Previously we didn't distinguish between canceling the menu (which popped the route with no return value, i.e. null) and explicitly selecting an item whose value is null (pop with value null). Both fired onChange(null). Now we box the return value so we can distinguish the two cases. I would have preferred to just disallow "null" as a value but it turns out people like being able to use "null" as a value for much the same reason we do, and it seems best for us to pay the complexity cost of boxing than having everyone else do it. :-)
This commit is contained in:
parent
09ab80502f
commit
0c6e3416d8
@ -95,7 +95,10 @@ class _DropDownMenu<T> extends StatusTransitionComponent {
|
|||||||
padding: _kMenuHorizontalPadding,
|
padding: _kMenuHorizontalPadding,
|
||||||
child: route.items[itemIndex]
|
child: route.items[itemIndex]
|
||||||
),
|
),
|
||||||
onTap: () => Navigator.pop(context, route.items[itemIndex].value)
|
onTap: () => Navigator.pop(
|
||||||
|
context,
|
||||||
|
new _DropDownRouteResult<T>(route.items[itemIndex].value)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -143,9 +146,24 @@ class _DropDownMenu<T> extends StatusTransitionComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DropDownRoute<T> extends PopupRoute<T> {
|
// We box the return value so that the return value can be null. Otherwise,
|
||||||
|
// canceling the route (which returns null) would get confused with actually
|
||||||
|
// returning a real null value.
|
||||||
|
class _DropDownRouteResult<T> {
|
||||||
|
const _DropDownRouteResult(this.result);
|
||||||
|
final T result;
|
||||||
|
bool operator ==(dynamic other) {
|
||||||
|
if (other is! _DropDownRouteResult)
|
||||||
|
return false;
|
||||||
|
final _DropDownRouteResult<T> typedOther = other;
|
||||||
|
return result == typedOther.result;
|
||||||
|
}
|
||||||
|
int get hashCode => result.hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DropDownRoute<T> extends PopupRoute<_DropDownRouteResult<T>> {
|
||||||
_DropDownRoute({
|
_DropDownRoute({
|
||||||
Completer<T> completer,
|
Completer<_DropDownRouteResult<T>> completer,
|
||||||
this.items,
|
this.items,
|
||||||
this.selectedIndex,
|
this.selectedIndex,
|
||||||
this.rect,
|
this.rect,
|
||||||
@ -246,7 +264,7 @@ class _DropDownButtonState<T> extends State<DropDownButton<T>> {
|
|||||||
void _handleTap() {
|
void _handleTap() {
|
||||||
final RenderBox renderBox = indexedStackKey.currentContext.findRenderObject();
|
final RenderBox renderBox = indexedStackKey.currentContext.findRenderObject();
|
||||||
final Rect rect = renderBox.localToGlobal(Point.origin) & renderBox.size;
|
final Rect rect = renderBox.localToGlobal(Point.origin) & renderBox.size;
|
||||||
final Completer completer = new Completer<T>();
|
final Completer completer = new Completer<_DropDownRouteResult<T>>();
|
||||||
Navigator.push(context, new _DropDownRoute<T>(
|
Navigator.push(context, new _DropDownRoute<T>(
|
||||||
completer: completer,
|
completer: completer,
|
||||||
items: config.items,
|
items: config.items,
|
||||||
@ -254,11 +272,11 @@ class _DropDownButtonState<T> extends State<DropDownButton<T>> {
|
|||||||
rect: _kMenuHorizontalPadding.inflateRect(rect),
|
rect: _kMenuHorizontalPadding.inflateRect(rect),
|
||||||
elevation: config.elevation
|
elevation: config.elevation
|
||||||
));
|
));
|
||||||
completer.future.then((T newValue) {
|
completer.future.then((_DropDownRouteResult<T> newValue) {
|
||||||
if (!mounted)
|
if (!mounted || newValue == null)
|
||||||
return;
|
return;
|
||||||
if (config.onChanged != null)
|
if (config.onChanged != null)
|
||||||
config.onChanged(newValue);
|
config.onChanged(newValue.result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user