Skip to content

Commit 3d2a176

Browse files
authored
android: restore vertical centering for content-hugging custom top-bar buttons (#8332)
* fix(android): size custom top-bar buttons to content height for vertical centering * test(android): assert content-height (AT_MOST) for custom top-bar buttons
1 parent ecbc064 commit 3d2a176

2 files changed

Lines changed: 18 additions & 14 deletions

File tree

android/src/main/java/com/reactnativenavigation/views/stack/topbar/titlebar/TitleBarReactButtonView.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,12 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
5050
// before the content has laid out that width is collapsed (~1px), Fabric lays the content into
5151
// it and the button never recovers (#8320/#8326 did this and regressed under the New Arch).
5252
//
53-
// Height: EXACTLY the available bar height. Giving the surface a filled height (rather than a
54-
// content-hugging AT_MOST height) lets content that centers itself (e.g. a flex container with
55-
// justifyContent: 'center') sit vertically centered in the bar, matching the legacy layout.
56-
// It does not cause the width collapse — only a forced width does.
53+
// Height: bounded (AT_MOST) so the surface sizes to its content height. The view is then
54+
// centered vertically by the toolbar's action-view layout and the CENTER_VERTICAL gravity set
55+
// in onViewAdded(). Forcing EXACTLY the full bar height (as #8328 did) made the surface fill
56+
// the bar, so content-hugging buttons that don't self-center (plain text like "Publish", a
57+
// fixed-size avatar image) were pinned to the top. AT_MOST height does NOT cause the width
58+
// collapse — only a forced EXACTLY *width* does.
5759
int widthSpec = component.width.hasValue()
5860
? createExactSpec(component.width)
5961
: makeMeasureSpec(resolveAvailableWidth(widthMeasureSpec), AT_MOST);
@@ -66,7 +68,7 @@ private int createHeightSpec(int measureSpec, Number dimension) {
6668
return createExactSpec(dimension);
6769
}
6870
int availableSize = MeasureSpec.getSize(measureSpec);
69-
return makeMeasureSpec(availableSize > 0 ? availableSize : Math.max(resolveActionBarSize(), 1), EXACTLY);
71+
return makeMeasureSpec(availableSize > 0 ? availableSize : Math.max(resolveActionBarSize(), 1), AT_MOST);
7072
}
7173

7274
private int resolveAvailableWidth(int measureSpec) {

android/src/test/java/com/reactnativenavigation/views/TitleBarReactButtonViewTest.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,14 @@ public class TitleBarReactButtonViewTest extends BaseTest {
3434

3535
// Without explicit dimensions the button measures the hosted React surface ONCE:
3636
// - width AT_MOST → the surface sizes itself to its content (max-of-children under Fabric).
37-
// - height EXACTLY the available bar height → the surface gets a filled box so content that
38-
// centers itself (flex justifyContent: 'center') stays vertically centered in the bar.
37+
// - height AT_MOST → the surface sizes to its content height; the view is then centered
38+
// vertically in the bar by the toolbar's action-view layout + the CENTER_VERTICAL gravity from
39+
// onViewAdded(). A forced EXACTLY full-bar height would pin content-hugging buttons (plain
40+
// text, a fixed-size avatar) to the top.
3941
// It deliberately does not push a forced EXACTLY *width*; under the New Architecture that re-pushes
4042
// a (initially collapsed) width to the async Fabric layout and the button never recovers.
4143
@Test
42-
public void missingDimensionsSizeWidthToContentAndFillHeight() {
44+
public void missingDimensionsSizeToContent() {
4345
Activity activity = newActivity();
4446
TitleBarReactButtonView uut = createView(activity, new ComponentOptions());
4547
RecordingContentView child = new RecordingContentView(activity);
@@ -48,11 +50,11 @@ public void missingDimensionsSizeWidthToContentAndFillHeight() {
4850
uut.measure(makeMeasureSpec(PARENT_WIDTH, AT_MOST), makeMeasureSpec(PARENT_HEIGHT, AT_MOST));
4951

5052
assertThat(uut.getMeasuredWidth()).isEqualTo(CHILD_WIDTH);
51-
assertThat(uut.getMeasuredHeight()).isEqualTo(PARENT_HEIGHT);
53+
assertThat(uut.getMeasuredHeight()).isEqualTo(CHILD_HEIGHT);
5254
assertThat(child.widthMeasureSpecs.size()).isEqualTo(1);
5355
assertThat(getMode(child.widthMeasureSpecs.get(0))).isEqualTo(AT_MOST);
5456
assertThat(getSize(child.widthMeasureSpecs.get(0))).isEqualTo(PARENT_WIDTH);
55-
assertThat(getMode(child.heightMeasureSpecs.get(0))).isEqualTo(EXACTLY);
57+
assertThat(getMode(child.heightMeasureSpecs.get(0))).isEqualTo(AT_MOST);
5658
assertThat(getSize(child.heightMeasureSpecs.get(0))).isEqualTo(PARENT_HEIGHT);
5759
}
5860

@@ -78,7 +80,7 @@ public void explicitDimensionsMeasureExactly() {
7880
}
7981

8082
@Test
81-
public void zeroParentSpecsFallBackToScreenWidthAndActionBarHeight() {
83+
public void zeroParentSpecsFallBackToScreenWidthAndBoundedActionBarHeight() {
8284
Activity activity = newActivity();
8385
TitleBarReactButtonView uut = createView(activity, new ComponentOptions());
8486
RecordingContentView child = new RecordingContentView(activity);
@@ -90,12 +92,12 @@ public void zeroParentSpecsFallBackToScreenWidthAndActionBarHeight() {
9092
assertThat(getMode(child.widthMeasureSpecs.get(0))).isEqualTo(AT_MOST);
9193
assertThat(getSize(child.widthMeasureSpecs.get(0)))
9294
.isEqualTo(Math.max(activity.getResources().getDisplayMetrics().widthPixels, 1));
93-
assertThat(getMode(child.heightMeasureSpecs.get(0))).isEqualTo(EXACTLY);
95+
assertThat(getMode(child.heightMeasureSpecs.get(0))).isEqualTo(AT_MOST);
9496
assertThat(getSize(child.heightMeasureSpecs.get(0))).isEqualTo(Math.max(resolveActionBarSize(activity), 1));
9597
}
9698

9799
@Test
98-
public void rtlMissingDimensionsUseBoundedWidthAndFilledHeight() {
100+
public void rtlMissingDimensionsUseBoundedWidthAndHeight() {
99101
Activity activity = newActivity();
100102
TitleBarReactButtonView uut = createView(activity, new ComponentOptions());
101103
RecordingContentView child = new RecordingContentView(activity);
@@ -107,7 +109,7 @@ public void rtlMissingDimensionsUseBoundedWidthAndFilledHeight() {
107109
assertThat(child.widthMeasureSpecs.size()).isEqualTo(1);
108110
assertThat(getMode(child.widthMeasureSpecs.get(0))).isEqualTo(AT_MOST);
109111
assertThat(getSize(child.widthMeasureSpecs.get(0))).isEqualTo(PARENT_WIDTH);
110-
assertThat(getMode(child.heightMeasureSpecs.get(0))).isEqualTo(EXACTLY);
112+
assertThat(getMode(child.heightMeasureSpecs.get(0))).isEqualTo(AT_MOST);
111113
assertThat(getSize(child.heightMeasureSpecs.get(0))).isEqualTo(PARENT_HEIGHT);
112114
}
113115

0 commit comments

Comments
 (0)