diff --git a/src/screens/PlayDetail/Horizontal/Lyric.tsx b/src/screens/PlayDetail/Horizontal/Lyric.tsx index 2d7dd57..654ae3c 100644 --- a/src/screens/PlayDetail/Horizontal/Lyric.tsx +++ b/src/screens/PlayDetail/Horizontal/Lyric.tsx @@ -103,10 +103,6 @@ export default () => { if (index < 0) return if (flatListRef.current) { // console.log('handleScrollToActive', index) - if (scrollCancelRef.current) { - scrollCancelRef.current() - scrollCancelRef.current = null - } if (scrollInfoRef.current && lineRef.current.line - lineRef.current.prevLine == 1) { let offset = listLayoutInfoRef.current.spaceHeight for (let line = 0; line < index; line++) { @@ -118,6 +114,10 @@ export default () => { }) } catch {} } else { + if (scrollCancelRef.current) { + scrollCancelRef.current() + scrollCancelRef.current = null + } try { flatListRef.current.scrollToIndex({ index, diff --git a/src/screens/PlayDetail/Vertical/Lyric.tsx b/src/screens/PlayDetail/Vertical/Lyric.tsx index 7ed5134..92d450a 100644 --- a/src/screens/PlayDetail/Vertical/Lyric.tsx +++ b/src/screens/PlayDetail/Vertical/Lyric.tsx @@ -143,10 +143,6 @@ export default () => { if (index < 0) return if (flatListRef.current) { // console.log('handleScrollToActive', index) - if (scrollCancelRef.current) { - scrollCancelRef.current() - scrollCancelRef.current = null - } if (scrollInfoRef.current && lineRef.current.line - lineRef.current.prevLine == 1) { let offset = listLayoutInfoRef.current.spaceHeight for (let line = 0; line < index; line++) { @@ -158,6 +154,10 @@ export default () => { }) } catch {} } else { + if (scrollCancelRef.current) { + scrollCancelRef.current() + scrollCancelRef.current = null + } try { flatListRef.current.scrollToIndex({ index, diff --git a/src/utils/scroll.ts b/src/utils/scroll.ts index b578af0..0e5a268 100644 --- a/src/utils/scroll.ts +++ b/src/utils/scroll.ts @@ -10,17 +10,33 @@ const easeInOutQuad = (t: number, b: number, c: number, d: number): number => { type Noop = () => void const noop: Noop = () => {} -const handleScrollY = (element: FlatList, info: NativeSyntheticEvent['nativeEvent'], to: number, duration = 300, fn = noop): Noop => { +type ScrollElement = { + lx_scrollLockKey?: number + lx_scrollNextParams?: [ScrollElement>, NativeSyntheticEvent['nativeEvent'], number, number, Noop] + lx_scrollTimeout?: NodeJS.Timeout + lx_scrollDelayTimeout?: NodeJS.Timeout +} & T + +const handleScrollY = (element: ScrollElement>, info: NativeSyntheticEvent['nativeEvent'], to: number, duration = 300, fn = noop): Noop => { if (element == null) { fn() return noop } - const key = Math.random() + const clean = () => { + element.lx_scrollLockKey = undefined + element.lx_scrollNextParams = undefined + if (element.lx_scrollTimeout) clearTimeout(element.lx_scrollTimeout) + element.lx_scrollTimeout = undefined + } + if (element.lx_scrollLockKey) { + element.lx_scrollNextParams = [element, info, to, duration, fn] + element.lx_scrollLockKey = -1 + return clean + } - const start = info.contentOffset.y - let cancel = false + let start = info.contentOffset.y if (to > start) { let maxScrollTop = info.contentSize.height - info.layoutMeasurement.height if (to > maxScrollTop) to = maxScrollTop @@ -30,7 +46,7 @@ const handleScrollY = (element: FlatList, info: NativeSyntheticEvent, info: NativeSyntheticEvent { - // @ts-expect-error - if (cancel || element.lx_scrollKey != key) { - fn() + element.lx_scrollTimeout = undefined + if (element.lx_scrollNextParams && currentTime > duration * 0.75) { + const [_element, info, to, duration, fn] = element.lx_scrollNextParams + info.contentOffset.y = val + clean() + handleScrollY(_element, info, to, duration, fn) return } + // if (element.lx_scrollLockKey != key) { + // if (element.lx_scrollNextParams) { + // // element.lx_scrollNextParams[1].contentOffset.y = val + // // handleScrollY(element.lx_scrollNextParams[0], element.lx_scrollNextParams[1], element.lx_scrollNextParams[2], element.lx_scrollNextParams[3], element.lx_scrollNextParams[4]) + // start = val + // info = element.lx_scrollNextParams[1] + // to = element.lx_scrollNextParams[2] + // fn = element.lx_scrollNextParams[4] + // if (to > start) { + // let maxScrollTop = info.contentSize.height - info.layoutMeasurement.height + // if (to > maxScrollTop) to = maxScrollTop + // } else if (to < start) { + // if (to < 0) to = 0 + // } else { + // clean() + // fn() + // return + // } + // change = to - val + + // element.lx_scrollLockKey = key + // } else { + // fn() + // return + // } + // } currentTime += increment val = Math.trunc(easeInOutQuad(currentTime, start, change, duration)) element.scrollToOffset({ offset: val, animated: false }) if (currentTime < duration) { - setTimeout(animateScroll, increment) + element.lx_scrollTimeout = setTimeout(animateScroll, increment) } else { - fn() + if (element.lx_scrollNextParams) { + const [_element, to, duration, fn] = element.lx_scrollNextParams + info.contentOffset.y = val + clean() + handleScrollY(_element, to, duration, fn) + } else { + clean() + fn() + } } } - // @ts-expect-error - element.lx_scrollKey = key - requestAnimationFrame(() => { - animateScroll() - }) - return () => { - cancel = true - } + element.lx_scrollLockKey = key + animateScroll() + + return clean } /** * 设置滚动条位置 @@ -73,16 +123,24 @@ const handleScrollY = (element: FlatList, info: NativeSyntheticEvent, info: NativeSyntheticEvent['nativeEvent'], to: number, duration = 300, fn = () => {}, delay = 0): () => void => { +export const scrollTo = (element: ScrollElement>, info: NativeSyntheticEvent['nativeEvent'], to: number, duration = 300, fn = () => {}, delay = 0): () => void => { let cancelFn: () => void - let timeout: NodeJS.Timeout | null + if (element.lx_scrollDelayTimeout != null) { + clearTimeout(element.lx_scrollDelayTimeout) + element.lx_scrollDelayTimeout = undefined + } if (delay) { let scrollCancelFn: Noop cancelFn = () => { - timeout == null ? scrollCancelFn?.() : clearTimeout(timeout) + if (element.lx_scrollDelayTimeout == null) { + scrollCancelFn?.() + } else { + clearTimeout(element.lx_scrollDelayTimeout) + element.lx_scrollDelayTimeout = undefined + } } - timeout = setTimeout(() => { - timeout = null + element.lx_scrollDelayTimeout = setTimeout(() => { + element.lx_scrollDelayTimeout = undefined scrollCancelFn = handleScrollY(element, info, to, duration, fn) }, delay) } else {