일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- React-Native업데이트
- Throttle
- react-native-permissions
- RN업데이트
- react-native-image-picker
- react animation
- animation
- async
- no-permission-handler-detected
- CS
- Hash-table
- debounce
- RN새로운아키텍쳐
- axios
- react-native
- ios
- hydration mismatch
- react
- named type
- motion.div
- Promise
- 비동기
- promise.all
- await
- RN아키텍쳐
- rn
- javascript
- react native
- Swift
- private-access-to-photos
- Today
- Total
하루살이 개발일지
[회고] TextInput 입력을 두 줄로 제한하기 - 인스타그램 설문 기능 본문
⚠️ 해당 글은 완성되지 않은 계속 업데이트 중인 글입니다.
1. 동적으로 TextInput 내에서 두 줄까지 입력 가능하게 하기
언뜻 보기에는 쉬워보이는 기능이지만 React-Native에서 <TextInput> 자체에 특정 width가 가득 찼는지 감지하는 기능 혹은 몇 줄 이상 넘어가지 못하게 제한하는 기능이 없어서 구현하기 까다로웠다.
이 기능을 구현하기 위해 생각해 낸 방법은
1) 글자수 제한
2) 어떻게든 2줄에 text가 가득 찼을 때를 감지해 비슷하게 구현하기
두 가지 방법이었다.
인스타그램에서는 어떻게 했는지 모르겠지만, 일단 내가 구현하는 ui는 인스타그램 스티커처럼 폰트나 width가 고정되어 있는 게 아니라, 사용자 screen에 따라 달라지는 ui였기 때문에 글자수를 제한하면 ui가 예쁘게 구현되지 않을 거라고 생각했다.
처음에는 TextInput의 multiline을 true로 설정해두고, onContentSizeChange 속성을 활용하여 TextInput의 사이즈 변화를 감지해 감싸고 있는 View의 크기에 맞물리면 사용자 입력을 더 이상 받지 않도록 구현하려고 했다.
그런데 여기에는 문제가 있었는데,
1) multiline={true} 로 설정해 input이 두 줄로 넘어가는 순간 width는 최대 width에서 변하지 않는다. (이미 첫 번째 줄 때문에 width가 최대치로 커진 상태)
2) maxHeight를 설정해 보았는데, 이 경우 TextInput 자체의 height는 고정되어 있지만 입력은 계속 줄바꿈을 통해 넘어가며 제한되지 않았다.
이후 두번째 줄로 줄바꿈된 후, 이를 감싸고 있는 View의 height를 계산한 다음 text input의 height가 이 view의 height를 넘어가는 경우를 감지해 사용자 입력을 제한하는 방법을 고안해 보았다.
이 경우 두번째 줄 -> 세번째 줄로 넘어갈 때 TextInput의 height가 변하는 순간 사용자 입력이 제한되긴 하지만, height의 변화를 감지하는 것이었기 때문에 height가 순간 늘어났다 줄어드는 게 보여 ui가 굉장히 불편해졌다.
그래서 마지막으로 생각해 낸 방법은,
TextInput을 두 개 만들고, 각각 onContentSizeChange 속성을 통해 width를 감지하고, 감싸고 있는 View의 width(보다는 아주 살짝 작은 값)만큼 커지면, 첫 번째 TextInput에서는 두 번째 TextInput을 보여지게 하고, 두 번째 TextInput에서는 입력을 제한하는 방식을 사용하면 어떨까? 였다.
구현한 코드는,
<View
style={styles.titleContainer}>
<View
style={{
width: '100%',
alignItems: 'center',
justifyContent: 'center',
}}
onLayout={event => {
const {width} = event.nativeEvent.layout;
if (width > 0) {
setContainerViewWidth(width);
}
}}>
{firstInput.length === 0 && placeHolderComponent()}
<TextInput
value={firstInput}
onChangeText={handleChangeFirstInput}
onKeyPress={handleKeyPress}
blurOnSubmit={true}
returnKeyType="done"
scrollEnabled={false}
style={[
{
minWidth: 30,
maxWidth: containerViewWidth,
textAlign: 'center',
flexDirection: 'row',
textAlignVertical: 'center',
},
styles.titleText,
]}
onContentSizeChange={checkFirstInputFull}
ref={firstInputRef}
/>
{isSecondInputShow && (
<TextInput
value={secondInput}
onChangeText={handleChangeSecondInput}
onKeyPress={handleKeyPress}
blurOnSubmit={true}
returnKeyType="done"
scrollEnabled={false}
style={[styles.titleText, {minWidth: 30}]}
onContentSizeChange={checkSecondInputFull}
ref={secondInputRef}
/>
)}
</View>
</View>
첫 번째 TextInput과 특정 조건에서 보여질 두 번째 TextInput을 감싸고 있는 View가 있고,
이 감싸는 View에는 onLayout으로 크기를 측정한다. (이 View는 width가 100%라 사용자 스크린 크기에 비례해 커짐)
TextInput에는 onContentSizeChange를 통해 이게 'full' 상태인지 감지하고, 감지했다면 isSecondInputShow의 상태를 바꾸거나 입력을 더이상 받지 않도록 제한했다.
사실 지울때 매끄럽게 지워지지 않고 한번 뚝 끊겨서 지워지고, 마지막 입력을 받을 때 살짝 깜빡거리는 증상이 있는데,
이건 더 어떻게 리팩토링할지 생각해 보아야 겠다.