Autoscroll when keyboard open on purchase screen
This commit is contained in:
@@ -318,84 +318,3 @@ abstract class BaseState<T extends StatefulWidget> extends State<T> {
|
||||
return new Container(margin: margin, height: buttonHeight, child: new Row(children: <Widget>[new Expanded(child: widget)]));
|
||||
}
|
||||
}
|
||||
|
||||
class EnsureVisibleWhenFocused extends StatefulWidget {
|
||||
const EnsureVisibleWhenFocused({
|
||||
Key key,
|
||||
@required this.child,
|
||||
@required this.focusNode,
|
||||
this.curve: Curves.ease,
|
||||
this.duration: const Duration(milliseconds: 100),
|
||||
}) : super(key: key);
|
||||
|
||||
/// The node we will monitor to determine if the child is focused
|
||||
final FocusNode focusNode;
|
||||
|
||||
/// The child widget that we are wrapping
|
||||
final Widget child;
|
||||
|
||||
/// The curve we will use to scroll ourselves into view.
|
||||
///
|
||||
/// Defaults to Curves.ease.
|
||||
final Curve curve;
|
||||
|
||||
/// The duration we will use to scroll ourselves into view
|
||||
///
|
||||
/// Defaults to 100 milliseconds.
|
||||
final Duration duration;
|
||||
|
||||
EnsureVisibleWhenFocusedState createState() => new EnsureVisibleWhenFocusedState();
|
||||
}
|
||||
|
||||
class EnsureVisibleWhenFocusedState extends State<EnsureVisibleWhenFocused> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
widget.focusNode.addListener(_ensureVisible);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
widget.focusNode.removeListener(_ensureVisible);
|
||||
}
|
||||
|
||||
Future<Null> _ensureVisible() async {
|
||||
// Wait for the keyboard to come into view
|
||||
// TODO: position doesn't seem to notify listeners when metrics change,
|
||||
// perhaps a NotificationListener around the scrollable could avoid
|
||||
// the need insert a delay here.
|
||||
await new Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
if (!widget.focusNode.hasFocus)
|
||||
return;
|
||||
|
||||
final RenderObject object = context.findRenderObject();
|
||||
final RenderAbstractViewport viewport = RenderAbstractViewport.of(object);
|
||||
assert(viewport != null);
|
||||
|
||||
ScrollableState scrollableState = Scrollable.of(context);
|
||||
assert(scrollableState != null);
|
||||
|
||||
ScrollPosition position = scrollableState.position;
|
||||
double alignment;
|
||||
if (position.pixels > viewport.getOffsetToReveal(object, 0.0)) {
|
||||
// Move down to the top of the viewport
|
||||
alignment = 0.0;
|
||||
} else if (position.pixels < viewport.getOffsetToReveal(object, 1.0)) {
|
||||
// Move up to the bottom of the viewport
|
||||
alignment = 1.0;
|
||||
} else {
|
||||
// No scrolling is necessary to reveal the child
|
||||
return;
|
||||
}
|
||||
position.ensureVisible(
|
||||
object,
|
||||
alignment: alignment,
|
||||
duration: widget.duration,
|
||||
curve: widget.curve,
|
||||
);
|
||||
}
|
||||
|
||||
Widget build(BuildContext context) => widget.child;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@ class PurchaseScreenState<T> extends BaseState<PurchaseScreen> {
|
||||
void initState() {
|
||||
loading = true;
|
||||
requestAsyncData(user);
|
||||
buildFocusNode();
|
||||
scrollController = new ScrollController();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@@ -54,12 +56,14 @@ class PurchaseScreenState<T> extends BaseState<PurchaseScreen> {
|
||||
}
|
||||
|
||||
bool purchaseInProgress = false;
|
||||
ScrollController scrollController;
|
||||
Map user;
|
||||
String card = '';
|
||||
String loyalityType = '';
|
||||
String loyalty = '';
|
||||
String bonus = '';
|
||||
List<Map> coupons = [];
|
||||
ListView listView;
|
||||
|
||||
@override
|
||||
Widget getScreenContent() {
|
||||
@@ -119,8 +123,8 @@ class PurchaseScreenState<T> extends BaseState<PurchaseScreen> {
|
||||
)
|
||||
));
|
||||
|
||||
return new Container(child: new ListView(reverse: true,
|
||||
children: <Widget>[new Column(children: widgetList)].reversed.toList()));
|
||||
listView = new ListView(children: widgetList, controller: scrollController);
|
||||
return listView;
|
||||
}
|
||||
|
||||
getBonusInputField() {
|
||||
@@ -130,6 +134,7 @@ class PurchaseScreenState<T> extends BaseState<PurchaseScreen> {
|
||||
hintText: (app != 'crypto') ? StringsLocalization.bonusHint() : StringsLocalization.joysHint(),
|
||||
hintStyle: new TextStyle(color: greyTextColor, fontSize: 16.0)
|
||||
),
|
||||
focusNode: bonusFocusNode,
|
||||
controller: bonusController,
|
||||
onSubmitted: (String text) {
|
||||
setState(() {
|
||||
@@ -206,13 +211,13 @@ class PurchaseScreenState<T> extends BaseState<PurchaseScreen> {
|
||||
hintText: getHintString(),
|
||||
hintStyle: new TextStyle(color: greyTextColor, fontSize: 16.0)),
|
||||
controller: controller,
|
||||
focusNode: sumFocusNode,
|
||||
onSubmitted: (String text) {
|
||||
setState(() {
|
||||
controller.text = _parseSum(text);
|
||||
});
|
||||
},
|
||||
textAlign: TextAlign.center,
|
||||
autofocus: true);
|
||||
textAlign: TextAlign.center);
|
||||
}
|
||||
|
||||
requestAsyncData(Map user) async {
|
||||
@@ -436,4 +441,39 @@ class PurchaseScreenState<T> extends BaseState<PurchaseScreen> {
|
||||
Navigator.of(context).pop(token);
|
||||
});
|
||||
}
|
||||
|
||||
FocusNode bonusFocusNode = new FocusNode();
|
||||
FocusNode sumFocusNode = new FocusNode();
|
||||
|
||||
// TODO: Удалить дублирующийся код.
|
||||
void buildFocusNode() {
|
||||
|
||||
sumFocusNode.addListener(() {
|
||||
setState(() {
|
||||
|
||||
if (sumFocusNode.hasFocus && bonusFocusNode.hasFocus) {
|
||||
bonusFocusNode.unfocus();
|
||||
}
|
||||
|
||||
if (sumFocusNode.hasFocus) {
|
||||
scrollController.animateTo(100.0, duration: new Duration(seconds: 1), curve: Curves.ease);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
bonusFocusNode.addListener(() {
|
||||
setState(() {
|
||||
|
||||
if (bonusFocusNode.hasFocus && sumFocusNode.hasFocus) {
|
||||
sumFocusNode.unfocus();
|
||||
}
|
||||
|
||||
if (bonusFocusNode.hasFocus) {
|
||||
scrollController.animateTo(120.0, duration: new Duration(seconds: 1), curve: Curves.ease);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,15 +57,13 @@ class RegistrationScreenState extends BaseState<RegistrationScreen> {
|
||||
|
||||
@override
|
||||
getTextWidget() {
|
||||
return new EnsureVisibleWhenFocused(
|
||||
focusNode: _focusNode,
|
||||
child: new TextField(
|
||||
return new TextField(
|
||||
focusNode: _focusNode,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: new InputDecoration.collapsed(
|
||||
hintText: getHintString(),
|
||||
hintStyle: new TextStyle(color: greyTextColor, fontSize: 16.0)),
|
||||
onChanged: (text) => handleUserInput(text)));
|
||||
onChanged: (text) => handleUserInput(text));
|
||||
}
|
||||
|
||||
/// Возвращает кнопку регистрации.
|
||||
|
||||
Reference in New Issue
Block a user