React-Native Expo: How to keep app tabs-bar showing on in-app browser? - react-native

I'm using Expo tabs app and Expo WebBrowser.
What I want to accomplish is to keep the in-app browser open inside the tab not in a popup modal, so the tabs-bar keep visible and you would be able to open another tab and click back on the browser tab to continue from where you left.
My current code
import React, { Component } from 'react';
import { Button, Text, View, StyleSheet } from 'react-native';
import { Constants, WebBrowser } from 'expo';
export default class LinksScreen extends React.Component {
state = {
result: null
};
render () {
return (
<View style={styles.container}>
<Button
style={styles.paragraph}
title="Open WebBrowser"
onPress={this._handlePressButtonAsync}
/>
<Text>{this.state.result && JSON.stringify(this.state.result)}</Text>
</View>
);
}
_handlePressButtonAsync = async () => {
let result = await WebBrowser.openBrowserAsync('https://expo.io');
this.setState({ result });
};
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1'
}
});

Related

How to convert my website to app using React Native Expo WebBrowser?

I want to make an app that shows the URL I passes. I tried react native web view and it got some issues while deep linking and others. I found expo webbrowser and I find that solves my problem.
The code I tried is the following
import React, { useState } from 'react';
import { Button, Text, View, StyleSheet } from 'react-native';
import * as WebBrowser from 'expo-web-browser';
import Constants from 'expo-constants';
export default function App() {
const [result, setResult] = useState(null);
const _handlePressButtonAsync = async () => {
let result = await WebBrowser.openBrowserAsync('https://expo.io');
setResult(result);
};
return (
<View style={styles.container}>
<Button title="Open WebBrowser" onPress={_handlePressButtonAsync} />
<Text>{result && JSON.stringify(result)}</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
});
It's the demo code from the expo webbrowser site. I want to remove the address bar on the top and launch the website without clicking the button. The following code didn't work
let result = await WebBrowser.openBrowserAsync('https://expo.io',{showTitle:false});
....
return (_handlePressButtonAsync);
Expo Webbrowser

How to add style customisation in Google Ads for React Native app?

I am using below package currently. But I am failing to add style customisation in my AdMobBanner component. Please tell if any other package might be useful for Google Ads customisation or any other Platform Ads that supports customisation.
https://www.npmjs.com/package/react-native-admob
Please click on this link to see my current O/P. I want to remove border and add labels and buttons below it. Is it possible?
import React, { PureComponent } from 'react';
import { ScrollView, StyleSheet, View } from 'react-native';
import { AdMobBanner } from 'react-native-admob';
const BannerExample = ({ style, title, children, ...props }) => (
<View {...props} style={[styles.example, style]}>
<View>{children}</View>
</View>
);
const adUnitID = 'ca-app-pub-3940256099942544/2934735716';
export default class GoogleAdsCompo extends PureComponent {
render() {
return (
<ScrollView>
<BannerExample title="Smart Banner">
<AdMobBanner
adSize="mediumRectangle"
adUnitID={adUnitID}
ref={el => (this._smartBannerExample = el)}
/>
</BannerExample>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
example: {
paddingVertical: 10,
justifyContent: 'center',
alignItems: 'center',
},
title: {
margin: 10,
fontSize: 20,
},
});

How to show loading progress or spinner in the middle of the screen with React Native?

I am developing React Native app.
I was able to solve all problems by myself but this is exception.
I am going to load another screen with bottom tab navigator.
For example, after user login to the app, it should show main home screen which has many pictures and many style sheet effects, icons. Because of that, after login confirm ( I mean after alert of the login confirm), the main home screen appears after a few seconds.
So I want to show some spinner in the login screen while loading main home screen in the background and when it is ready to show, erase spinner and show main home screen.
How can I do this?
My bottom tab navigator was simply created with createBottomTabNavigator() method.
So in your case you can do several things
You can use React Native Activity Indicator -> View
You can use Overlay Library -> react-native-loading-spinner-overlay -> View GitHub
If you like to make loading like facebook / instagram -> then use react-native-easy-content-loader -> View GitHub
Assume that you are using React Native Activity Indicator :
import { ActivityIndicator } from "react-native";
export default class HomeScreen extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true
};
}
//Get Home Screen Data API Action
componentDidMount() {
this.loadAPI(); // Call home screen get data API function
}
//Login API Function
loadAPI = () => {
this.setState({ isLoading: true }); // Once You Call the API Action loading will be true
fetch(API_URL, {
method: "POST",
headers: {
"Content-Type": "application/json"
}
})
.then(response => response.json())
.then(responseText => {
// You can do anything accroding to your API response
this.setState({ isLoading: false }); // After getting response make loading to false
})
.catch(error => {});
};
render() {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
{this.state.isLoading && <ActivityIndicator color={"#fff"} />}
</View>
);
}
}
If you want to hide all the view until loading finish like images, so you can use custom library instead of Activity Indicator.
I have created my custom Loader component. Using this you can display built in ActivityIndicator or your custom gif loader image with overlay.
Loader.js
import React, { Component } from 'react';
import {
StyleSheet,
View,
Modal,
Image,
ActivityIndicator
} from 'react-native';
class Loader extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: this.props.isLoading
}
}
static getDerivedStateFromProps(nextProps) {
return {
isLoading: nextProps.isLoading
};
}
render() {
return (
<Modal
transparent={true}
animationType={'none'}
visible={this.state.isLoading}
style={{ zIndex: 1100 }}
onRequestClose={() => { }}>
<View style={styles.modalBackground}>
<View style={styles.activityIndicatorWrapper}>
<ActivityIndicator animating={this.state.isLoading} color="black" />
{/* If you want to image set source here */}
{/* <Image
source={require('../assets/images/loader.gif')}
style={{ height: 80, width: 80 }}
resizeMode="contain"
resizeMethod="resize"
/> */}
</View>
</View>
</Modal>
)
}
}
const styles = StyleSheet.create({
modalBackground: {
flex: 1,
alignItems: 'center',
flexDirection: 'column',
justifyContent: 'space-around',
backgroundColor: '#rgba(0, 0, 0, 0.5)',
zIndex: 1000
},
activityIndicatorWrapper: {
backgroundColor: '#FFFFFF',
height: 100,
width: 100,
borderRadius: 10,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-around'
}
});
export default Loader
Now you can use it when you have to display loading indicator as below :
<Loader isLoading={this.state.isLoading} />
import { ActivityIndicator } from 'react-native';
export default class LoginScreen extends Component {
constructor(props) {
super(props);
this.state = {
spinner : true
}
}
render() {
return (
<View style={{flex : 1, justifyContent: 'center', alignItems: 'center',}}>
{
this.state.spinner &&
<ActivityIndicator color={'#fff'} />
}
</View>
)
}
}
So you can show the SPinner for suppose when you have to load an API or something and when you get the response of api, you can set spinner loading value to false.
For eg :
import {View, ActivityIndicator } from 'react-native';
export default class MainScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
spinner : true
}
}
componentDidMount(){
this.loadApi();
}
loadApi = async() => {
let result = axios.get('url').then((data) =>{
this.setState({spinner:false});
}
).catch((err) => this.setState({spinner:false})
}
render() {
return (
<View style={{flex : 1, justifyContent: 'center', alignItems: 'center',}}>
{
this.state.spinner? <ActivityIndicator color={'#fff'} />:<View><Text>Data loaded</Text></View>
}
</View>
)
}
}
you have to use ActivityIndicator you can have to load this activityindicator before getting data from the server , you have to check below code hope you will understand
import React, {useEffect, useState} from 'react';
import {ActivityIndicator, View, Dimensions} from 'react-native';
import HomeScreen from './Home';
const DataViewer = () => {
const [data, setData] = useState([]);
const {height, width} = Dimensions.get('window');
useEffect(() => {
fetch('http://example.com/movies.json')
.then(response => {
return response.json();
})
.then(myJson => {
setData(myJson);
});
});
return data.length > 0 ? (
<HomeScreen data={data} />
) : (
<View
style={{justifyContent: 'center', alignItems: 'center', height, width}}>
<ActivityIndicator size="large" color="#0000ff" />
</View>
);
};
export default DataViewer;
You can use the Activity indicator as the default loading animation. But you can also use Lottie files to implement custom loading screen animation on your project by installing npm i lottie-react-native or yarn add lottie-react-native

Two of my common components that I'm importing with index.js don't fire

I'm doing this course at Udemy. Files: https://github.com/StephenGrider/ReactNativeReduxCasts/tree/master/auth
The issue I'm having is with importing common components. It's only for 2 of the common components--the rest work fine. Card, CardSection, Header, Input.
When I try to import the Button or Spinner, they won't fire. But if I use the basic functionality (putting the TouchableOpacity or ActivityIndicator in the file directly and do all the styling THERE), they work fine.
Here's the file structure:
Here's /components/common/index.js
export * from './Header';
export * from './Input';
export * from './Card';
export * from './CardSection';
export * from './Button';
export * from './Spinner';
Here's Button.js
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
const Button = ({ propOnPress, children }) => {
const { buttonStyle, textStyle } = styles;
return (
<TouchableOpacity onPress={propOnPress} style={buttonStyle}>
<Text style={textStyle}>
{children}
</Text>
</TouchableOpacity>
)
}
const styles = {
textStyle: {
alignSelf: 'center',
color: '#fff',//'#007aff',
fontSize: 16,
fontWeight: '600',
paddingTop: 10,
paddingBottom: 10
},
buttonStyle: {
flex: 1,
alignSelf: 'stretch',
backgroundColor: '#007aff', //'#fff',
borderRadius: 5,
borderWidth: 1,
borderColor: '#007aff',
marginLeft: 5,
marginRight: 5,
}
}
export { Button };
Here's Spinner.js
import React from 'react';
import { View, ActivityIndicator } from 'react-native';
const Spinner = ({ size }) => {
return (
<View style={styles.spinnerStyle}>
<ActivityIndicator size={size || 'large'} />
</View>
)
}
const styles = {
spinnerStyle: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
}
export { Spinner }
Here's where I import them in LoginForm.js
import { Card, CardSection, Button, Spinner, Input } from './common';
And where they're used in the code in LoginForm.js
renderButton() {
//console.log('render button');
if (this.state.loading) {
console.log('returning the spinner');
return <Spinner animating={this.state.loading} size="small" />;
}
console.log('gonna return a button');
return(
<Button onPress={this.onYouPressedIt.bind(this)}>Log in</Button>
);
}
What am I doing wrong?
Issues I see with the Button.js file
Property onPress doesn't exist. You created a property called propOnPress
So, your Button component should be used like this
<Button propOnPress={}>...</Button>
Issues I see with the Spinner.js file
Property animating doesn't exist on the component. The only properties you created is size.
Solution would be to simply add an animating property to your Spinner component.
Component would end up looking like this
const Spinner = ({ animating, size }) => {
return (
{
animating ? (
<View style={styles.spinnerStyle}>
<ActivityIndicator size={size || 'large'} />
</View>
) : null
}
)
}
I assume the animating property is a boolean which if false then you don't want to display the activity indicator which is why I added the ternary operator.

Open a WebView after a button pressed with reactNative

I am developing a mobile app with React Native. I want to open a WebView after a button pressed. Here is my code, but its not working. The button onPress method is not working.
import React, { Component } from 'react';
import { View, StyleSheet, Button, WebView } from 'react-native';
import { Constants } from 'expo';
export default class webView extends Component {
onNavigationStateChange = navState => {
if (navState.url.indexOf('https://www.google.com') === 0) {
const regex = /#access_token=(.+)/;
const accessToken = navState.url.match(regex)[1];
console.log(accessToken);
}
};
renderContent() {
return (
<WebView
source={{
uri: '',
}}
onNavigationStateChange={this.onNavigationStateChange}
startInLoadingState
scalesPageToFit
javaScriptEnabled
style={{ flex: 1 }}
/>
);
}
render() {
return (
<View style={styles.container}>
<Button
style={styles.paragraph}
title="Login"
onPress={() => this.renderContent()}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
});
I tried onPress={this.renderContent()} this also, but it give an exception. What can I do ?
You aren't rendering your WebView in the the render() method of the Component. Just think of render as your DOM of the webpage. You need to provide the component a place in the render component, than you can remove it or add it, see i am calling the renderContent from the render method. So whenever the state variable showWebView is true it will render the WebView You should do something like this:
import React, { Component } from 'react';
import { View, StyleSheet, Button, WebView } from 'react-native';
import { Constants } from 'expo';
export default class webView extends Component {
state={
showWebView: false
}
onNavigationStateChange = navState => {
if (navState.url.indexOf('https://www.google.com') === 0) {
const regex = /#access_token=(.+)/;
const accessToken = navState.url.match(regex)[1];
console.log(accessToken);
}
};
renderContent() {
return (
<WebView
source={{
uri: '',
}}
onNavigationStateChange={this.onNavigationStateChange}
startInLoadingState
scalesPageToFit
javaScriptEnabled
style={{ flex: 1 }}
/>
);
}
render() {
return (
<View style={styles.container}>
{ this.state.showWebView && this.renderContent() }
<Button
style={styles.paragraph}
title="Login"
onPress={() => this.setState({showWebView: true})}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
});
I think you must import the following
import { WebView } from 'react-native-webview'
instead of
'react'