I am working on a comment box which I am expanding to the height of device on swipe up action and back to its original height on swipe down action. But I am not able to add the animation to it as the function does not work the way i wanted it to be. For the reference we can talk about the slack comment box animation.
Here is what my code looks like :
code :
Snack link : https://snack.expo.dev/@sidd0328/animate-comment-box
const deviceHeight = Dimensions.get("window").height;
const height = useRef(new Animated.Value(1)).current;
const videoPlaceholderSize = 80;
const parentContainerExpandedHeight = deviceHeight * 0.85 - keyboardHeight;
const childContainerExpandedHeight = deviceHeight * 0.82 - keyboardHeight;
const textContainerExpandedHeight = deviceHeight * 0.75 - keyboardHeight;
useEffect(() => {
Animated.timing(height, {
toValue: isExpanded ? parentContainerExpandedHeight : 0,
duration: 400,
useNativeDriver: false,
}).start();
}, [isExpanded]);
return (
<GestureRecognizer
onSwipeUp={() => setIsExpanded(true)}
onSwipeDown={() => setIsExpanded(false)}
>
<Animated.View
style={[
getStyle.parentContainer,
isExpanded && {
height: height,
},
]}
>
<View style={getStyle.handlebar} />
<View
style={[getStyle.childContainer, isExpanded && { height: childContainerExpandedHeight }]}
>
<View
style={[
getStyle.textImageWrapper,
isExpanded && { height: textContainerExpandedHeight },
]}
>
<ScrollView showsVerticalScrollIndicator={false}>
<>
<TextInput
ref={inputRef}
value={inputValue}
style={getStyle.input}
placeholder={placeholder || i18n.t("community.writeComment")}
placeholderTextColor="gray"
multiline
textAlignVertical="top"
onChangeText={handleChangeText}
maxLength={maxLength || 500}
/>
</>
</ScrollView>
{Object.keys(selectedImageFile).length ? (
isVideoByType(selectedImageFile.type) && selectedImage.length > 0 ? (
<View style={getStyle.videoPlaceholder}>
<VideoPlaceholder
variant="nonPressable"
height={videoPlaceholderSize}
width={videoPlaceholderSize}
/>
<TouchableOpacity style={getStyle.backImageWrapper} onPress={removeImage}>
<VectorImage
source={Icons.removeCircle2}
width={IconSize.m}
height={IconSize.m}
/>
</TouchableOpacity>
</View>
) : selectedImage.length > 0 ? (
<View style={getStyle.imagePlaceholder}>
<ImagesLayout
path="CommentBox"
images={selectedImage}
isRemoveImageIconVisible={true}
onRemoveImagePress={removeImage}
/>
</View>
) : null
) : null}
</View>
{!isEditing ? (
<View style={getStyle.container}>
<TouchableOpacity
style={[getStyle.submitButton, getStyle.addImageButtonWrapper]}
onPress={() => setImageSelectionVisible(true)}
>
<VectorImage source={Icons.pictureSingle2} width={IconSize.m} height={IconSize.m} />
</TouchableOpacity>
<TouchableOpacity
onPress={inputValue.length ? onPressSubmit : () => {}}
style={[
getStyle.submitButton,
{
backgroundColor: inputValue.length ? buttonColor.newPrimaryColor : colors.gray3,
},
]}
activeOpacity={inputValue.length ? 0.2 : 1}
>
<VectorImage
source={Icons.send2}
style={getStyle.imageColor}
width={IconSize.m}
height={IconSize.m}
/>
</TouchableOpacity>
<ImageSelectionMethod
isVisible={isImageSelectionVisible}
isVideo={isVideoCaptureEnabled}
onClose={() => setImageSelectionVisible(false)}
onCameraPicker={showCamera}
onImagePicker={
isVideoCaptureEnabled ? showPhotoAndVideoGalleryPicker : showPhotoGalleryPicker
}
onVideoPicker={showVideoRecorder}
/>
</View>
) : (
<View style={getStyle.buttonContainer}>
<View style={getStyle.buttonWrapper}>
<Button
variant={Variant.SECONDARY_OUTLINED_SMALL}
label={i18n.t("community.cancelText")}
onPress={cancelEditing}
/>
</View>
<Button
variant={Variant.PRIMARY_SMALL}
label={i18n.t("contactForms.createContactFormScreen.saveButtonLabel")}
isEnabled={Boolean(inputValue.length)}
onPress={onPressSubmit}
/>
</View>
)}
</View>
<View style={getStyle.bottomHandlebarContainer} />
</Animated.View>
</GestureRecognizer>
);
animation video for above implementation : https://www.dropbox.com/s/ivfaqd397f3jutz/Screen%20Recording%202023-06-28%20at%205.53.38%20PM.mov?dl=0
What I want :
https://www.dropbox.com/s/ylktmw3j1z0ec5d/IMG_5044.mov?dl=0
Any suggestions or help would be greatly appreciated!!!
I checked the snack link shared by you and added the animation in it, here is the snack with expected behavior.
I have updated some of the styling related to TextInput
and its containers and removed the check you added for adding the animated height in style.
styles.parentContainer,
isExpanded && { // removed this
height: height,
},
]}
I have also removed the useEffect which was increasing/descresing the height of container,instead I added 2 separate functions to do the same thing and called this functions in swipeUp/swipeDown callbacks.
Also, To get the correct increased height, substract 96 from parentContainerExpandedHeight
. Here 96 is the total minimum height of the container of TextInput
(total minimum height = vertical padding/margin + height).
const parentContainerExpandedHeight = deviceHeight - 96;
Swipe gesture callback function
const onSwipeUp = () => {
console.log('swipe up');
isExpanded.current = true;
Animated.timing(height, {
toValue: parentContainerExpandedHeight,
duration: 400,
useNativeDriver: false,
}).start();
};
const onSwipeDown = () => {
console.log('swipe down');
isExpanded.current = false;
Animated.timing(height, {
toValue: 0,
duration: 400,
useNativeDriver: false,
}).start();
};
Gesture handler with TextInput
<GestureRecognizer
onSwipeUp={state => onSwipeUp()}
onSwipeDown={state => onSwipeDown()}>
<View style={[styles.parentContainer]}>
<View style={styles.handlebar} />
<Animated.View style={[styles.childContainer, {minHeight: height}]}>
<View style={[styles.anotherChildContainer]}>
<View style={[styles.textImageWrapper]}>
<ScrollView showsVerticalScrollIndicator={false}>
<>
<TextInput
value={text}
onChangeText={onChangeText}
placeholder={'placeholder'}
placeholderTextColor="gray"
multiline
textAlignVertical="top"
style={{
textAlignVertical: 'top',
marginBottom: 10,
}}
maxLength={500}
/>
</>
</ScrollView>
</View>
<View style={styles.container}>
<TouchableOpacity
style={styles.submitButton}></TouchableOpacity>
<TouchableOpacity
onPress={() => {}}
style={styles.submitButton}></TouchableOpacity>
</View>
</View>
</Animated.View>
</View>
</GestureRecognizer>