我很确定这是我在这里发布的第一个问题,所以我希望我能正确地做到这一点并提供所有相关信息。
这是一个双重的个人项目。我严格为我和我的合作伙伴构建这个应用程序,因此没有重大限制,并且我愿意接受所有建议/推荐。她和我都经常旅行并会说几种外语,但我们每天仍在学习更多内容,并希望有一个可以一起使用和分享的个性化应用程序,所以我开始创建这个应用程序来提高我们的沟通和语言发展技能。
这个项目也恰好是我学习和提高 React Native 和原生 Kotlin/Swift 开发技能的绝佳机会(我尝试过 JavaFx 一段时间,但我是一名全职前端 Web 开发人员,所以 React Native对于 UI 开发和用于本机/后端的 Kotlin/Swift 来说,这似乎是一种更自然的方法。
它本质上只是一个学习应用程序,结合了我喜欢的 Quizlet、Anki、Pimsleur 等功能,并结合了一些聊天功能等,但这超出了本期的范围。请参阅我的问题陈述了解主要问题。
我遇到的问题是,屏幕顶部的状态栏在将其设置为隐藏后仍然留有空白区域。尽管我已经尝试和研究了一切,但这个问题仍然存在。
我希望在隐藏 StatusBar 时显示我想要的背景颜色,或者根据它所在的活动/屏幕显示 ImageBackground。即屏幕顶部没有空白或凹口。
backgroundColor
设置为透明并将 translucent
属性设置为 true。dark
作为 userInterfaceStyle 属性。react-native-safe-area-context
包及其 SafeAreaProvider
,并在组件本身周围使用 SafeAreaView
(我知道常规 SafeAreaView 仅适用于 iOS,我特别需要这个用于 Android,我只是觉得也许这个上下文包值得一试)。backgroundColor
设置为黑色style
设置为深色,并将 barStyle
设置为深色内容expo-status-bar
和 react-native
StatusBar(奇怪的是,即使我使用 expo,我对 expo-status-bar 也遇到了更多样式问题)我已经没有办法尝试了。以上在实现它时都没有做任何事情。一旦我隐藏状态栏,顶部总是有空白,这很烦人。
{
"expo": {
"name": "...",
"slug": "...",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "dark",
"splash": {
"image": "./assets/....gif",
"resizeMode": "contain",
"backgroundColor": "#000000"
},
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com...."
},
"android": {
"package": "com....",
"adaptiveIcon": {
"foregroundImage": "./assets/....gif",
"backgroundColor": "#000000"
}
},
"androidStatusBar": {
"barStyle": "dark-content",
"backgroundColor": "#000000",
"hidden": true,
"translucent": true
},
"web": {
"favicon": "./assets/favicon.png"
}
}
}
import { useState, useEffect } from 'react';
import { View, Text, Pressable, StyleSheet, FlatList, Dimensions, ImageBackground, StatusBar } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import Logo from '../assets/....gif';
const DEVICE_WIDTH = Dimensions.get('window').width;
const SAMPLE = [
{
id: 0,
name: "Русские карточки",
description: "These are sample Russian flashcards.",
},
{
id: 1,
name: "Flashcards tiếng Việt",
description: "These are sample Vietnamese flashcards.",
},
{
id: 2,
name: '中文抽認卡',
description: 'These are sample Chinese flashcards.',
},
{
id: 3,
name: 'כרטיסי פלאש בעברית',
description: 'These are sample Hebrew flashcards.',
},
{
id: 4,
name: 'Data structures',
description: 'These are sample data structure flashcards.',
},
{
id: 5,
name: 'Countries',
description: 'These are sample culture flashcards from countries around the world.',
},
{
id: 6,
name: 'Cultures',
description: 'These are sample cultural tradition flashcards.',
},
{
id: 7,
name: 'Exercises',
description: 'These are sample flashcards about healthy exercises.',
},
{
id: 8,
name: 'Final',
description: 'This is the final collection just being used to see if it will make it scrollable.',
}
];
export default function Flashcards({ navigation }) {
const [collections, setCollections] = useState([]);
const [selectedCollection, setSelectedCollection] = useState(null);
useEffect(() => {
setCollections(SAMPLE)
}, [])
const Item = ({ name, onPress, description }) => (
<Pressable onPress={onPress} style={styles.item}>
<Text style={styles.itemTitle}>{name}</Text>
<Text style={styles.itemDescription}>{description}</Text>
</Pressable>
);
const handleClick = (item) => {
setSelectedCollection(item.id);
navigation.navigate('StudyMode', {
name: item.name,
});
};
return (
<SafeAreaView style={styles.container}>
<StatusBar
hidden
backgroundColor="black"
// translucent
style="dark"
barStyle="dark-content"
/>
<ImageBackground
source={Logo}
style={styles.image}
resizeMode="cover"
>
<View style={styles.titleContainer}>
<Text style={styles.title}>Flashcards</Text>
</View>
<View style={styles.collectionsContainer}>
<FlatList
data={SAMPLE}
style={styles.flatlist}
renderItem={({ item }) => {
return <Item onPress={() => handleClick(item)} name={item.name} description={item.description} />
}}
keyExtractor={item => item.id}
/>
</View>
</ImageBackground>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
marginTop: StatusBar.currentHeight + 10 || 10,
backgroundColor: '#000000',
alignItems: 'center',
justifyContent: 'center',
paddingBottom: 60,
},
image: {
flex: 1,
justifyContent: 'center',
contentFit: 'cover',
},
titleContainer: {
borderBottomWidth: 6,
borderColor: 'red',
borderRadius: 12,
backgroundColor: 'black',
justifyContent: 'center',
alignItems: 'center',
marginLeft: 12,
marginRight: 12,
marginTop: 14,
marginBottom: 10,
},
title: {
color: 'white',
fontFamily: 'Agright',
fontSize: 32,
},
collectionsContainer: {
borderWidth: 6,
borderColor: 'red',
borderRadius: 12,
backgroundColor: 'black',
width: DEVICE_WIDTH - 10,
},
flatlist: {
flexGrow: 0,
height: '100%',
},
item: {
borderRadius: 12,
borderWidth: 2,
borderColor: 'red',
width: '99%',
alignItems: 'center',
marginLeft: 2,
marginRight: 2,
marginTop: 6,
marginBottom: 6,
paddingVertical: 6,
backgroundColor: '#000000',
},
itemTitle: {
fontFamily: 'Agright',
fontSize: 26,
color: 'white',
},
itemDescription: {
fontFamily: 'Agright',
fontSize: 13,
color: 'white',
}
});
import { useState, useEffect, useContext } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import * as SplashScreen from 'expo-splash-screen';
import * as Font from 'expo-font';
import { Platform, NativeModules } from 'react-native';
import { IntlProvider } from 'react-intl';
import en from './locales/en.json';
import he from './locales/he.json';
import ru from './locales/ru.json';
import uk from './locales/uk.json';
import vi from './locales/vi.json';
import zh from './locales/zh.json';
/**
* Components
*/
import Login from './screens/Login';
import Home from './screens/Home';
import Flashcards from './screens/Flashcards';
import StudyMode from './screens/StudyMode';
import Texts from './screens/Texts';
import Translator from './screens/Translator';
import Dictionary from './screens/Dictionary';
import Chat from './screens/Chat';
/**
* Hooks
*/
import useFonts from './hooks/useFonts';
/**
* Context
*/
import { LocaleContextProvider, LocaleContext } from './context/LocaleContext';
import { DbContextProvider } from './database/DbContext';
/**
* Messages (Localization)
*/
const messages = {
'en': en,
'en_US': en,
'he': he,
'ru': ru,
'uk': uk,
'vi': vi,
'zh': zh,
};
const devicePlatform = Platform.OS;
const _deviceLocale = devicePlatform === 'android' ?
NativeModules.I18nManager.localeIdentifier :
NativeModules.SettingsManager.settings.AppleLocale ||
NativeModules.SettingsManager.settings.AppleLanguages[0];
const deviceLocale = _deviceLocale.split(/[-_]/)[0];
SplashScreen.preventAutoHideAsync();
const Stack = createNativeStackNavigator();
const screenOptions = {
headerStyle: {
backgroundColor: '#000000',
},
headerTintColor: '#ffffff',
headerTitleStyle: {
fontFamily: 'Agright',
textAlign: 'center'
},
headerTitleAlign: 'center',
};
export default function App() {
const [appIsReady, setAppIsReady] = useState(false);
const [isAuthNd, setIsAuthNd] = useState(false);
const [isVisible, setIsVisible] = useState(false);
const [fontsLoaded] = Font.useFonts({
Agright: require('./assets/fonts/AgrightRegular-qZ5dr.otf'),
})
const { changeLanguage, currentLang } = useContext(LocaleContext);
const loadFonts = async () => {
try {
await Font.loadAsync({
Agright: require('./assets/fonts/AgrightRegular-qZ5dr.otf'),
Fridays: require('./assets/fonts/Fridays-AWjM.ttf'),
MyChemicalRomance: require('./assets/fonts/MyChemicalRomance-1X5Z.ttf'),
Toxia: require('./assets/fonts/Toxia-OwOA.ttf'),
Varukers: require('./assets/fonts/VarukersPersonalUse-K70Be.ttf'),
});
} catch (err) {
console.error(err, err.stack);
} finally {
setAppIsReady(true);
}
};
const loadHomeScreen = async () => {
if (appIsReady) {
await SplashScreen.hideAsync();
}
};
useEffect(() => {
if (fontsLoaded) {
setAppIsReady(true);
}
}, [fontsLoaded]);
useEffect(() => {
if (appIsReady) {
loadHomeScreen();
}
}, [appIsReady])
if (!fontsLoaded) {
return null;
}
return (
<SafeAreaProvider>
<DbContextProvider>
<LocaleContextProvider>
<IntlProvider messages={messages[currentLang]} locale={deviceLocale} defaultLocale="en">
<NavigationContainer>
<Stack.Navigator>
{!isAuthNd
? (
<Stack.Screen
name="Login"
component={Login}
options={{
...screenOptions,
headerShown: false,
}}
/>
)
: (
<Stack.Screen
name="Home"
component={Home}
options={{
...screenOptions,
headerShown: false,
}}
/>
)
}
<Stack.Screen
name="Home"
component={Home}
options={{
...screenOptions,
headerShown: false,
}}
/>
<Stack.Screen
name="Flashcards"
component={Flashcards}
options={{
...subScreenOptions,
headerShown: false,
}}
/>
<Stack.Screen
name="StudyMode"
component={StudyMode}
options={{
...subScreenOptions,
headerShown: false,
}}
/>
<Stack.Screen
name="Texts"
component={Texts}
options={{
...subScreenOptions,
headerShown: false,
}}
/>
<Stack.Screen
name="Translator"
component={Translator}
options={{
...subScreenOptions,
headerShown: false,
}}
/>
<Stack.Screen
name="Dictionary"
component={Dictionary}
options={{
...screenOptions,
headerShown: false,
}}
/>
<Stack.Screen
name="Chat"
component={Chat}
options={{
...subScreenOptions,
headerShown: false,
}}
/>
</Stack.Navigator>
</NavigationContainer>
</IntlProvider>
</LocaleContextProvider>
</DbContextProvider>
</SafeAreaProvider>
);
}
"dependencies": {
"@react-navigation/native": "^6.1.6",
"@react-navigation/native-stack": "^6.9.12",
"@react-oauth/google": "^0.11.0",
"axios": "^1.4.0",
"expo": "~48.0.15",
"expo-application": "~5.1.1",
"expo-asset": "~8.9.1",
"expo-auth-session": "~4.0.3",
"expo-crypto": "~12.2.1",
"expo-file-system": "~15.2.2",
"expo-font": "^11.1.1",
"expo-image": "~1.0.1",
"expo-splash-screen": "~0.18.2",
"expo-sqlite": "~11.1.1",
"expo-web-browser": "~12.1.1",
"isaac": "^0.0.5",
"react": "18.2.0",
"react-intl": "^6.4.4",
"react-native": "0.71.8",
"react-native-bcrypt": "^2.4.0",
"react-native-crypto": "^2.2.0",
"react-native-safe-area-context": "4.5.0",
"uuid": "^9.0.0",
"expo-system-ui": "~2.2.1"
},
"devDependencies": {
"@babel/core": "^7.20.0"
},
非常感谢您的帮助!
您找到解决这个问题的方法了吗?我遇到了同样的问题。预先感谢。