Splash Screen white flicker before loading (React Native Expo) - react-native

When the app loads there is a white background then a flicker before the splash screen is shown. I have removed the splash screen from the app.json file since i am manually loading and hiding the splash screen. (Leaving the splash screen in the app.json file results in the splash screen being shown followed by a white flicker and then the splash scrren is shown again a second time)
App.js
import React from 'react';
import { StyleSheet, View, Image } from 'react-native'
import { MyAuthStack, MyMainDrawer } from './Screens/Navigators'
import firebase from './firebase'
import { AppLoading, SplashScreen } from 'expo';
import { Asset } from 'expo-asset';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
authState: false,
imgUrl: '',
isSplashReady: false,
isAppReady: false,
}
}
_cacheSplashResourcesAsync = async () => {
const gif = require('./assets/splash.png');
return Asset.fromModule(gif).downloadAsync();
}
_cacheResourcesAsync = async () => {
SplashScreen.hide();
const images = [
require('./assets/addthreadicon.png'),
require('./assets/500x500.png'),
];
const cacheImages = images.map((image) => Asset.fromModule(image).downloadAsync());
await Promise.all(cacheImages);
firebase.auth().onAuthStateChanged(user => {
if (user != null) {
const userRef = firebase.database().ref(`users/${firebase.auth().currentUser.uid}/img`)
userRef.once('value', snapshot => {
this.setState({ imgUrl: snapshot.val(), authState: true, isAppReady: true })
})
} else {
this.setState({ imgUrl: '', authState: false, isAppReady: true })
}
})
};
render() {
const { isSplashReady, isAppReady, authState } = this.state;
if (!isSplashReady) {
return (
<AppLoading
startAsync={this._cacheSplashResourcesAsync}
onFinish={() => this.setState({ isSplashReady: true })}
onError={process.env.NODE_ENV === 'production' ? undefined : console.warn /* eslint-disable-line no-console */}
autoHideSplash={false}
/>
);
}
return (
<View style={{ flex: 1 }}>
{!isAppReady ? (
<Image
source={require('./assets/splash.png')}
onLoad={this._cacheResourcesAsync}
style={{ width: '100%', height: '100%' }}
/>
) : (
<View style={{ flex: 1 }}>
{authState ? (<MyMainDrawer imgUrl={this.state.imgUrl} />) : (<MyAuthStack />)}
</View>
)
}
</View>
)
}
}
});
app.json
{
"expo": {
"name": "Blank Template",
"slug": "movie",
"privacy": "public",
"sdkVersion": "36.0.0",
"platforms": [
"ios",
"android",
"web"
],
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": [
"**/*"
],
"android": {
"package": "com.saim.moviethreads",
"versionCode": 1,
"config": {
"googleMobileAdsAppId": ""
}
},
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.yourcompany.yourappname",
"buildNumber": "1.0.0"
}
}
}

Splash Screen flickers because you want to change the state of the application as soon as the splash screen loads. I suggest you use AppLoading from expo, this controls the visibility of the splash screen.
<AppLoading
startAsync={*function to load when splash screen starts*}
onFinish={set the state to finished here}
/>

Related

Geofencing is Slow on android compared to iOS

I am working on a bare Expo project that uses the Location SDK (https://docs.expo.io/versions/latest/sdk/location/) to geofence an area.
Geofencing works fine on iOS, however, on Android it can be really slow in the background (or when the app is force-quitted). It can sometimes take more than 15 minutes to run the registered task when exiting or entering a geofence.
I have also noticed that I can force trigger the registered geofence task to run, if I open an app such as Google Maps and hit the GPS button.
Is it possible to speed up location updates somehow, or perhaps configure something in Android Studio?
package.json includes:
"expo-location": "^12.0.4",
"expo-notifications": "^0.11.5",
"expo-permissions": "^12.0.1",
"expo-task-manager": "^9.0.0",
"react": "17.0.1",
"react-native": "0.64.1",
Let me know if you need anything else.
import React, { useEffect, useState } from "react";
import { StyleSheet, Text, View } from "react-native";
import {
getForegroundPermissionsAsync,
requestBackgroundPermissionsAsync,
requestForegroundPermissionsAsync,
startGeofencingAsync,
} from "expo-location";
import * as Notifications from "expo-notifications";
import { LocationGeofencingEventType } from "expo-location";
import * as TaskManager from "expo-task-manager";
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: false,
shouldSetBadge: false,
}),
});
TaskManager.defineTask(
"GEOFENCE_TASK",
({ data: { eventType, region }, error }) => {
if (error) {
// check `error.message` for more details.
return;
}
if (eventType === LocationGeofencingEventType.Enter) {
console.log("You've entered region:", region);
Notifications.scheduleNotificationAsync({
content: {
title: "ENTERED GEOFENCE",
body: region.identifier,
},
trigger: null,
});
} else if (eventType === LocationGeofencingEventType.Exit) {
console.log("You've left region:", region);
Notifications.scheduleNotificationAsync({
content: {
title: "EXITED GEOFENCE",
body: region.identifier,
},
trigger: null,
});
}
}
);
export default function App() {
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const setUp = async () => {
const { granted: notificationsGranted } =
await Notifications.getPermissionsAsync();
if (!notificationsGranted) {
await Notifications.requestPermissionsAsync();
}
const { granted: fgGranted } = await getForegroundPermissionsAsync();
if (!fgGranted) {
await requestForegroundPermissionsAsync();
await requestBackgroundPermissionsAsync();
}
const geofences = [
{
identifier: "Stockholm",
latitude: 59.332598,
longitude: 18.035258,
radius: 100,
notifyOnEnter: true,
notifyOnExit: true,
},
];
await startGeofencingAsync("GEOFENCE_TASK", geofences);
};
setUp();
}, []);
return (
<View style={styles.container}>
{isLoading ? <Text>App is Loading</Text> : <Text>Loading done</Text>}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
I discovered the same "issue" and to mitigate it, i use a foreground notification to put improve the geofencing service.
The good news is thats trick works well with "app in-use" permission. (but background location permission is mandatory)
Regards.

React Native: Standalone, Expo built app on Android crashes when using Facebook login (works on iOS)

I have a React Native app I built using the Expo managed workflow. I am using Facebook login for my app along with Firebase authentication. My understanding is this can not be tested when running in the Expo app, and can only be used in a standalone app.
FB login is working fine in my iOS standalone app, however, in android, it crashes before the Facebook login screen even appears. My LandingPage loads, but as soon as I press the "Login With Facebook" button, it crashes.
Below is my app.json file and my login code. Per the instructions, I have also added the Facebook Key Hash to my project on the Facebook developer site. Can anyone help me understand what is wrong?
app.json:
{
"expo": {
"name": "Pick Up",
"slug": "PickUp",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/ball-and-glove-5.png",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"notification": {
"icon": "./assets/ball-and-glove-5.png",
"color": "#fff",
"androidMode": "default"
},
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true,
"userInterfaceStyle": "light",
"config": {
"googleMobileAdsAppId": "ca-app-pub-xxxxxxxxxxxxxxxx~xxxxxxxxxx",
"googleMapsApiKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
"bundleIdentifier": "com.myapp.name",
"buildNumber": "1.0.0"
},
"userInterfaceStyle": "automatic",
"android": {
"useNextNotificationsApi": true,
"userInterfaceStyle": "dark",
"config": {
"googleMobileAdsAppId": "ca-app-pub-xxxxxxxxxxxxxxxx~xxxxxxxxxx",
"googleMaps": {
"apiKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
},
"package": "com.myapp.name",
"versionCode": 1
},
"web": {
"favicon": "./assets/favicon.png"
},
"facebookScheme": "fbxxxxxxxxxxxxxxxx",
"facebookAppId": "xxxxxxxxxxxxxxx",
"facebookDisplayName": "myname"
}
}
Login Code:
import React, { useState, useEffect, useContext } from 'react';
import { Alert, Animated, Image, StatusBar, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { Ionicons } from '#expo/vector-icons';
import * as WebBrowser from 'expo-web-browser';
import * as Facebook from 'expo-facebook';
import * as firebase from 'firebase';
import { loginUser } from '../../firebase.js';
import { StoreContext } from '../../contexts/storeContext';
const turquoise = "#4ECDC4";
const LandingPage = ({ navigation }) => {
const store = useContext(StoreContext);
const handleFacebook = async () => {
try {
await Facebook.initializeAsync();
const options = {
permissions: ["public_profile"]
}
const { type, token } = await Facebook.logInWithReadPermissionsAsync(options);
if (type === "success") {
const credential = firebase.auth.FacebookAuthProvider.credential(token);
if (credential) {
const bool = await loginUser(credential);
}
}
else {
Alert.alert("", "There was a problem. Please try again.");
}
}
catch (e) {
console.log("e : ", e);
Alert.alert("", e);
}
}
return (
<View>
<StatusBar barStyle="dark-content" backgroundColor={ turquoise } />
<View>
<TouchableOpacity onPress={ handleFacebook }>
<Ionicons name="logo-facebook" />
<Text>Continue with Facebookk</Text>
</TouchableOpacity>
<TouchableOpacity onPress={ () => navigation.navigate("PhoneVerification") }>
<Text>Use cell phone number</Text>
</TouchableOpacity>
</View>
<View>
<Image
resizeMode="contain"
source={require('../../assets/new-logo.png')}
/>
</View>
</View>
)
}
The issue was that for Android, Facebook.initializeAsync() needs to be passed an argument -- your FB appID.
const handleFacebook = async () => {
try {
await Facebook.initializeAsync("123456789"); // <-- your FB appID
const options = {
permissions: ["public_profile"]
}
const { type, token } = await Facebook.logInWithReadPermissionsAsync(options);
if (type === "success") {
const credential = firebase.auth.FacebookAuthProvider.credential(token);
// do the rest of your Firebase login logic
}
else {
Alert.alert("", "There was a problem. Please try again.");
}
}
catch (e) {
console.log("e : ", e);
Alert.alert("", e);
}
}

Header back button disappears on stand alone build

When I build a stand alone android app the header left back button disappears, yet it's there if you click on it. It has no issue on the emulator. What could cause this?
I'm not sure when it started because I was relying on the emulator, but I do know that it was working at some point
Here is my app.json
{
"name": "appname",
"displayName": "appname",
"expo": {
"name": "appname",
"version": "1.0.0",
"slug": "appslug",
"orientation": "portrait",
"privacy": "unlisted",
"sdkVersion": "32.0.0",
"description": "",
"platforms": [
"ios",
"android"
],
"icon": "./assets/images/icon.png",
"splash": {
"image": "./assets/images/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"updates": {
"enabled": true,
"fallbackToCacheTimeout": 30000,
"checkAutomatically": "ON_LOAD"
},
"ios": {
"buildNumber": "1.0.0",
"icon": "./assets/images/icon.png",
"bundleIdentifier": "my.unique.id"
// "splash": {
// "backgroundColor": "#FFFFFF",
// "resizeMode": "cover",
// "image": "./assets/iphone/Default-667h#2x.png"
// }
},
"android": {
"versionCode": 1,
"icon": "./assets/images/icon.png",
"package": "my.unique.id",
"adaptiveIcon": {
"foregroundImage": "./assets/images/icon.png",
"backgroundColor": "#FFFFFF"
}
// "splash": {
// "backgroundColor": "#FFFFFF",
// "resizeMode": "cover",
// "mdpi": "./assets/android/res/drawable-mdpi/background.9.png", // natural sized image (baseline),
// "hdpi": "./assets/android/res/drawable-hdpi/background.9.png", // scale 1.5x
// "xhdpi": "./assets/android/res/drawable-xhdpi/background.9.png", // scale 2x
// "xxhdpi": "./assets/android/res/drawable-xxhdpi/background.9.png", // scale 3x
// "xxxhdpi": "./assets/android/res/drawable-xxxhdpi/background.9.png" // scale 4x
// }
},
"hooks": {
"postPublish": [
{
"file": "sentry-expo/upload-sourcemaps",
"config": {
"organization": "my.org",
"project": "proj",
"authToken": "************"
}
}
]
},
"primaryColor": "#fefefe"
}
}
And here is my App.js
import React from 'react';
import { Platform, StatusBar, StyleSheet, View } from 'react-native';
import { AppLoading, Asset, Font, Icon } from 'expo';
import AppNavigator from './navigation/AppNavigator';
import { Ionicons } from '#expo/vector-icons';
import Sentry from 'sentry-expo';
// Remove this once Sentry is correctly setup.
Sentry.enableInExpoDevelopment = true;
Sentry.config('https://sentry').install();
export default class App extends React.Component {
state = {
isLoadingComplete: false,
};
async componentDidMount() {
await Font.loadAsync({
'Roboto': require('native-base/Fonts/Roboto.ttf'),
'Roboto_medium': require('native-base/Fonts/Roboto_medium.ttf'),
...Ionicons.font,
});
}
render() {
if (!this.state.isLoadingComplete && !this.props.skipLoadingScreen) {
return (
<AppLoading
startAsync={this._loadResourcesAsync}
onError={this._handleLoadingError}
onFinish={this._handleFinishLoading}
/>
);
} else {
return (
<View style={styles.container}>
{Platform.OS === 'ios' && <StatusBar barStyle="default" />}
<AppNavigator />
</View>
);
}
}
_loadResourcesAsync = async () => {
return Promise.all([
Asset.loadAsync([
require('./assets/images/robot-dev.png'),
require('./assets/images/robot-prod.png'),
]),
Font.loadAsync({
// This is the font that we are using for our tab bar
...Icon.Ionicons.font,
// We include SpaceMono because we use it in HomeScreen.js. Feel free
// to remove this if you are not using it in your app
'space-mono': require('./assets/fonts/SpaceMono-Regular.ttf'),
}),
]);
};
_handleLoadingError = error => {
// In this case, you might want to report the error to your error
// reporting service, for example Sentry
console.warn(error);
};
_handleFinishLoading = () => {
this.setState({ isLoadingComplete: true });
};
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
});
/navigation/MainTabNavigator.js
import React from 'react';
import {Platform} from 'react-native';
import {createBottomTabNavigator, createStackNavigator} from 'react-navigation';
import TabBarIcon from '../components/TabBarIcon';
import HomeScreen from '../screens/HomeScreen';
import NotificationScreen from '../screens/NotificationScreen';
import SettingsScreen from '../screens/SettingsScreen';
import ProfileScreen from "../screens/ProfileScreen";
import DraftScreen from "../screens/DraftScreen";
import StatsScreen from "../screens/StatsScreen";
import Colors from "../constants/Colors";
import ViewStoryScreen from "../screens/ViewStoryScreen";
import LoginScreen from "../screens/LoginScreen";
import RegisterScreen from "../screens/RegisterScreen";
import MyStoriesScreen from "../screens/MyStories";
import EditStoryScreen from "../screens/EditStoryScreen";
import AddStoryScreen from "../screens/AddStoryScreen";
const headerStyle = {
/* The header config from HomeScreen is now here */
/*
For full list of options
https://reactnavigation.org/docs/en/stack-navigator.html#navigationoptions-for-screens-inside-of-the-navigator
*/
defaultNavigationOptions: {
headerStyle: {
backgroundColor: Colors.headerBackgroundColor,
},
headerTintColor: Colors.headerTintColor,
headerTitleStyle: {
fontWeight: 'bold',
},
headerBackTitleStyle: {color: Colors.headerTintColor},
headerBackStyle: {color: Colors.headerTintColor},
headerBackAllowFontScaling: true,
},
};
const HomeStack = createStackNavigator({
Home: HomeScreen,
ViewStoryScreen: ViewStoryScreen,
EditStory: EditStoryScreen,
AddStory: AddStoryScreen,
},
{
/* The header config from HomeScreen is now here */
defaultNavigationOptions: headerStyle.defaultNavigationOptions
}
);
HomeStack.navigationOptions = {
tabBarLabel: 'Home',
tabBarIcon: ({focused}) => (
<TabBarIcon
focused={focused}
name={
Platform.OS === 'ios'
? `ios-home`
: 'md-home'
}
/>
),
};
const NotificationStack = createStackNavigator({
Links: NotificationScreen,
ViewStoryScreen: ViewStoryScreen,
},
{
/* The header config from HomeScreen is now here */
defaultNavigationOptions: headerStyle.defaultNavigationOptions
});
NotificationStack.navigationOptions = {
tabBarLabel: 'Notifications',
tabBarIcon: ({focused}) => (
<TabBarIcon
focused={focused}
name={Platform.OS === 'ios' ? 'ios-notifications' : 'md-notifications'}
/>
),
};
const SettingsStack = createStackNavigator({
Settings: SettingsScreen,
Profile: ProfileScreen,
Drafts: DraftScreen,
Stats: StatsScreen,
Login: LoginScreen,
Register: RegisterScreen,
MyStories: MyStoriesScreen,
ViewStoryScreen: ViewStoryScreen,
EditStory: EditStoryScreen,
AddStory: AddStoryScreen,
},
{
/* The header config from HomeScreen is now here */
defaultNavigationOptions: headerStyle.defaultNavigationOptions
}
);
SettingsStack.navigationOptions = {
tabBarLabel: 'Settings',
tabBarIcon: ({focused}) => (
<TabBarIcon
focused={focused}
name={Platform.OS === 'ios' ? 'ios-options' : 'md-options'}
/>
),
};
export default createBottomTabNavigator({
HomeStack,
NotificationStack,
SettingsStack,
});
Solution
As #Masuk Helal Anik mentioned this is a bug
Here is what worked for me, but had to sacrifice header back title.
In every screen add this
static navigationOptions = ({navigation}) => {
return {
headerLeft: (
<Ionicons
name={Platform.OS === "ios" ? "ios-arrow-back" : "md-arrow-back"}
size={Platform.OS === "ios" ? 35 : 24}
color={Colors.headerTintColor}
style={
Platform.OS === "ios"
? { marginBottom: -4, width: 25, marginLeft: 9 }
: { marginBottom: -4, width: 25, marginLeft: 20 }
}
onPress={() => {
navigation.goBack();
}}
/>
),
title: 'Screen Title'
}
};
It seems to me like a bug. As a solution in this issue is stated
if you use expo you should include the assets from react-navigation in
your assetBundlePatterns so the images are bundled with your app when
you build a standalone app. the easiest way to do this is to just
bundle all assets that your app uses:
https://github.com/expo/new-project-template/blob/6d4c5636de573852dfd2f7715cfa152fd9c84f89/app.json#L20-L22.
to fix it in development mode within expo, you can cache the assets
locally as per this guide. we do this in the navigationplayground
example app, so you can copy that code from here.
There is some workaround also. Try out them to find which one working for you!

TabNavigator only showing first tab

I'm developing a new app with RN and using TabNavigator from react-navigation library, the most basic example of TabNavigator only showing first Tab. I've read somewhere that it could be a bug and could be solved by downgrading react-navigation to 1.0.3 but it didn't work for me. How to solve it?
tab1
tab2
app.js
import React, { Component } from 'react';
import Dashboard from './screens/Dashboard';
import Profile from './screens/Profile';
// import {I18nManager} from 'react-native';
// import { Container, Header, Content, Footer, FooterTab, Button, Icon, Text, Badge, Tab, Tabs } from 'native-base';
import { TabNavigator, TabBarBottom } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
export default TabNavigator({
home: { screen: Dashboard },
profile: { screen: Profile },
nav: { screen: Dashboard },
},
{
navigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, tintColor }) => {
const { routeName } = navigation.state;
let iconName;
if (routeName === 'home') {
iconName = `ios-pulse${focused ? '' : '-outline'}`;
} else if (routeName === 'profile') {
iconName = `ios-person${focused ? '' : '-outline'}`;
}
// You can return any component that you like here! We usually use an
// icon component from react-native-vector-icons
return <Ionicons name={iconName} size={25} color={tintColor} />;
},
}),
tabBarOptions: {
activeTintColor: 'blue',
inactiveTintColor: 'gray',
},
tabBarComponent: TabBarBottom,
lazy: false,
tabBarPosition: 'bottom',
animationEnabled: false,
swipeEnabled: false,
}
);
Dashboard.js
import React, { Component } from 'react';
import { TouchableOpacity,
Title,
Subtitle,
Tile,
Divider,
ImageBackground,
Card,
Image,
View,
Caption,
GridRow,
ListView,
Screen
} from '#shoutem/ui';
// import I18n from 'react-native-i18n';
// import {I18nManager} from 'react-native';
// I18nManager.forceRTL(true);
export default class Dashboard extends Component {
constructor(props) {
super(props);
this.renderRow = this.renderRow.bind(this);
this.state = {
restaurants: [
{
'name': 'برنامه ۳۰ روزه هوازی',
'address': 'چربی سوزی | کاهش وزن',
'image': { 'url': 'https://shoutem.github.io/static/getting-started/restaurant-1.jpg' },
},
{
'name': 'تمرین سینه',
'address': 'افزایش قدرت و حجم عضلات سینه و فرم دهی به آن',
'image': { 'url': 'https://shoutem.github.io/static/getting-started/restaurant-2.jpg' },
},
{
'name': 'تمرین شکم',
'address': 'حاضرید که عضلات شکمتان را ورزیده و تکه کنید؟ حرکاتی که در زیر آمده، راهنمایی است که همیشه برای شما کافی و مفید خواهد بود.',
'image': { 'url': 'https://shoutem.github.io/static/getting-started/restaurant-3.jpg' },
},
{
'name': 'تمرین سینه',
'address': 'افزایش قدرت و حجم عضلات سینه و فرم دهی به آن',
'image': { 'url': 'https://shoutem.github.io/static/getting-started/restaurant-2.jpg' },
},
{
'name': 'تمرین شکم',
'address': 'حاضرید که عضلات شکمتان را ورزیده و تکه کنید؟ حرکاتی که در زیر آمده، راهنمایی است که همیشه برای شما کافی و مفید خواهد بود.',
'image': { 'url': 'https://shoutem.github.io/static/getting-started/restaurant-3.jpg' },
},
{
'name': 'تمرین ران پا',
'address': 'این یک تست است.',
'image': { 'url': 'https://shoutem.github.io/static/getting-started/restaurant-2.jpg' },
},
],
};
}
renderRow(rowData, sectionId, index) {
// rowData contains grouped data for one row,
// so we need to remap it into cells and pass to GridRow
if (index === '0') {
return (
<TouchableOpacity key={index}>
<ImageBackground
styleName="large"
source={{ uri: rowData[0].image.url }}
>
<Tile>
<Title styleName="md-gutter-bottom">{rowData[0].name}</Title>
<Subtitle styleName="sm-gutter-horizontal">{rowData[0].address}</Subtitle>
</Tile>
</ImageBackground>
<Divider styleName="line" />
</TouchableOpacity>
);
}
const cellViews = rowData.map((restaurant, id) => {
return (
<TouchableOpacity key={id} styleName="flexible">
<Card styleName="flexible">
<Image
styleName="medium-wide"
source={{ uri: restaurant.image.url }}
/>
<View styleName="content">
<Subtitle numberOfLines={3}>{restaurant.name}</Subtitle>
<View styleName="horizontal">
<Caption styleName="collapsible" numberOfLines={2}>{restaurant.address}</Caption>
</View>
</View>
</Card>
</TouchableOpacity>
);
});
return (
<GridRow columns={2}>
{cellViews}
</GridRow>
);
}
render() {
const restaurants = this.state.restaurants;
// Group the restaurants into rows with 2 columns, except for the
// first restaurant. The first restaurant is treated as a featured restaurant
let isFirstArticle = true;
const groupedData = GridRow.groupByRows(restaurants, 2, () => {
if (isFirstArticle) {
isFirstArticle = false;
return 2;
}
return 1;
});
return (
<ListView
data={groupedData}
renderRow={this.renderRow}
/>
);
}
}
Profile.js
import React, { Component } from 'react';
import { Container, Header, Content, Form, Item, Input, Label } from 'native-base';
// import I18n from 'react-native-i18n';
// import {I18nManager} from 'react-native';
// I18nManager.forceRTL(true);
export default class Profile extends Component {
render() {
return (
<Container>
<Header />
<Content>
<Form>
<Item floatingLabel>
<Label>نام</Label>
<Input />
</Item>
<Item floatingLabel last>
<Label>قد (سانتیمتر)</Label>
<Input />
</Item>
</Form>
</Content>
</Container>
);
}
}
package.json
"dependencies": {
"#shoutem/ui": "^0.23.4",
"native-base": "^2.4.2",
"react": "16.3.1",
"react-native": "0.55.3",
"react-native-vector-icons": "^4.6.0",
"react-navigation": "^1.0.3"
},
"devDependencies": {
"babel-jest": "22.4.3",
"babel-preset-react-native": "4.0.0",
"eslint": "^4.19.1",
"eslint-plugin-react": "^7.7.0",
"jest": "22.4.3",
"react-test-renderer": "16.3.1"
},
"jest": {
"preset": "react-native"
}
I've already tried latest version of react-navigation so its downgraded version you see in package.json
I've found solution to this, and I'm going to be as specific as I can for all the people out there that might face this!
First of all it's a problem with I18nManager.forceRTL(true);
the moment you use this line of code anywhere on your react-native code that its screen gonna get rendered, and on 2nd reload, the app the layout is being change to RTL, and it does not change even if you comment that line! You'll have to use I18nManager.forceRTL(false); and reload a couple of times to get back to normal ltr setup.
The thing is... some of us really need that RTL layout change like I thought I did! Well guess what react-navigation does not respect that, at least for now and in the TabNabigator dept.
So to sum it all up: RTL layout on RN will break your react-navigation's Tab Navigation! (as of the current version you can see in the packages.json above) The issue makes only the first that visible and for the others a bland tab shows, if you turn on the animation or swipe other tabs will show but tabs behave in a weird way, meaning the last tab is active when the first one is active and vice versa... middle tabs are never focused by the way.
So you should know you can't use tabbed navigation with RTL layout. I'll update this answer after this issue got a fix!
I have run it using react-native run-ios, and all the tabs display a different screen. If you are referring to the fact that the nav tab does not change when you click on it whilst on the home tab, both the home and nav tabs are using the Dashboard screen.
The following is my package.json file for this project:
{
"name": "a",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest"
},
"dependencies": {
"react-native-code-push": "1.15.0-beta",
"#babel/core": "^7.0.0-beta.40",
"#shoutem/ui": "^0.23.4",
"eslint": "^3.19.0",
"native-base": "^2.4.2",
"react": "16.3.1",
"react-native": "0.55.3",
"react-native-vector-icons": "^4.6.0",
"react-navigation": "^1.5.11"
},
"devDependencies": {
"babel-jest": "22.4.3",
"babel-preset-react-native": "4.0.0",
"jest": "22.4.3",
"react-test-renderer": "16.3.1"
},
"jest": {
"preset": "react-native"
}
}

Change loading icon size for different DPI deivces

I am working on application which is implemented using Expo and react native. I have splash screen in my app.The icon in splash screen loading screen is coming correct in android devices but very small in IOS devices ( in different dpi).I want to make icon resize based on dpi which present under loading .Can anyone help me out here.Thank you.
Config file:-
"expo": {
"name": "ExpoApp",
"description": "No description",
"slug": "evosus",
"privacy": "unlisted", // public
"sdkVersion": "19.0.0",
"version": "1.0.0",
"orientation": "portrait,landscape",
"primaryColor": "green",
"icon": "./assets/icons/ball.png",
//"icon": "./assets/icons/logo_Dark.png",
"notification": {
"icon": "./assets/icons/ball.png",
"color": "#000000"
},
"loading": {
//"icon": "./assets/icons/loading-icon.png",
"icon": "./assets/icons/icon.png",//I want to resize this icon based on screen dpi
"hideExponentText": true
},
"packagerOpts": {
"assetExts": [
"ttf"
]
},
"ios": {
"supportsTablet": true
}
//,"androidStatusBarColor": "#444444"
}
}
App.js component:-
import React from 'react';
import { Platform, StatusBar, StyleSheet, View } from 'react-native';
import { AppLoading, Asset, Font, SQLite } from 'expo';
import { Ionicons, EvilIcons } from '#expo/vector-icons';
import RootNavigation from './navigation/RootNavigation';
// Services
import DB from "./src/Services/DBDefinitionService";
import appService from "./src/Services/AppService";
console.ignoredYellowBox = [ 'Setting a timer' ];
export default class App extends React.Component {
state = {
assetsAreLoaded: false,
};
componentWillMount() {
this._loadAssetsAsync();
// Added by Anil G on 23/08/2017
this.db_init();
this.db_device_info_save();
}
render() {
if (!this.state.assetsAreLoaded && !this.props.skipLoadingScreen) {
return <AppLoading/>;
} else {
return (
<View style={styles.container}>
{Platform.OS === 'ios' && <StatusBar barStyle="default" />}
{Platform.OS === 'android' &&
<View style={styles.statusBarUnderlay} />}
<RootNavigation />
</View>
);
}
}
async _loadAssetsAsync() {
try {
await Promise.all([
Asset.loadAsync([
require('./assets/images/robot-dev.png'),
require('./assets/images/robot-prod.png'),
]),
Font.loadAsync([
// This is the font that we are using for our tab bar
Ionicons.font,
EvilIcons.font,
// We include SpaceMono because we use it in HomeScreen.js. Feel free
// to remove this if you are not using it in your app
{ 'space-mono': require('./assets/fonts/SpaceMono-Regular.ttf'),
'roboto-regular': require('./assets/fonts/Roboto-Regular.ttf'),
'roboto-medium': require('./assets/fonts/Roboto-Medium.ttf'),
},
]),
]);
} catch (e) {
// In this case, you might want to report the error to your error
// reporting service, for example Sentry
console.warn(
'There was an error caching assets (see: App.js), perhaps due to a ' +
'network timeout, so we skipped caching. Reload the app to try again.'
);
console.log(e);
} finally {
this.setState({ assetsAreLoaded: true });
}
}
async db_init() {
await DB.init();
}
async db_device_info_save() {
await appService.device_info_save();
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
statusBarUnderlay: {
height: 24,
backgroundColor: 'rgba(0,0,0,0.2)',
},
});
If I remember properly you can define it the same way you do in iOS, adding #x2, #x4...to your icon name and defining one for each dpi.