diff --git a/App.tsx b/App.tsx index 9a0d1e2d..04e2c333 100644 --- a/App.tsx +++ b/App.tsx @@ -3,6 +3,7 @@ import * as React from 'react' import { Image, Platform, + ScrollView, StyleSheet, Text, TouchableOpacity, @@ -21,7 +22,7 @@ const uri = // Add at the root of you app! function App() { return ( - + ) @@ -29,14 +30,14 @@ function App() { const AppContent = () => { const iconProps = { size: 40, color: '#888' } - + const scrollRef = React.useRef(null); // Use Hooks to control! const { start, canStart, stop, eventEmitter } = useTourGuideController() React.useEffect(() => { // start at mount if (canStart) { - start() + start(1,scrollRef) } }, [canStart]) // wait until everything is registered @@ -47,11 +48,71 @@ const AppContent = () => { return () => eventEmitter.off('*', null) }, []) return ( + {scrollRef.current = r}} + contentContainerStyle={{ flexGrow: 1 }} + scrollEventThrottle={16} + keyboardShouldPersistTaps={'always'} + > {/* Use TourGuideZone only to wrap */} + + {'Welcome to the demo of\n"rn-tourguide"'} + + + {'Welcome to the demo of\n"rn-tourguide"'} + + + {'Welcome to the demo of\n"rn-tourguide"'} + + + {'Welcome to the demo of\n"rn-tourguide"'} + + + {'Welcome to the demo of\n"rn-tourguide"'} + + + {'Welcome to the demo of\n"rn-tourguide"'} + + + {'Welcome to the demo of\n"rn-tourguide"'} + + + {'Welcome to the demo of\n"rn-tourguide"'} + + + {'Welcome to the demo of\n"rn-tourguide"'} + + + {'Welcome to the demo of\n"rn-tourguide"'} + + + {'Welcome to the demo of\n"rn-tourguide"'} + + + {'Welcome to the demo of\n"rn-tourguide"'} + + + {'Welcome to the demo of\n"rn-tourguide"'} + + + {'Welcome to the demo of\n"rn-tourguide"'} + + + {'Welcome to the demo of\n"rn-tourguide"'} + + + {'Welcome to the demo of\n"rn-tourguide"'} + + + {'Welcome to the demo of\n"rn-tourguide"'} + + + {'Welcome to the demo of\n"rn-tourguide"'} + @@ -92,7 +153,7 @@ const AppContent = () => { - + @@ -120,6 +181,7 @@ const AppContent = () => { /> ) : null} + ) } diff --git a/src/components/TourGuideContext.ts b/src/components/TourGuideContext.ts index e414a0c6..798a9b8b 100644 --- a/src/components/TourGuideContext.ts +++ b/src/components/TourGuideContext.ts @@ -16,7 +16,7 @@ export interface ITourGuideContext { registerStep?(key: string, step: IStep): void unregisterStep?(key: string, stepName: string): void getCurrentStep?(key: string): IStep | undefined - start?(key: string, fromStep?: number): void + start?(key: string, fromStep?: number, scrollRef?: React.RefObject): void stop?(key: string): void } diff --git a/src/components/TourGuideProvider.tsx b/src/components/TourGuideProvider.tsx index 77006f07..4d0421fc 100644 --- a/src/components/TourGuideProvider.tsx +++ b/src/components/TourGuideProvider.tsx @@ -1,6 +1,12 @@ import mitt, { Emitter } from 'mitt' import * as React from 'react' -import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native' +import { + findNodeHandle, + StyleProp, + StyleSheet, + View, + ViewStyle, +} from 'react-native' import { TourGuideContext, Ctx } from './TourGuideContext' import { useIsMounted } from '../hooks/useIsMounted' import { IStep, Labels, StepObject, Steps } from '../types' @@ -49,6 +55,7 @@ export const TourGuideProvider = ({ dismissOnPress = false, preventOutsideInteraction = false, }: TourGuideProviderProps) => { + const [scrollRef, setScrollRef] = useState>() const [tourKey, setTourKey] = useState('_default') const [visible, updateVisible] = useState>({ _default: false, @@ -133,15 +140,36 @@ export const TourGuideProvider = ({ }) } - const setCurrentStep = (key: string, step?: IStep) => - new Promise((resolve) => { - updateCurrentStep((currentStep) => { - const newStep = { ...currentStep } - newStep[key] = step - eventEmitter[key]?.emit('stepChange', step) - return newStep - }) - resolve() + const setCurrentStep = async (key: string, step?: IStep) => + new Promise(async (resolve) => { + if (scrollRef && step) { + await step.wrapper.measureLayout( + findNodeHandle(scrollRef.current), + (_x: number, y: number, _w: number, h: number) => { + const yOffsett = y > 0 ? y - h / 2 : 0 + scrollRef.current.scrollTo({ y: yOffsett, animated: false }) + }, + ) + setTimeout(() => { + updateCurrentStep((currentStep) => { + const newStep = { ...currentStep } + newStep[key] = step + eventEmitter[key]?.emit('stepChange', step) + return newStep + }) + resolve() + }, 100); + } + else { + updateCurrentStep((currentStep) => { + const newStep = { ...currentStep } + newStep[key] = step + eventEmitter[key]?.emit('stepChange', step) + return newStep + }) + resolve() + } + }) const getNextStep = ( @@ -212,7 +240,14 @@ export const TourGuideProvider = ({ const getCurrentStep = (key: string) => currentStep[key] - const start = async (key: string, fromStep?: number) => { + const start = async ( + key: string, + fromStep?: number, + _scrollRef?: React.RefObject, + ) => { + if (!scrollRef) { + setScrollRef(_scrollRef) + } const currentStep = fromStep ? (steps[key] as StepObject)[fromStep] : getFirstStep(key) diff --git a/src/hooks/useTourGuideController.tsx b/src/hooks/useTourGuideController.tsx index d6db52d1..5a21c64b 100644 --- a/src/hooks/useTourGuideController.tsx +++ b/src/hooks/useTourGuideController.tsx @@ -12,12 +12,12 @@ export const useTourGuideController = (tourKey?: string) => { const key = tourKey ?? '_default' - const _start = (fromStep?: number) => { + const _start = (fromStep?: number,scrollRef?: React.RefObject) => { if (setTourKey) { setTourKey(key) } if (start) { - start(key, fromStep) + start(key, fromStep,scrollRef) } } const _stop = () => {