Skip to content

Conversation

@victorsanni
Copy link
Contributor

@victorsanni victorsanni commented Oct 21, 2025

This PR makes CupertinoTextField's placeholder and editable text position respect CupertinoTextField.textAlignVertical.

Image comparison
Before After
top top b4 top
center top b4 center
bottom top b4 bottom
Sample code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main() => runApp(const TextFieldApp());

class TextFieldApp extends StatelessWidget {
  const TextFieldApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(home: HomePage());
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  TextEditingController commentController = TextEditingController();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey,
      body: SafeArea(
        child: Center(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: CupertinoTextField(
              style: const TextStyle(fontSize: 40),
              placeholderStyle: const TextStyle(
                fontSize: 80,
                color: CupertinoColors.inactiveGray,
              ),
              placeholder: 'Enter text',
              textAlignVertical: TextAlignVertical.bottom,
            ),
          ),
        ),
      ),
    );
  }
}

Fixes CupertinoTextField text not vertically centered when fontSize differs between style and placeholderStyle.

@github-actions github-actions bot added a: text input Entering text in a text field or keyboard related problems framework flutter/packages/flutter repository. See also f: labels. f: cupertino flutter/packages/flutter/cupertino repository labels Oct 21, 2025
@victorsanni victorsanni marked this pull request as ready for review October 23, 2025 21:29
Copy link
Contributor

@justinmc justinmc left a comment

Choose a reason for hiding this comment

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

LGTM 👍

I guess it's possible this will break visual diff tests, so let's see what the Google tests say.

Comment on lines 1392 to +1395
child: _BaselineAlignedStack(
placeholder: placeholder,
editableText: editableText,
textAlignVertical: _textAlignVertical,
Copy link
Contributor

Choose a reason for hiding this comment

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

Ok so previously the placeholder and the EditableText were aligned by baseline. However, when they have different font sizes, this might look wrong (as seen in the screenshots in the description of #176817). Now with this PR it will default to center, which looks correct when the font sizes differ, and otherwise it's configurable with the textAlignVertical parameter.

Am I understanding correctly?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Partly.

This PR doesn't change the default. The wrong look happened because the position of the placeholder and editable text was slightly wrong (wrong calculations) and also wasn't configurable (even though the property textAlignVertical existed).

textAlignVertical originally wrapped the text dependent attachments (placeholder, editable text etc.) in an Align. My understanding (but might be wrong) is in writing our own renderbox, we now arbitrarily fixed the position of the placeholder + editable text in the entire space the Align contained, making the Align uneffective.

This PR basically copies over the alignment into the renderbox positioning so it is respected.

required this.editableTextBaseline,
required this.placeholderBaseline,
required this.editableText,
required this.textAlignVertical,
Copy link
Member

@loic-sharma loic-sharma Oct 24, 2025

Choose a reason for hiding this comment

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

Should we make textAlignVertical before the editableText parameter?

It feels a little weird that textAlignVertical is in between editableText and placeholder. It feels like we're "interrupting" the section of children arguments, if that makes sense.

This would also match the order used by the fields below.

Copy link
Member

@loic-sharma loic-sharma left a comment

Choose a reason for hiding this comment

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

LGTM

Expanded(
child: Directionality(
textDirection: widget.textDirection ?? Directionality.of(context),
child: _BaselineAlignedStack(
Copy link
Member

@loic-sharma loic-sharma Oct 24, 2025

Choose a reason for hiding this comment

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

This seems like a useful widget. Should we add a generic version of this widget to the widgets library? I imagine other design systems would want to use this.

This isn't a blocker for landing this PR. Just an idea for future improvement :)

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'm wondering if we can just do this by adding a flag to Stack. The problem would be knowing which child's baseline should be the reference baseline.

I do think this is very doable though. Off the top of my head I think the API could have two main properties: a child with a reference baseline and children for all the other widgets that should be aligned to that baseline. Although if we know the baseline distance for the reference child's renderbox, we can use that number to align other children in a Stack by wrapping each child in a Baseline.

But getting the reference child's renderbox outside layout might be problematic (using a post frame callback can mitigate this, but that has its problems as well). So it's a good argument for writing a custom renderobject for this, but (correct me if I'm wrong here) that will mean we will have to manually position the children instead of relying on Baseline to simplify the work.

Copy link
Member

@loic-sharma loic-sharma Oct 24, 2025

Choose a reason for hiding this comment

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

Maybe we could do something like this:

BaselineStack(
  alignment: Alignment.top,
  children: [
    child1,
    BaselineReference(child: child2),
    child3,
  ],
),

BaselineReference must be the child of a BaselineStack (similar to how Flexible and Expanded must be the direct child of a Row/Colum/Flex)

Copy link
Contributor Author

@victorsanni victorsanni Oct 27, 2025

Choose a reason for hiding this comment

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

I've always been confused by the Row/Column/Flex and Flexible/Expanded API because forcing a widget to only have a specific parent/child relationship introduces additional cognitive complexity.

Since all we need here is a reference baseline (so no Positioned widget as in Stack), I'm strongly inclined to an API that separates the child with the reference baseline from the other children. And this API means we can require the reference child but not necessarily the other children.

I do think we need some sort of intermediary configuration class that wraps both the reference child and other children. This is so that the TextBaseline for each child can be provided. Or is there an alternative way to provide the TextBaseline for each child?

Copy link
Member

Choose a reason for hiding this comment

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

Since all we need here is a reference baseline (so no Positioned widget as in Stack), I'm strongly inclined to an API that separates the child with the reference baseline from the other children. And this API means we can require the reference child but not necessarily the other children.

That's fair. Another alternative might be:

BaselineStack(
  alignment: Alignment.top,
  baselineReferenceIndex: 1,
  children: [
    child1,
    child2,
    child3,
  ],
),

@victorsanni victorsanni added the autosubmit Merge PR when tree becomes green via auto submit App label Oct 27, 2025
@auto-submit auto-submit bot added this pull request to the merge queue Oct 27, 2025
Merged via the queue into flutter:master with commit df3867e Oct 27, 2025
77 of 78 checks passed
@flutter-dashboard flutter-dashboard bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Oct 27, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Oct 28, 2025
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Oct 28, 2025
flutter/flutter@4c91098...7cf0dc1

2025-10-28 [email protected] Roll Skia from 602bbd4af8f9 to e4d3d8f31aef (4 revisions) (flutter/flutter#177647)
2025-10-28 [email protected] Fix AppBar Semantics namesRoute for mismatched platforms (flutter/flutter#176694)
2025-10-28 [email protected] Fix Popup menu Semantics label for mismatched platforms (flutter/flutter#177049)
2025-10-28 [email protected] Roll Skia from 8b2d056701df to 602bbd4af8f9 (1 revision) (flutter/flutter#177628)
2025-10-28 [email protected] Roll Skia from 5723f87f8530 to 8b2d056701df (3 revisions) (flutter/flutter#177626)
2025-10-27 [email protected] Roll Skia from 170c11f1ddc5 to 5723f87f8530 (6 revisions) (flutter/flutter#177618)
2025-10-27 [email protected] Enhance DropdownMenuEntry's labelWidget docs (flutter/flutter#177160)
2025-10-27 [email protected] Regenerated lockfiles for New Template Values (flutter/flutter#177617)
2025-10-27 [email protected] Correct editable text and placeholder position in baseline aligned stack (flutter/flutter#177342)
2025-10-27 49699333+dependabot[bot]@users.noreply.github.com Bump actions/upload-artifact from 4 to 5 in the all-github-actions group (flutter/flutter#177620)
2025-10-27 [email protected] add gn flag to optimize builds for size (flutter/flutter#176835)
2025-10-27 [email protected] disable metal for crosscompile from mac to linux (flutter/flutter#176639)
2025-10-27 [email protected] [DDM] enable host builds in the merge queue (flutter/flutter#177446)
2025-10-27 [email protected] Disable vulkan X11 support when building for minimal linux (flutter/flutter#176697)
2025-10-27 [email protected] Roll Skia from 77348c40d101 to 170c11f1ddc5 (6 revisions) (flutter/flutter#177602)
2025-10-27 [email protected] Set the font weight variation axis based on the text style's FontWeight (flutter/flutter#175771)
2025-10-27 [email protected] Fixed `RuntimeEffect` with `ImageFilter.compose` (flutter/flutter#177510)
2025-10-27 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Clean before building when framework headers change (#177512)" (flutter/flutter#177610)
2025-10-27 [email protected] [skia] Disable legacy png encoding/decoding in skp (flutter/flutter#177462)
2025-10-27 [email protected] Clean before building when framework headers change (flutter/flutter#177512)
2025-10-27 [email protected] Roll dartdoc to 9.0.0 (flutter/flutter#177590)
2025-10-27 [email protected] Fix typo in comment about `manifestFile` in `DeepLinkJsonFromManifestTaskHelper.kt‎` (flutter/flutter#177538)
2025-10-27 [email protected] Fix RoundedSuperellipse crashes for tiny corners (flutter/flutter#177070)
2025-10-27 [email protected] Roll Packages from 53d6138 to bbf96a0 (7 revisions) (flutter/flutter#177588)
2025-10-27 [email protected] Fix missing list indicators in CHANGELOG.md (flutter/flutter#177484)
2025-10-27 [email protected] [ Tool ] Add `Stream.transformWithCallSite` to provide more useful stack traces (flutter/flutter#177470)
2025-10-27 [email protected] Roll Skia from 06243224ecf0 to 77348c40d101 (1 revision) (flutter/flutter#177585)
2025-10-27 [email protected] Add guided error for precompiled cache error (flutter/flutter#177327)
2025-10-27 [email protected] Roll Fuchsia Linux SDK from tKrvmvTOQITL81oOC... to ir6J2isKAYa1jNLyJ... (flutter/flutter#177578)
2025-10-27 [email protected] Roll Skia from 784ed1787bd6 to 06243224ecf0 (1 revision) (flutter/flutter#177575)
2025-10-27 [email protected] Roll Skia from de52b3a7585a to 784ed1787bd6 (5 revisions) (flutter/flutter#177571)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
@victorsanni victorsanni deleted the text-field-align branch October 30, 2025 22:07
flutter-zl pushed a commit that referenced this pull request Oct 31, 2025
…ack (#177342)

This PR makes CupertinoTextField's placeholder and editable text
position respect `CupertinoTextField.textAlignVertical`.

<details open>
<summary>Image comparison</summary>

| | Before | After | 
| --- | --- | --- |
| top | <img width="436" height="327" alt="top b4"
src="https://github.com/user-attachments/assets/39606c72-fb1f-4619-bfb2-ccaeaf502324"
/> | <img width="436" height="327" alt="top"
src="https://github.com/user-attachments/assets/faea26fc-c934-4660-bbee-e62effa44599"
/> |
| center | <img width="436" height="327" alt="top b4"
src="https://github.com/user-attachments/assets/39606c72-fb1f-4619-bfb2-ccaeaf502324"
/> | <img width="436" height="327" alt="center"
src="https://github.com/user-attachments/assets/2ee7004a-6f70-4af2-b33b-76293c8deac1"
/> |
| bottom | <img width="436" height="327" alt="top b4"
src="https://github.com/user-attachments/assets/39606c72-fb1f-4619-bfb2-ccaeaf502324"
/> | <img width="436" height="327" alt="bottom"
src="https://github.com/user-attachments/assets/69ba89fb-9f1c-456e-9889-216eb31d66b9"
/> |

</details>

<details>
<summary>Sample code</summary>

```dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main() => runApp(const TextFieldApp());

class TextFieldApp extends StatelessWidget {
  const TextFieldApp({super.key});

  @OverRide
  Widget build(BuildContext context) {
    return const MaterialApp(home: HomePage());
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @OverRide
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  TextEditingController commentController = TextEditingController();
  @OverRide
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey,
      body: SafeArea(
        child: Center(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: CupertinoTextField(
              style: const TextStyle(fontSize: 40),
              placeholderStyle: const TextStyle(
                fontSize: 80,
                color: CupertinoColors.inactiveGray,
              ),
              placeholder: 'Enter text',
              textAlignVertical: TextAlignVertical.bottom,
            ),
          ),
        ),
      ),
    );
  }
}

```

</details>

Fixes [CupertinoTextField text not vertically centered when fontSize
differs between style and
placeholderStyle.](#176817)
reidbaker pushed a commit to AbdeMohlbi/flutter that referenced this pull request Dec 10, 2025
…ack (flutter#177342)

This PR makes CupertinoTextField's placeholder and editable text
position respect `CupertinoTextField.textAlignVertical`.

<details open>
<summary>Image comparison</summary>

| | Before | After | 
| --- | --- | --- |
| top | <img width="436" height="327" alt="top b4"
src="https://github.com/user-attachments/assets/39606c72-fb1f-4619-bfb2-ccaeaf502324"
/> | <img width="436" height="327" alt="top"
src="https://github.com/user-attachments/assets/faea26fc-c934-4660-bbee-e62effa44599"
/> |
| center | <img width="436" height="327" alt="top b4"
src="https://github.com/user-attachments/assets/39606c72-fb1f-4619-bfb2-ccaeaf502324"
/> | <img width="436" height="327" alt="center"
src="https://github.com/user-attachments/assets/2ee7004a-6f70-4af2-b33b-76293c8deac1"
/> |
| bottom | <img width="436" height="327" alt="top b4"
src="https://github.com/user-attachments/assets/39606c72-fb1f-4619-bfb2-ccaeaf502324"
/> | <img width="436" height="327" alt="bottom"
src="https://github.com/user-attachments/assets/69ba89fb-9f1c-456e-9889-216eb31d66b9"
/> |

</details>

<details>
<summary>Sample code</summary>

```dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main() => runApp(const TextFieldApp());

class TextFieldApp extends StatelessWidget {
  const TextFieldApp({super.key});

  @OverRide
  Widget build(BuildContext context) {
    return const MaterialApp(home: HomePage());
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @OverRide
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  TextEditingController commentController = TextEditingController();
  @OverRide
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey,
      body: SafeArea(
        child: Center(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: CupertinoTextField(
              style: const TextStyle(fontSize: 40),
              placeholderStyle: const TextStyle(
                fontSize: 80,
                color: CupertinoColors.inactiveGray,
              ),
              placeholder: 'Enter text',
              textAlignVertical: TextAlignVertical.bottom,
            ),
          ),
        ),
      ),
    );
  }
}

```

</details>

Fixes [CupertinoTextField text not vertically centered when fontSize
differs between style and
placeholderStyle.](flutter#176817)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: text input Entering text in a text field or keyboard related problems f: cupertino flutter/packages/flutter/cupertino repository framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CupertinoTextField text not vertically centered when fontSize differs between style and placeholderStyle.

3 participants