实现效果
需要实现的效果主要有两个,一个是上下翻页效果,还有就是点赞的动画。
效果 (好像不支持 webp 格式图片 只能将就一下)
列表页上下翻页实现
播放视频使用 react-native-video 库。列表使用 FlatList,每个 item 占用一整屏,配合 pagingEnabled 属性可以翻页效果。
通过 onViewableItemsChanged
来控制只有当前的页面才播放视频。
const ShortVideoPage = () => {
const [currentItem, setCurrentItem] = useState(0);
const [data, setData] = useState([]);
const _onViewableItemsChanged = useCallback(({ viewableItems }) => {
// 这个方法为了让state对应当前呈现在页面上的item的播放器的state
// 也就是只会有一个播放器播放,而不会每个item都播放
// 可以理解为,只要不是当前再页面上的item 它的状态就应该暂停
// 只有100%呈现再页面上的item(只会有一个)它的播放器是播放状态
if (viewableItems.length === 1) {
setCurrentItem(viewableItems[0].index);
}
}, []);
useEffect(() => {
const mockData = [];
for (let i = 0; i < 100; i++) {
mockData.push({ id: i, pause: false });
}
setData(mockData);
}, []);
return (
onMoveShouldSetResponder={() => true}
data={data}
renderItem={({ item, index }) => (
)}
pagingEnabled={true}
getItemLayout={(item, index) => {
return { length: HEIGHT, offset: HEIGHT * index, index };
}}
onViewableItemsChanged={_onViewableItemsChanged}
keyExtractor={(item, index) => index.toString()}
viewabilityConfig={{
viewAreaCoveragePercentThreshold: 80, // item滑动80%部分才会到下一个
}}
/>
);
};
点赞效果
单次点击的时候切换暂停/播放状态,连续多次点击每次在点击位置出现一个爱心,随机旋转一个角度,爱心先放大再变透明消失。
爱心动画实现
const AnimatedHeartView = React.memo(
(props: AnimatedHeartProps) => {
// [-25, 25]随机一个角度
const rotateAngle = `${Math.round(Math.random() * 50 - 25)}deg`;
const animValue = React.useRef(new Animated.Value(0)).current;
React.useEffect(() => {
Animated.sequence([
Animated.spring(animValue, {
toValue: 1,
useNativeDriver: true,
bounciness: 5,
}),
Animated.timing(animValue, {
toValue: 2,
useNativeDriver: true,
}),
]).start(() => {
props.onAnimFinished();
});
}, [animValue, props]);
return (
);
},
() => true,
);
连续点赞判定
监听手势,记录每次点击时间 lastClickTime,设置 CLICK_THRESHOLD 连续两次点击事件间隔小于 CLICK_THRESHOLD 视为连续点击,在点击位置创建爱心,添加到 heartList,否则视为单次点击,暂停播放。
const ShortVideoItem = React.memo((props: ShortVideoItemProps) => {
const [paused, setPaused] = React.useState(props.paused);
const [data, setData] = React.useState();
const [heartList, setHeartList] = React.useState([]);
const lastClickTime = React.useRef(0); // 记录上次点击时间
const pauseHandler = React.useRef();
useEffect(() => {
setTimeout(() => {
setData({
video: TEST_VIDEO,
hasFavor: false,
});
});
}, []);
useEffect(() => {
setPaused(props.paused);
}, [props.paused]);
const _addHeartView = React.useCallback(heartViewData => {
setHeartList(list => [...list, heartViewData]);
}, []);
const _removeHeartView = React.useCallback(index => {
setHeartList(list => list.filter((item, i) => index !== i));
}, []);
const _favor = React.useCallback(
(hasFavor, canCancelFavor = true) => {
if (!hasFavor || canCancelFavor) {
setData(preValue => (preValue ? { ...preValue, hasFavor: !hasFavor } : preValue));
}
}, [],
);
const _handlerClick = React.useCallback(
(event: GestureResponderEvent) => {
const { pageX, pageY } = event.nativeEvent;
const heartViewData = {
x: pageX,
y: pageY - 60,
key: new Date().getTime().toString(),
};
const currentTime = new Date().getTime();
// 连续点击
if (currentTime - lastClickTime.current < CLICK_THRESHOLD) {
pauseHandler.current && clearTimeout(pauseHandler.current);
_addHeartView(heartViewData);
if (data && !data.hasFavor) {
_favor(false, false);
}
} else {
pauseHandler.current = setTimeout(() => {
setPaused(preValue => !preValue);
}, CLICK_THRESHOLD);
}
lastClickTime.current = currentTime;
}, [_addHeartView, _favor, data],
);
return true}
onResponderGrant={_handlerClick}
style={{ height: HEIGHT }}
>
{
data
?
: null
}
{
heartList.map(({ x, y, key }, index) => {
return (
_removeHeartView(index)}
/>
);
})
}
短视频招募了
5㎡长条形卫生间如何设计干湿分离?
家里只有一个卫生间,一定要这样装!颜值比五星酒店卫生间还高级,卫生间,一定要这样装!颜值比卫生间,一定要这样装!
造作设计工作坊
1.2w
1.2w
1.2w
{
paused
?
: null
}
;
}, (preValue, nextValue) => preValue.id === nextValue.id && preValue.paused === nextValue.paused);
手势冲突
通过 GestureResponder 拦截点击事件之后会造成 FlatList 滚动事件失效,所以需要将滚动事件交给 FlatList。通过 onResponderTerminationRequest 属性可以让 View 放弃处理事件的权利,将滚动事件交给 FlatList来处理。
true}
onResponderTerminationRequest={() => true} <---- here
onResponderGrant={_handlerClick}>
{/* some code */}
代码
MyTiktok
参考文献
https://blog.csdn.net/qq_38356174/article/details/96439456
https://juejin.im/post/5b504823e51d451953125799