# flatlist inside scrollview
VirtualizedLists should never be nested inside plain ScrollViews with the same orientation because it can break windowing and other functionality - use another VirtualizedList-backed container instead.
# before
<ScrollView >
<FlatList />
</ScrollView>
# after
<ScrollView horizontal={false} style={{width: '100%', height: '100%'}}>
<ScrollView horizontal={true} style={{width: '100%', height: '100%'}}>
<FlatList />
</ScrollView>
</ScrollView>
# Navigator
# Drawer
function MainStackComponent() {
const MainStack = createStackNavigator();
return (
<MainStack.Navigator>
<MainStack.Screen name="HomeIndex" component={HomeIndex} options={({route}) => ({title: route.name, headerShown: false})} />
</MainStack.Navigator>
);
}
function YoutubeIframeStackComponent() {
// var videoId = route?.params?.id;
const StackNavigator = createStackNavigator();
return (
<StackNavigator.Navigator>
<StackNavigator.Screen name="YoutubeIframeIndex" component={YoutubeIframeIndex} options={({route}) => ({title: route.name, headerShown: false})} />
</StackNavigator.Navigator>
);
}
// λλ‘μ΄ λ€λΉκ²μ΄ν°
const DrawerNav = ({navigation, route}) => {
const DrawerNavigator = createDrawerNavigator();
return (
<DrawerNavigator.Navigator>
<DrawerNavigator.Screen
key={'HomeIndex'}
name={'home'}
component={MainStackComponent}
options={{
headerShown: false,
unmountOnBlur: true,
}}
/>
<DrawerNavigator.Screen
key={'YoutubeIframeIndex'}
name={'youtube'}
component={YoutubeIframeStackComponent}
options={{
headerShown: false,
unmountOnBlur: true,
}}
/>
</DrawerNavigator.Navigator>
);
};
# BottomTab
const MainTabNav = ({navigation, route}) => {
const BottomTabNavigator = createBottomTabNavigator();
// var videoId = route?.params?.id;
return (
<BottomTabNavigator.Navigator>
{bottomRoutes.map(data => (
<BottomTabNavigator.Screen
// initialParams={{id: videoId}}
key={data.name}
name={data.label}
component={data.component}
options={{
tabBarShowLabel: false,
headerShown: false,
unmountOnBlur: true,
tabBarIcon: ({focused}) => {
return <Image source={focused ? data.activeMenu : route.inactiveMenu} style={{width: 15, height: 15}} />;
},
tabBarStyle: {height: 50},
}}
/>
))}
</BottomTabNavigator.Navigator>
);
};
const bottomRoutes = [
{
name: 'home',
label: 'home',
component: HomeIndex,
inactiveMenu: Images.menu_home_off,
activeMenu: Images.menu_home_on,
},
{
name: 'iframe',
label: 'iframe',
component: YoutubeIframeIndex,
inactiveMenu: Images.menu_youtube_off,
activeMenu: Images.menu_youtube_on,
},
];
# we have failed to run 'bundletool build-apks' on this android app bundle
# The emulator process for AVD Pixel5API31 has terminated.
https://codingjerk-diary.tistory.com/entry/Android%EC%98%A4%EB%A5%98%ED%95%B4%EA%B2%B0-The-emulator-process-for-AVD-has-terminated
# custom react-native-appstate-hook
// https://github.com/amrlabib/react-native-appstate-hook/issues/17
const useAppState = settings => {
const {onChange, onForeground, onBackground} = settings || {};
const [appState, setAppState] = useState(AppState.currentState);
useEffect(() => {
const handleAppStateChange = nextAppState => {
if (nextAppState === 'active' && appState !== 'active') {
isValidFunction(onForeground) && onForeground();
} else if (
appState === 'active' &&
nextAppState.match(/inactive|background/)
) {
isValidFunction(onBackground) && onBackground();
}
setAppState(nextAppState);
isValidFunction(onChange) && onChange(nextAppState);
};
AppState.addEventListener('change', handleAppStateChange);
return () => {
AppState.removeEventListener('change', handleAppStateChange);
};
}, [onChange, onForeground, onBackground, appState]);
return {appState};
};
# gesture
import {useFocusEffect} from '@react-navigation/native';
const pan = useRef(new Animated.ValueXY()).current;
const panResponder = useRef(
PanResponder.create({
// onStartShouldSetPanResponder: μ€μμ΄νλ₯Ό μμν΄μΌ ν μ§ μ¬λΆλ₯Ό κ²°μ ν©λλ€.
onStartShouldSetPanResponder: (evt, gestureState) => true, // μ€μμ΄ν νμ©
// onStartShouldSetPanResponderCapture: μ€μμ΄νλ₯Ό μν μΊ‘μ² μ¬λΆλ₯Ό κ²°μ ν©λλ€.
onStartShouldSetPanResponderCapture: (evt, gestureState) => true, // μ€μμ΄ν νμ©
// onMoveShouldSetPanResponder: μ€μμ΄νλ₯Ό μ§νν μ§ μ¬λΆλ₯Ό κ²°μ ν©λλ€.
onMoveShouldSetPanResponder: (evt, gestureState) => true, // μ€μμ΄ν νμ©
// onMoveShouldSetPanResponderCapture: μ€μμ΄νλ₯Ό μν μΊ‘μ² μ¬λΆλ₯Ό κ²°μ ν©λλ€.
onMoveShouldSetPanResponderCapture: (evt, gestureState) => true, // μ€μμ΄ν νμ©
// onPanResponderMove: μ€μμ΄ν λμμ λν μ²λ¦¬λ₯Ό ν©λλ€.
onPanResponderMove: (evt, gestureState) => {
// μ€μμ΄ν λμμ λ°λ₯Έ μ²λ¦¬ λ‘μ§
// console.log('start', evt);
console.log('start', gestureState);
},
// onPanResponderRelease: μ€μμ΄νκ° λλ¬μ λ μ²λ¦¬λ₯Ό ν©λλ€.
onPanResponderRelease: (evt, gestureState) => {
// μ€μμ΄ν μ’
λ£ ν μ²λ¦¬ λ‘μ§
// console.log('end', evt);
console.log('end', gestureState);
},
}),
).current;
<Animated.View
style={{
transform: [{translateY: pan.y}],
}}
{...panResponder.panHandlers}>
</Animated.View>
β - flutter-ubuntu - rn-expo β