react-native-navigation 8.8.7 → 8.8.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -3,7 +3,9 @@ package com.reactnativenavigation.views.stack.topbar.titlebar;
|
|
|
3
3
|
import android.annotation.SuppressLint;
|
|
4
4
|
import android.content.Context;
|
|
5
5
|
import android.util.TypedValue;
|
|
6
|
+
import android.view.Gravity;
|
|
6
7
|
import android.view.View;
|
|
8
|
+
import android.widget.FrameLayout;
|
|
7
9
|
|
|
8
10
|
import com.reactnativenavigation.options.ComponentOptions;
|
|
9
11
|
import com.reactnativenavigation.options.params.Number;
|
|
@@ -16,6 +18,7 @@ import static com.reactnativenavigation.utils.UiUtils.dpToPx;
|
|
|
16
18
|
|
|
17
19
|
@SuppressLint("ViewConstructor")
|
|
18
20
|
public class TitleBarReactButtonView extends ReactView {
|
|
21
|
+
private static final float FINAL_WIDTH_PADDING_DP = 1f;
|
|
19
22
|
private final ComponentOptions component;
|
|
20
23
|
|
|
21
24
|
public TitleBarReactButtonView(Context context, ComponentOptions component) {
|
|
@@ -23,6 +26,17 @@ public class TitleBarReactButtonView extends ReactView {
|
|
|
23
26
|
this.component = component;
|
|
24
27
|
}
|
|
25
28
|
|
|
29
|
+
@Override
|
|
30
|
+
public void onViewAdded(View child) {
|
|
31
|
+
super.onViewAdded(child);
|
|
32
|
+
if (child.getLayoutParams() instanceof FrameLayout.LayoutParams) {
|
|
33
|
+
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) child.getLayoutParams();
|
|
34
|
+
layoutParams.gravity = layoutParams.gravity == -1
|
|
35
|
+
? Gravity.CENTER_VERTICAL
|
|
36
|
+
: (layoutParams.gravity & ~Gravity.VERTICAL_GRAVITY_MASK) | Gravity.CENTER_VERTICAL;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
26
40
|
@Override
|
|
27
41
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
28
42
|
// This is a workaround, ReactNative throws exception when views have ids, On android MenuItems
|
|
@@ -31,32 +45,44 @@ public class TitleBarReactButtonView extends ReactView {
|
|
|
31
45
|
this.setId(View.NO_ID);
|
|
32
46
|
}
|
|
33
47
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
);
|
|
38
|
-
|
|
48
|
+
int initialWidthSpec = component.width.hasValue()
|
|
49
|
+
? createExactSpec(component.width)
|
|
50
|
+
: makeMeasureSpec(resolveAvailableWidth(widthMeasureSpec), AT_MOST);
|
|
51
|
+
int initialHeightSpec = createHeightSpec(heightMeasureSpec, component.height);
|
|
52
|
+
|
|
53
|
+
// First discover the content size without forcing every custom button to actionBarSize.
|
|
54
|
+
super.onMeasure(initialWidthSpec, initialHeightSpec);
|
|
39
55
|
|
|
40
|
-
|
|
41
|
-
|
|
56
|
+
if (component.width.hasValue() && component.height.hasValue()) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Then give RN/Yoga a stable exact final box for compatibility with centered button layouts.
|
|
61
|
+
// A small allowance avoids clipping implicit RN padding/subpixel layout while staying content-based.
|
|
62
|
+
int finalWidth = component.width.hasValue()
|
|
63
|
+
? MeasureSpec.getSize(initialWidthSpec)
|
|
64
|
+
: resolveFinalWidth(getMeasuredWidth());
|
|
65
|
+
int finalHeight = component.height.hasValue()
|
|
66
|
+
? MeasureSpec.getSize(initialHeightSpec)
|
|
67
|
+
: Math.max(getMeasuredHeight(), 1);
|
|
68
|
+
super.onMeasure(makeMeasureSpec(finalWidth, EXACTLY), makeMeasureSpec(finalHeight, EXACTLY));
|
|
42
69
|
}
|
|
43
70
|
|
|
44
71
|
private int createHeightSpec(int measureSpec, Number dimension) {
|
|
45
72
|
if (dimension.hasValue()) {
|
|
46
73
|
return createExactSpec(dimension);
|
|
47
74
|
}
|
|
48
|
-
|
|
75
|
+
int availableSize = MeasureSpec.getSize(measureSpec);
|
|
76
|
+
return makeMeasureSpec(availableSize > 0 ? availableSize : Math.max(resolveActionBarSize(), 1), AT_MOST);
|
|
49
77
|
}
|
|
50
78
|
|
|
51
|
-
private int
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return makeMeasureSpec(availableSize > 0 ? availableSize : fallbackSize, AT_MOST);
|
|
59
|
-
}
|
|
79
|
+
private int resolveAvailableWidth(int measureSpec) {
|
|
80
|
+
int availableSize = MeasureSpec.getSize(measureSpec);
|
|
81
|
+
return availableSize > 0 ? availableSize : Math.max(getResources().getDisplayMetrics().widthPixels, 1);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private int resolveFinalWidth(int measuredContentWidth) {
|
|
85
|
+
return Math.max(measuredContentWidth + (int) Math.ceil(dpToPx(getContext(), FINAL_WIDTH_PADDING_DP)), 1);
|
|
60
86
|
}
|
|
61
87
|
|
|
62
88
|
private int createExactSpec(Number dimension) {
|
package/android/src/test/java/com/reactnativenavigation/views/TitleBarReactButtonViewTest.java
CHANGED
|
@@ -9,8 +9,10 @@ import static org.assertj.core.api.Java6Assertions.assertThat;
|
|
|
9
9
|
|
|
10
10
|
import android.app.Activity;
|
|
11
11
|
import android.util.TypedValue;
|
|
12
|
+
import android.view.Gravity;
|
|
12
13
|
import android.view.View;
|
|
13
14
|
import android.view.ViewGroup;
|
|
15
|
+
import android.widget.FrameLayout;
|
|
14
16
|
|
|
15
17
|
import com.reactnativenavigation.BaseTest;
|
|
16
18
|
import com.reactnativenavigation.options.ComponentOptions;
|
|
@@ -21,6 +23,9 @@ import com.reactnativenavigation.views.stack.topbar.titlebar.TitleBarReactButton
|
|
|
21
23
|
|
|
22
24
|
import org.junit.Test;
|
|
23
25
|
|
|
26
|
+
import java.util.ArrayList;
|
|
27
|
+
import java.util.List;
|
|
28
|
+
|
|
24
29
|
public class TitleBarReactButtonViewTest extends BaseTest {
|
|
25
30
|
private static final int PARENT_WIDTH = 200;
|
|
26
31
|
private static final int PARENT_HEIGHT = 100;
|
|
@@ -28,15 +33,25 @@ public class TitleBarReactButtonViewTest extends BaseTest {
|
|
|
28
33
|
private static final int CHILD_HEIGHT = 16;
|
|
29
34
|
|
|
30
35
|
@Test
|
|
31
|
-
public void
|
|
36
|
+
public void missingDimensionsMeasureToContentThenRemeasureExactForStableAlignment() {
|
|
32
37
|
Activity activity = newActivity();
|
|
33
38
|
TitleBarReactButtonView uut = createView(activity, new ComponentOptions());
|
|
34
|
-
|
|
39
|
+
RecordingContentView child = new RecordingContentView(activity);
|
|
40
|
+
setContentView(uut, child);
|
|
35
41
|
|
|
36
42
|
uut.measure(makeMeasureSpec(PARENT_WIDTH, AT_MOST), makeMeasureSpec(PARENT_HEIGHT, AT_MOST));
|
|
37
43
|
|
|
38
|
-
assertThat(uut.getMeasuredWidth()).isEqualTo(
|
|
39
|
-
assertThat(uut.getMeasuredHeight()).isEqualTo(
|
|
44
|
+
assertThat(uut.getMeasuredWidth()).isEqualTo(finalWidth(activity));
|
|
45
|
+
assertThat(uut.getMeasuredHeight()).isEqualTo(CHILD_HEIGHT);
|
|
46
|
+
assertThat(child.widthMeasureSpecs.size()).isEqualTo(2);
|
|
47
|
+
assertThat(getMode(child.widthMeasureSpecs.get(0))).isEqualTo(AT_MOST);
|
|
48
|
+
assertThat(getSize(child.widthMeasureSpecs.get(0))).isEqualTo(PARENT_WIDTH);
|
|
49
|
+
assertThat(getMode(child.heightMeasureSpecs.get(0))).isEqualTo(AT_MOST);
|
|
50
|
+
assertThat(getSize(child.heightMeasureSpecs.get(0))).isEqualTo(PARENT_HEIGHT);
|
|
51
|
+
assertThat(getMode(child.widthMeasureSpecs.get(1))).isEqualTo(EXACTLY);
|
|
52
|
+
assertThat(getSize(child.widthMeasureSpecs.get(1))).isEqualTo(finalWidth(activity));
|
|
53
|
+
assertThat(getMode(child.heightMeasureSpecs.get(1))).isEqualTo(EXACTLY);
|
|
54
|
+
assertThat(getSize(child.heightMeasureSpecs.get(1))).isEqualTo(CHILD_HEIGHT);
|
|
40
55
|
}
|
|
41
56
|
|
|
42
57
|
@Test
|
|
@@ -46,50 +61,91 @@ public class TitleBarReactButtonViewTest extends BaseTest {
|
|
|
46
61
|
component.width = new Number(72);
|
|
47
62
|
component.height = new Number(32);
|
|
48
63
|
TitleBarReactButtonView uut = createView(activity, component);
|
|
49
|
-
|
|
64
|
+
RecordingContentView child = new RecordingContentView(activity);
|
|
65
|
+
setContentView(uut, child);
|
|
50
66
|
|
|
51
67
|
uut.measure(makeMeasureSpec(PARENT_WIDTH, AT_MOST), makeMeasureSpec(PARENT_HEIGHT, AT_MOST));
|
|
52
68
|
|
|
53
69
|
assertThat(uut.getMeasuredWidth()).isEqualTo(UiUtils.dpToPx(activity, 72));
|
|
54
70
|
assertThat(uut.getMeasuredHeight()).isEqualTo(UiUtils.dpToPx(activity, 32));
|
|
71
|
+
assertThat(child.widthMeasureSpecs.size()).isEqualTo(1);
|
|
72
|
+
assertThat(getMode(child.widthMeasureSpecs.get(0))).isEqualTo(EXACTLY);
|
|
73
|
+
assertThat(getSize(child.widthMeasureSpecs.get(0))).isEqualTo(UiUtils.dpToPx(activity, 72));
|
|
74
|
+
assertThat(getMode(child.heightMeasureSpecs.get(0))).isEqualTo(EXACTLY);
|
|
75
|
+
assertThat(getSize(child.heightMeasureSpecs.get(0))).isEqualTo(UiUtils.dpToPx(activity, 32));
|
|
55
76
|
}
|
|
56
77
|
|
|
57
78
|
@Test
|
|
58
|
-
public void
|
|
79
|
+
public void zeroParentSpecsFallbackToBoundedAtMostSpecs() {
|
|
59
80
|
Activity activity = newActivity();
|
|
60
81
|
TitleBarReactButtonView uut = createView(activity, new ComponentOptions());
|
|
61
|
-
|
|
62
|
-
uut
|
|
63
|
-
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
64
|
-
ViewGroup.LayoutParams.MATCH_PARENT
|
|
65
|
-
));
|
|
82
|
+
RecordingContentView child = new RecordingContentView(activity);
|
|
83
|
+
setContentView(uut, child);
|
|
66
84
|
|
|
67
85
|
uut.measure(makeMeasureSpec(0, AT_MOST), makeMeasureSpec(0, AT_MOST));
|
|
68
86
|
|
|
69
|
-
assertThat(
|
|
70
|
-
assertThat(
|
|
87
|
+
assertThat(child.widthMeasureSpecs.size()).isEqualTo(2);
|
|
88
|
+
assertThat(getMode(child.widthMeasureSpecs.get(0))).isEqualTo(AT_MOST);
|
|
89
|
+
assertThat(getSize(child.widthMeasureSpecs.get(0)))
|
|
71
90
|
.isEqualTo(Math.max(activity.getResources().getDisplayMetrics().widthPixels, 1));
|
|
72
|
-
assertThat(getMode(child.
|
|
73
|
-
assertThat(getSize(child.
|
|
91
|
+
assertThat(getMode(child.widthMeasureSpecs.get(1))).isEqualTo(EXACTLY);
|
|
92
|
+
assertThat(getSize(child.widthMeasureSpecs.get(1))).isEqualTo(finalWidth(activity));
|
|
93
|
+
assertThat(getMode(child.heightMeasureSpecs.get(0))).isEqualTo(AT_MOST);
|
|
94
|
+
assertThat(getSize(child.heightMeasureSpecs.get(0))).isEqualTo(Math.max(resolveActionBarSize(activity), 1));
|
|
95
|
+
assertThat(getMode(child.heightMeasureSpecs.get(1))).isEqualTo(EXACTLY);
|
|
96
|
+
assertThat(getSize(child.heightMeasureSpecs.get(1))).isEqualTo(CHILD_HEIGHT);
|
|
74
97
|
}
|
|
75
98
|
|
|
76
99
|
@Test
|
|
77
100
|
public void rtlMissingDimensionsUseBoundedSpecs() {
|
|
78
101
|
Activity activity = newActivity();
|
|
79
102
|
TitleBarReactButtonView uut = createView(activity, new ComponentOptions());
|
|
80
|
-
|
|
103
|
+
RecordingContentView child = new RecordingContentView(activity);
|
|
81
104
|
uut.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
|
|
82
|
-
uut
|
|
105
|
+
setContentView(uut, child);
|
|
106
|
+
|
|
107
|
+
uut.measure(makeMeasureSpec(PARENT_WIDTH, AT_MOST), makeMeasureSpec(PARENT_HEIGHT, AT_MOST));
|
|
108
|
+
|
|
109
|
+
assertThat(child.widthMeasureSpecs.size()).isEqualTo(2);
|
|
110
|
+
assertThat(getMode(child.widthMeasureSpecs.get(0))).isEqualTo(AT_MOST);
|
|
111
|
+
assertThat(getSize(child.widthMeasureSpecs.get(0))).isEqualTo(PARENT_WIDTH);
|
|
112
|
+
assertThat(getMode(child.widthMeasureSpecs.get(1))).isEqualTo(EXACTLY);
|
|
113
|
+
assertThat(getSize(child.widthMeasureSpecs.get(1))).isEqualTo(finalWidth(activity));
|
|
114
|
+
assertThat(getMode(child.heightMeasureSpecs.get(1))).isEqualTo(EXACTLY);
|
|
115
|
+
assertThat(getSize(child.heightMeasureSpecs.get(1))).isEqualTo(CHILD_HEIGHT);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@Test
|
|
119
|
+
public void contentRemainsCenteredWhenMenuCellLaysButtonOutTallerThanMeasuredHeight() {
|
|
120
|
+
Activity activity = newActivity();
|
|
121
|
+
TitleBarReactButtonView uut = createView(activity, new ComponentOptions());
|
|
122
|
+
RecordingContentView child = new RecordingContentView(activity);
|
|
123
|
+
setContentView(uut, child);
|
|
124
|
+
|
|
125
|
+
uut.measure(makeMeasureSpec(PARENT_WIDTH, AT_MOST), makeMeasureSpec(PARENT_HEIGHT, AT_MOST));
|
|
126
|
+
uut.layout(0, 0, uut.getMeasuredWidth(), PARENT_HEIGHT);
|
|
127
|
+
|
|
128
|
+
assertThat(uut.getMeasuredHeight()).isEqualTo(CHILD_HEIGHT);
|
|
129
|
+
assertThat(child.getTop()).isEqualTo((PARENT_HEIGHT - CHILD_HEIGHT) / 2);
|
|
130
|
+
assertThat(child.getBottom()).isEqualTo((PARENT_HEIGHT + CHILD_HEIGHT) / 2);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
@Test
|
|
134
|
+
public void contentCenteringReplacesExistingVerticalGravityOnly() {
|
|
135
|
+
Activity activity = newActivity();
|
|
136
|
+
TitleBarReactButtonView uut = createView(activity, new ComponentOptions());
|
|
137
|
+
RecordingContentView child = new RecordingContentView(activity);
|
|
138
|
+
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
|
|
83
139
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
84
140
|
ViewGroup.LayoutParams.MATCH_PARENT
|
|
85
|
-
)
|
|
141
|
+
);
|
|
142
|
+
params.gravity = Gravity.TOP | Gravity.RIGHT;
|
|
86
143
|
|
|
87
|
-
uut.
|
|
144
|
+
uut.addView(child, params);
|
|
88
145
|
|
|
89
|
-
|
|
90
|
-
assertThat(
|
|
91
|
-
assertThat(
|
|
92
|
-
assertThat(getSize(child.lastHeightMeasureSpec)).isEqualTo(resolveActionBarSize(activity));
|
|
146
|
+
FrameLayout.LayoutParams updatedParams = (FrameLayout.LayoutParams) child.getLayoutParams();
|
|
147
|
+
assertThat(updatedParams.gravity & Gravity.VERTICAL_GRAVITY_MASK).isEqualTo(Gravity.CENTER_VERTICAL);
|
|
148
|
+
assertThat(updatedParams.gravity & Gravity.HORIZONTAL_GRAVITY_MASK).isEqualTo(Gravity.RIGHT);
|
|
93
149
|
}
|
|
94
150
|
|
|
95
151
|
private TitleBarReactButtonView createView(Activity activity, ComponentOptions component) {
|
|
@@ -98,6 +154,14 @@ public class TitleBarReactButtonViewTest extends BaseTest {
|
|
|
98
154
|
return new TitleBarReactButtonView(activity, component);
|
|
99
155
|
}
|
|
100
156
|
|
|
157
|
+
private void setContentView(TitleBarReactButtonView uut, View child) {
|
|
158
|
+
uut.removeAllViews();
|
|
159
|
+
uut.addView(child, new ViewGroup.LayoutParams(
|
|
160
|
+
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
161
|
+
ViewGroup.LayoutParams.MATCH_PARENT
|
|
162
|
+
));
|
|
163
|
+
}
|
|
164
|
+
|
|
101
165
|
private int resolveActionBarSize(Activity activity) {
|
|
102
166
|
TypedValue tv = new TypedValue();
|
|
103
167
|
if (activity.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
|
|
@@ -106,30 +170,30 @@ public class TitleBarReactButtonViewTest extends BaseTest {
|
|
|
106
170
|
return UiUtils.dpToPx(activity, 48);
|
|
107
171
|
}
|
|
108
172
|
|
|
109
|
-
private
|
|
110
|
-
|
|
111
|
-
super(activity);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
@Override
|
|
115
|
-
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
116
|
-
setMeasuredDimension(CHILD_WIDTH, CHILD_HEIGHT);
|
|
117
|
-
}
|
|
173
|
+
private int finalWidth(Activity activity) {
|
|
174
|
+
return CHILD_WIDTH + (int) Math.ceil(UiUtils.dpToPx(activity, 1f));
|
|
118
175
|
}
|
|
119
176
|
|
|
120
|
-
private static class
|
|
121
|
-
|
|
122
|
-
|
|
177
|
+
private static class RecordingContentView extends View {
|
|
178
|
+
final List<Integer> widthMeasureSpecs = new ArrayList<>();
|
|
179
|
+
final List<Integer> heightMeasureSpecs = new ArrayList<>();
|
|
123
180
|
|
|
124
|
-
|
|
181
|
+
RecordingContentView(Activity activity) {
|
|
125
182
|
super(activity);
|
|
126
183
|
}
|
|
127
184
|
|
|
128
185
|
@Override
|
|
129
186
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
187
|
+
widthMeasureSpecs.add(widthMeasureSpec);
|
|
188
|
+
heightMeasureSpecs.add(heightMeasureSpec);
|
|
189
|
+
|
|
190
|
+
int measuredWidth = getMode(widthMeasureSpec) == EXACTLY
|
|
191
|
+
? getSize(widthMeasureSpec)
|
|
192
|
+
: Math.min(CHILD_WIDTH, getSize(widthMeasureSpec));
|
|
193
|
+
int measuredHeight = getMode(heightMeasureSpec) == EXACTLY
|
|
194
|
+
? getSize(heightMeasureSpec)
|
|
195
|
+
: Math.min(CHILD_HEIGHT, getSize(heightMeasureSpec));
|
|
196
|
+
setMeasuredDimension(measuredWidth, measuredHeight);
|
|
133
197
|
}
|
|
134
198
|
}
|
|
135
199
|
}
|