Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CupertinoTextField vertical alignment #34723

Merged
merged 14 commits into from Jul 3, 2019

Conversation

justinmc
Copy link
Contributor

@justinmc justinmc commented Jun 19, 2019

Description

This PR adds the textAlignVertical parameter to CupertinoTextField. It works the same as TextField with the slight differences that 1. including any prefix or suffix causes alignment to default to the center, and 2. the text centers itself within the vertical space of the prefix/suffix. Both of these are existing behaviors that have been preserved by this PR.

Related

See #34355, which added textAlignVertical for TextField.

Closes #33785

@justinmc justinmc self-assigned this Jun 19, 2019
@justinmc justinmc added f: cupertino flutter/packages/flutter/cupertino repository framework flutter/packages/flutter repository. See also f: labels. work in progress; do not review labels Jun 19, 2019
@justinmc justinmc force-pushed the text-field-vertical-align-cupertino branch from 1b0211e to d21f322 Compare June 20, 2019 17:02
@justinmc justinmc force-pushed the text-field-vertical-align-cupertino branch 2 times, most recently from 24826bc to bc17df9 Compare June 20, 2019 19:43
@justinmc justinmc force-pushed the text-field-vertical-align-cupertino branch from bc17df9 to 376bdd6 Compare June 20, 2019 19:44
@justinmc justinmc force-pushed the text-field-vertical-align-cupertino branch from 599c480 to a5f79b4 Compare June 25, 2019 22:50
/// * [TextField.textAlignVertical], which is passed on to the [InputDecorator].
/// * [InputDecorator.textAlignVertical], which defines the alignment of
/// prefix, input, and suffix, within the [InputDecorator].
class TextAlignVertical {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just moved this to alignment.dart so that it's accessible by both Cupertino and Material.

@@ -898,7 +914,26 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
ignoring: !enabled,
child: Container(
decoration: effectiveDecoration,
child: _addTextDependentAttachments(paddedEditable, textStyle, placeholderStyle),
child: TextSelectionGestureDetector(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Align widget is what does the vertical alignment. I had to move the TextSelectionGestureDetector here in order to get the entire input to be interactive in all cases like it should be.

// Because TextSelectionGestureDetector listens to taps that happen on
// widgets in front of it, tapping the clear button will also trigger this
// handler here. If this is the case, return.
if (_clearing) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is hacky. Is there any other way to prevent taps on the clear button from triggering the TextSelectionGestureDetector? I'm back to the confusing gesture arena problem of multiple widgets getting the same event.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we want to eliminate gestures that start (with a down event) in either the text field's prefix or the clear button suffix. The TextSelectionGestureDetector would have to ignore gestures that start within the corresponding render boxes, per hitTest.

This probably isn't academic. One could use a Slider as prefix for example.

@justinmc justinmc force-pushed the text-field-vertical-align-cupertino branch 2 times, most recently from 6a17d5f to 94c8ddd Compare June 26, 2019 22:49
// Tapping anywhere inside focuses it.
expect(focusNode.hasFocus, false);
await tester.tapAt(tester.getTopLeft(find.byType(CupertinoTextField)));
await tester.pumpAndSettle(const Duration(milliseconds: 400)); // timer error if no duration
Copy link
Contributor Author

@justinmc justinmc Jun 26, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I didn't add this Duration, then I got failures due to "A Timer is still pending even after the widget tree was disposed." Any other way to fix that? Am I doing something weird here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be the 300ms doubleTap timer from packages/flutter/lib/src/widgets/text_selection.dart. Pump and settle only waits for 100ms, so the timer may survive to the end of the test. Assuming that's correct, you could explicitly add a second 300 ms pump (after a no-args pumpAndSettle) to ensure that the double tap timer has expired.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems to be it, thanks for the tip.

@justinmc justinmc force-pushed the text-field-vertical-align-cupertino branch from 94c8ddd to 47c87a4 Compare June 26, 2019 22:52
@justinmc justinmc force-pushed the text-field-vertical-align-cupertino branch from 47c87a4 to b8c6750 Compare June 26, 2019 22:53
@justinmc justinmc changed the title WIP CupertinoTextField vertical alignment CupertinoTextField vertical alignment Jun 26, 2019
@justinmc justinmc requested a review from HansMuller June 26, 2019 22:54
@justinmc justinmc force-pushed the text-field-vertical-align-cupertino branch from 1af3afa to 082bd29 Compare July 1, 2019 17:34
@justinmc
Copy link
Contributor Author

justinmc commented Jul 1, 2019

Now the clear button and any prefix or suffix will be hit tested by tap events, and if hit, the underlying CupertinoTextField will ignore the events.

Changed so that only the clear button is opaque to tap events. See comments below.

Copy link
Contributor

@HansMuller HansMuller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with some feedback about the details.

void _handleSingleTapUp(TapUpDetails details) {
// Because TextSelectionGestureDetector listens to taps that happen on
// widgets in front of it, tapping the prefix or suffix will also trigger
// this handler here. If this is the case, ignore the tap.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this handler here => this handler.
If this is the case ... => If the the prefix or suffix widget recognizes the up event, then prevent the text field from seeing it.

if (widget.textAlignVertical != null) {
return widget.textAlignVertical;
}
return _hasDecoration ? TextAlignVertical.center : TextAlignVertical.top;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment about backwards compatibility might be helpful here

@@ -742,7 +784,10 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
// Insert a prefix at the front if the prefix visibility mode matches
// the current text state.
if (_showPrefixWidget(text)) {
rowChildren.add(widget.prefix);
rowChildren.add(Container(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

KeyedSubtree instead of Container? Here and below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We talked and decided to remove this behavior on the prefix and suffix, so for now only the clear button will be opaque to tap events, and I'll get rid of these containers.

@@ -633,3 +633,44 @@ class _MixedAlignment extends AlignmentGeometry {
return null;
}
}

/// The vertical alignment of text within an input.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

input => input field or input box? Here and below.

/// The vertical alignment of text within an input.
///
/// A single [y] value that can range from -1.0 to 1.0. -1.0 aligns to the top
/// of the input so that the top of the first line of text fits within the input
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you used "input box" then:
of the input box, so that the top of the first line of text fits within the box

etc

assert(y >= -1.0 && y <= 1.0);

/// A value ranging from -1.0 to 1.0 that defines the topmost and bottommost
/// locations of the top and bottom of the input text box.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"the input text box", NICE. Maybe: a text input box (here and elsewhere).

/// locations of the top and bottom of the input text box.
final double y;

/// Aligns a TextField's input Text with the topmost location within the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

within the => within a

TextField => TextField's input box.

@@ -650,6 +651,12 @@ void main() {
+ tester.getSize(find.byIcon(CupertinoIcons.add)).width
+ 6.0,
);

// Tapping on the prefix isn't received by the CupertinoTextField.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tapping on the prefix doesn't cause the CupertinoTextField to take the keyboard focus.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing this test after the functionality was removed.

@@ -3087,6 +3102,9 @@ void main() {
),
),
);

tester.binding.window.physicalSizeTestValue = null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Were tests failing because we hadn't reset these values?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! It took me awhile to track it down to this.

// Tapping anywhere inside focuses it.
expect(focusNode.hasFocus, false);
await tester.tapAt(tester.getTopLeft(find.byType(CupertinoTextField)));
await tester.pumpAndSettle(const Duration(milliseconds: 400)); // timer error if no duration
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be the 300ms doubleTap timer from packages/flutter/lib/src/widgets/text_selection.dart. Pump and settle only waits for 100ms, so the timer may survive to the end of the test. Assuming that's correct, you could explicitly add a second 300 ms pump (after a no-args pumpAndSettle) to ensure that the double tap timer has expired.

@justinmc justinmc merged commit 2d2bb6b into flutter:master Jul 3, 2019
@justinmc justinmc deleted the text-field-vertical-align-cupertino branch July 3, 2019 15:22
darrenaustin pushed a commit to darrenaustin/flutter that referenced this pull request Jul 3, 2019
CupertinoTextField now supports vertical alignment via the textAlignVertical parameter.
tango5614 added a commit to tango5614/flutter that referenced this pull request Jul 4, 2019
* commit 'a0c47e2216a2b50b70c478001cf5652f31a783af': (187 commits)
  Do not use ideographic baseline for RenderPargraph baseline (flutter#35493)
  Add type to StreamChannel in generated test code. (flutter#35367)
  Fix RenderFittedBox when child.size.isEmpty (flutter#35487)
  add APK build time benchmarks (flutter#35481)
  fix Selection handles position is off (flutter#34665)
  Move usage flutter create tests into memory filesystem. (flutter#35160)
  Include tags in SemanticsNode debug properties (flutter#35491)
  Re-apply 'Add currentSystemFrameTimeStamp to SchedulerBinding' (flutter#35492)
  CupertinoTextField vertical alignment (flutter#34723)
  Mark update-packages as non-experimental (flutter#35467)
  fix default artifacts to exclude ios and android (flutter#35303)
  Roll engine ffba2f6..7d3e722 (59 commits) (flutter#35489)
  Update macrobenchmarks README and app name (flutter#35477)
  mark windows and macos chrome dev mode as flaky (flutter#35495)
  Use the new service protocol message names (flutter#35482)
  Manual roll of engine 45b66b7...ffba2f6 (flutter#35464)
  more ui-as-code (flutter#35393)
  update reassemble doc (flutter#35164)
  New parameter for RawGestureDetector to customize semantics mapping (flutter#33936)
  Add --target support for Windows and Linux (flutter#34660)
  ...
johnsonmh pushed a commit to johnsonmh/flutter that referenced this pull request Jul 30, 2019
CupertinoTextField now supports vertical alignment via the textAlignVertical parameter.
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 5, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
f: cupertino flutter/packages/flutter/cupertino repository framework flutter/packages/flutter repository. See also f: labels.
Projects
None yet
3 participants