想实现一个触底显示评论框的效果,参考了下手机版Safari浏览器的效果,当网页滑动到底部,就出现输入框,离开就消失。看起来简单,做起来也遇到了些问题。

一开始的想法是,评论框就在webview下方,只是被超出不展示,滑动到底部后,评论框自动滑出,离开自动滑入。
但这个简单的效果,在webview里却不好实现。webview 里面的网页滑动,无法传递到外面的容器,也就是到底后外面的View 并不知道。于是想到,给页面注入js ,或者监听webview 的 onscroll 事件,触底后,在滑动外面的容器。
为了外面容器能滑动,尝试了scrollView 和Flatlist , 但遗憾的是,这两个滑动容器,会和webview 滑动冲突,也就是说,容器能滑动,里面页面就不能滑动;里面页面能滑动,容器就不能滑动。好在有enableScroll 属性,通过监听是否触底,来开启和关闭,让同一时间只有一个容器能滑动。但效果也差强人意,比如里面的快速滑动到底部,触底后外面滑动,两段滑动效果很生硬。
<>
<View style={styles.container}>
<Header onBack={handleBack} title={'222s'} />
<FlatList
style={{height: Dimensions.get('window').height}}
data={[{key: 'webview'}, {key: 'commentBox'}]}
ref={flatListRef}
onViewableItemsChanged={onViewableItemsChanged}
viewabilityConfig={viewabilityConfig}
renderItem={({item}) => {
if (item.key === 'webview') {
return renderWebView();
} else if (item.key === 'commentBox') {
return renderCommentBox();
}
return null;
}}
// ListFooterComponent={renderCommentBox()} // 始终渲染评论框
keyExtractor={item => item.key}
scrollEnabled={isScrollEnabled}
nestedScrollEnabled={true}
// scrollEnabled={isScrollEnabled} // 在评论框显示时禁用外部滚动
/>
</View>
</>最终还是放弃了这个方案,换了一个思路,改用flex 和动画来实现。
思路是在一个flex容器中,webview 先充满屏幕100%,评论框在底部,高度为0;当里面滑动到底部的时候,评论框高度为100,压缩webview 空间,显得评论框从底部出来了,并且有一个高度变化的动画。整体效果比之前的方案好。
<>
<View style={styles.container}>
<Header onBack={handleBack} title={'222s'} />
<View style={styles.webview}>
<Webview
// style={[showCommentBox ? styles.webviewShifted : null]}
url={url}
ref={webview}
onScroll={event => {
const {contentOffset, layoutMeasurement, contentSize} =
event.nativeEvent;
const currentScrollY = contentOffset.y;
// 判断滚动方向
if (currentScrollY > lastScrollY) {
// 向下滚动
const isAtBottom =
event.nativeEvent.layoutMeasurement.height +
contentOffset.y >=
event.nativeEvent.contentSize.height - 10;
if (isAtBottom) {
console.log('到底了');
setShowCommentBox(false); // 隐藏评论框
// 向下滚动时,显示评论框
Animated.timing(commentBoxHeight, {
toValue: 100, // 显示评论框
duration: 300,
useNativeDriver: false,
}).start();
}
} else if (currentScrollY < lastScrollY) {
// 向上滚动
const isAtBottom =
event.nativeEvent.layoutMeasurement.height +
contentOffset.y >=
event.nativeEvent.contentSize.height - 10;
const isNearBottom =
layoutMeasurement.height + currentScrollY >=
contentSize.height - 500;
if (isNearBottom) {
console.log('离开底了');
setShowCommentBox(true); // 显示评论框
// 向上滚动时,隐藏评论框
Animated.timing(commentBoxHeight, {
toValue: 0, // 隐藏评论框的高度
duration: 300,
useNativeDriver: false,
}).start();
}
}
setLastScrollY(currentScrollY);
}}
/>
</View>
<Animated.View style={[styles.commentBox, {height: commentBoxHeight}]}>
<Input
style={styles.input}
placeholder="写下你的..."
value={comment}
onChangeText={setComment}
/>
<Button
title="提交"
onPress={() => {
setComment('');
}}
/>
</Animated.View>
</View>
</>