Skip to content

Update InputDecorator et al - #13734

Merged
HansMuller merged 38 commits into
flutter:masterfrom
HansMuller:input_decorator
Jan 8, 2018
Merged

HansMuller merged 38 commits into
flutter:masterfrom
HansMuller:input_decorator

Conversation

@HansMuller

@HansMuller HansMuller commented Dec 21, 2017 •

Copy link
Copy Markdown
Contributor

Updates the appearance of InputDecorator which updates the appearance of most TextFields.

There's a short video of the new InputDecorator in action on YouTube. The screenshot below shows some of the new InputDecorator configurations.

demo_screenshot

InputDecorator "container"

In the descriptions of the new input decorator's features that follow the term 'container' is often used to refer to the areas highlighted in the screenshots below:

container1
container2

New Features

This version of InputDecorator is largely API compatible with the current one. Some new visual elements have been added and the internal layout has changed a bit.

  • The prefixIcon and suffixIcon appear at the leading or trailing edge of the input. Unlike the icon, they appear within the decorator's container.

    In the screenshot below the suffixIcon appears on the right (because the prevailing text direction is LTR):

    screenshot

    This screenshot shows an input decorator with icon and contentPadding that eliminates the default horizontal 12dps padding with the decorator's container.

    icon

  • The container part of the decorator can be filled with filled: true and the color can be specified with fillColor: color.

  • What was called the "divider" is now a configurable border. Specifying border: const OutlineInputBorder() draw's an outline around the decorator's container, border: const UnderlineInputBorder() underlines the input as before, and border: null doesn't draw anything (same as hideDivider: true in the previous version).

  • When the decorator is outlined, the floating label animates into a gap in the border.

    The screenshots below show the decorator's label when the text field lacks the focus, and the floating label when it gains the focus.

    label
    floating_label

  • When the errorText first appears it "shakes" left and right to get the user's attention.

  • The default padding of the decorator's content can be overridden with contentPadding: edgeInsets. For example to generate a layout that's similar to the current Input decorator: contentPadding: const EdgeInsets.only(bottom: 8.0, top: 16.0).

Incompatible Changes

  • The hideDivider property has been replaced by border: null.
  • The layout of the InputDecorator's elements has changed. The "inline" elements, like the input child, the labelText and hintText, are now padded 12 dps on the left and right if filled is true. The vertical padding is also different: previously there was 16dps above the floating label, and 8dps below the inline elements, now its 12dps above and below.
  • The labelText's location is a little different. It's vertically centered within the input decorator's container when isFocus is true or isEmpty is false. When the labelText is "floating"
    it appears within a gap within the InputBorderType.outline or just a little lower than before for InputBorderType.underline.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

trivial nit: vertically align the subexpressions (i.e. indent by 3 more)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

convert into a TODO() or fix or remove as appropriate

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ditto

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ditto

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

should we just fill if fillColor is non-null, and not fill if it's null?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Most apps will not want to actually specify a fill color, they'll just the default one that's based on the theme's brightness.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

(that would work better in a world where there's a way to configure the fill color in the theme explicitly)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I agree. What might work best here is an InputDecoratorTheme which would be part of ThemeData like IconTheme and textTheme. I will add that in a follow-up PR.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

it'd be mildly more efficient to do hashValues(..., hashValues(...))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

looks like you don't actually use the textDirection in _precache?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

oops

@Hixie

Hixie commented Dec 21, 2017

Copy link
Copy Markdown
Contributor

My main feedback is that instead of an enum for the borderType, I would just define an abstract subclass of ShapeBorder (similar to what you have), and then have people provide instances of subclasses of that subclass as the borderType (call it just shape, probably, to match what @amirh is doing). That way you get two benefits: one, your shape border class gets split into two simpler ones since now each one only has to deal with one border style, and two, people get to build their own crazy border styles if they want to.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

you should also check the animation is the same

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i think this whole method can just assert false, not reachable

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

if you skip the default case, then the analyzer will catch cases where you have an unrecognized one for you

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

TBD->todo or fix

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

->TODO or fix

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think the gapAnimation should probably be an argument to the paint method. You don't use it anywhere else as far as I can tell, and passing in a Listenable to a class without a lifecycle is a little scary (is it going to listen to it? i don't know!).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, that seems reasonable.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I replaced gapAnimation with gapPercentage, which is just the animation's value.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can you elaborate on why it's important that they be circular?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The label text's gap can extend into the corners (even both the top left and top right corners) and I didn't want to bother with the more complicated problem of finding how far the gap penetrated into an elliptical corner. It didn't seem to be an important feature to support now. I suppose the summary rationale is: sloth.

@abarth

abarth commented Dec 22, 2017

Copy link
Copy Markdown
Contributor

Those outline animations are beautiful!

@HansMuller

Copy link
Copy Markdown
Contributor Author

UnderlineInputBorder and OutlineInputBorder and their abstract superclass InputBorder (a ShapeBorder) are public classes that can be used to configure InputDecoration.border. I've removed the borderType parameter and InputBorderType enum.

new TextField(
  decoration: new InputDecoration(
    border: const OutlineInputBorder(),
    labelText: 'Hello World',
  ),
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we should add the following to this class, to avoid needing to hard-code any knowledge about InputBorder's subclasses in any of the other classes, thus allowing people to implement custom InputBorders that are crazier than currently allowed, while also simplifying the rest of the code:

  • add an abstract paint() method that has the arguments that OutlineInputBorder has.
  • add a property that returns an enum that describes how the padding/baseline should be applied (also covers the isOutlineBorder logic in the paint method).

We should also document in the class docs for InputBorder all the ways that this class differs from ShapeBorder, in particular:

  • That it always has a single side style, borderSide.
  • That copies of the class can be made, applying a different style, using copyWith.
  • That the paint method has additional arguments.
  • What the enum property described above is about.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

InputBorder now has an abstract isOutline getter that's used by the renderer to configure the layout. The renderer tests this boolean instead of testing the border's type.

I updated the abstract methods and docs as you suggested.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

for completeness, also add borderRadius and gapPad

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

gapPadding?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, that's better.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we just say "logical pixels", not "dps", in the Flutter documentation

@Hixie Hixie Jan 3, 2018 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

where is the default of 4px implemented? oh, i see, in the getter.

For efficiency it'd be better if that was done in the constructor.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why must the radii be circular?

@HansMuller HansMuller Jan 4, 2018 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This came up before: #13734 (comment)

I added a comment with the explanation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

assuming

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

use a switch

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

assert circular

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Now checked at the top of CircularInputBorder.paint().

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

TODO should be actionable

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This code isn't used so for now it's assert(false, 'not implemented').

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

prefer switch instead of if when checking an enum value

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

@HansMuller
HansMuller merged commit d188a8f into flutter:master Jan 8, 2018
final double t = decoration.floatingLabelProgress;
// The center of the outline border label ends up a little below the
// center of the top border line.
final double floatingY = decoration.border.isOutline ? -labelHeight * 0.25 : contentPadding.top;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

this line throws an exception if border: null and a labelText is used

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sorry to have missed this. I've filed and issue and will fix:
#14165

DaveShuckerow pushed a commit to DaveShuckerow/flutter that referenced this pull request May 14, 2018
@justinmc justinmc mentioned this pull request Apr 27, 2020
@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Aug 11, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants