英文:
Animation like slack comment box react-native
问题
我正在开发一个评论框,我想在向上滑动操作时将其扩展到设备的高度,并在向下滑动操作时将其恢复到原始高度。但是,我无法为其添加动画,因为函数的工作方式不符合我的期望。可以参考Slack评论框动画来了解具体效果。
以下是我的代码:
代码:
Snack链接: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>
);
上述实现的动画视频:https://www.dropbox.com/s/ivfaqd397f3jutz/Screen%20Recording%202023-06-28%20at%205.53.38%20PM.mov?dl=0
我想要的效果:
https://www.dropbox.com/s/ylktmw3j1z0ec5d/IMG_5044.mov?dl=0
非常感谢任何建议或帮助!
英文:
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!!!
答案1
得分: 1
我检查了你分享的小吃链接,并在其中添加了动画,这里是具有期望行为的小吃。
解释
我已经更新了与TextInput
及其容器相关的一些样式,并删除了你添加的用于在样式中添加动画高度的检查。
styles.parentContainer,
isExpanded && { // 这部分已删除
height: height,
},
]}
我还删除了增加/减少容器高度的useEffect,而是添加了两个单独的函数来执行相同的操作,并在swipeUp/swipeDown回调中调用这些函数。
此外,为了获得正确的增加高度,从parentContainerExpandedHeight
中减去96。这里的96是TextInput
容器的总最小高度(总最小高度=垂直填充/边距+高度)。
const parentContainerExpandedHeight = deviceHeight - 96;
代码
滑动手势回调函数
const onSwipeUp = () => {
console.log('向上滑动');
isExpanded.current = true;
Animated.timing(height, {
toValue: parentContainerExpandedHeight,
duration: 400,
useNativeDriver: false,
}).start();
};
const onSwipeDown = () => {
console.log('向下滑动');
isExpanded.current = false;
Animated.timing(height, {
toValue: 0,
duration: 400,
useNativeDriver: false,
}).start();
};
带有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={'占位符'}
placeholderTextColor="灰色"
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>
输出
英文:
I checked the snack link shared by you and added the animation in it, here is the snack with expected behavior.
Explanation
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;
Code
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>
Output
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论