Skip to content

Commit 48ffdc9

Browse files
authored
SegmentedControl - fixed Outline sometimes renders as a line (#3099)
* fixed Outline sometimes renders as a line * fixed lint and ts errors * removed first array initialization * removed getinitialarray
1 parent 4947072 commit 48ffdc9

File tree

1 file changed

+20
-23
lines changed

1 file changed

+20
-23
lines changed

src/components/segmentedControl/index.tsx

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import _ from 'lodash';
2-
import React, {useRef, useCallback, useEffect, useState} from 'react';
2+
import React, {useRef, useCallback, useEffect} from 'react';
33
import {StyleSheet, StyleProp, ViewStyle, TextStyle, LayoutChangeEvent} from 'react-native';
44
import {
55
Easing,
@@ -97,6 +97,7 @@ export type SegmentedControlProps = {
9797
};
9898

9999
const nonAreUndefined = <T, >(array: Array<T | undefined>): array is Array<T> => {
100+
'worklet';
100101
for (const item of array) {
101102
if (item === undefined) {
102103
return false;
@@ -105,10 +106,6 @@ const nonAreUndefined = <T, >(array: Array<T | undefined>): array is Array<T> =>
105106
return true;
106107
};
107108

108-
function getInitialSegmentsDimensionsArray(length: number) {
109-
return Array<{x: number; width: number} | undefined>(length).fill(undefined);
110-
}
111-
112109
/**
113110
* @description: SegmentedControl component for toggling two values or more
114111
* @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/SegmentedControlScreen.tsx
@@ -138,8 +135,8 @@ const SegmentedControl = (props: SegmentedControlProps) => {
138135
const animatedSelectedIndex = useSharedValue(initialIndex);
139136
const segmentsStyle = useSharedValue([] as {x: number; width: number}[]);
140137
// const shouldResetOnDimensionsOnNextLayout = useRef(false); // use this flag if there bugs with onLayout being called more than once.
141-
const segmentsDimensions = useRef(getInitialSegmentsDimensionsArray(segments?.length || 0));
142-
const [containerHeight, setContainerHeight] = useState(0);
138+
const segmentsDimensions = useRef<{x: number; width: number}[]>([]);
139+
const containerHeight = useSharedValue(0);
143140

144141
useEffect(() => {
145142
animatedSelectedIndex.value = initialIndex;
@@ -171,40 +168,42 @@ const SegmentedControl = (props: SegmentedControlProps) => {
171168
const onLayout = useCallback((index: number, event: LayoutChangeEvent) => {
172169
// if (shouldResetOnDimensionsOnNextLayout.current) {
173170
// shouldResetOnDimensionsOnNextLayout.current = false;
174-
// // segmentsDimensions.current = getInitialSegmentsDimensionsArray(segments?.length || 0);
171+
// segmentsDimensions.current = getInitialSegmentsDimensionsArray(segments.length || 0);
175172
// }
176173
const {x, width} = event.nativeEvent.layout;
177174
segmentsDimensions.current[index] = {x, width};
178-
if (nonAreUndefined(segmentsDimensions.current)) {
175+
if (segmentsDimensions.current.length === segments.length && nonAreUndefined(segmentsDimensions.current)) {
179176
segmentsStyle.value = [...segmentsDimensions.current];
180177
// shouldResetOnDimensionsOnNextLayout.current = true;// in case onLayout will be called again (orientation change etc.)
181178
}
182179
},
183180
// eslint-disable-next-line react-hooks/exhaustive-deps
184-
[initialIndex, segments?.length]);
181+
[initialIndex, segments.length]);
185182

186183
const containerOnLayout = useCallback(({nativeEvent: {layout: {height}}} : LayoutChangeEvent) => {
187-
setContainerHeight(height);
188-
}, []);
184+
containerHeight.value = height;
185+
}, [containerHeight]);
189186

190187
const animatedStyle = useAnimatedStyle(() => {
191-
if (segmentsStyle.value.length !== 0) {
188+
const {value} = segmentsStyle;
189+
const {value: height} = containerHeight;
190+
if (height !== 0 && value.length === segments.length && nonAreUndefined(value)) {
192191
const isFirstElementSelected = animatedSelectedIndex.value === 0;
193-
const isLastElementSelected = animatedSelectedIndex.value === segmentsStyle.value.length - 1;
192+
const isLastElementSelected = animatedSelectedIndex.value === value.length - 1;
194193
const isMiddleSelected = !isFirstElementSelected && !isLastElementSelected;
195194
const insetFix = -CONTAINER_BORDER_WIDTH - (!isFirstElementSelected ? segmentDividerWidth : 1);
196195
const widthFix = isMiddleSelected ? 2 * segmentDividerWidth : CONTAINER_BORDER_WIDTH + segmentDividerWidth;
197-
const inset = withTiming(segmentsStyle.value[animatedSelectedIndex.value].x + insetFix, TIMING_CONFIG);
198-
const width = withTiming(segmentsStyle.value[animatedSelectedIndex.value].width + widthFix, TIMING_CONFIG);
199-
return Constants.isRTL ? {width, right: inset} : {width, left: inset};
196+
const inset = withTiming(value[animatedSelectedIndex.value].x + insetFix, TIMING_CONFIG);
197+
const width = withTiming(value[animatedSelectedIndex.value].width + widthFix, TIMING_CONFIG);
198+
return Constants.isRTL ? {width, height, right: inset} : {width, height, left: inset};
200199
}
201200
return {};
202201
});
203202
const shouldRenderDividers = segmentDividerWidth !== 0;
204203

205204
const renderSegments = () =>
206205
_.map(segments, (_value, index) => {
207-
const isLastSegment = index + 1 === segments?.length;
206+
const isLastSegment = index + 1 === segments.length;
208207
return (
209208
<React.Fragment key={`segment-fragment-${index}`}>
210209
<Segment
@@ -218,7 +217,7 @@ const SegmentedControl = (props: SegmentedControlProps) => {
218217
style={[segmentsStyleProp]}
219218
segmentLabelStyle={segmentLabelStyle}
220219
iconTintColor={iconTintColor}
221-
{...segments?.[index]}
220+
{...segments[index]}
222221
testID={testID}
223222
/>
224223
{!isLastSegment && shouldRenderDividers && (
@@ -243,8 +242,7 @@ const SegmentedControl = (props: SegmentedControlProps) => {
243242
borderRadius,
244243
backgroundColor: activeBackgroundColor,
245244
borderWidth: shouldRenderDividers ? undefined : outlineWidth,
246-
borderColor: shouldRenderDividers ? undefined : outlineColor,
247-
height: containerHeight
245+
borderColor: shouldRenderDividers ? undefined : outlineColor
248246
},
249247
animatedStyle
250248
]}
@@ -258,8 +256,7 @@ const SegmentedControl = (props: SegmentedControlProps) => {
258256
{
259257
borderColor: outlineColor,
260258
borderRadius,
261-
borderWidth: outlineWidth,
262-
height: containerHeight
259+
borderWidth: outlineWidth
263260
},
264261
animatedStyle
265262
]}

0 commit comments

Comments
 (0)