I followed the react-navigation API instructions as in the link (https://reactnavigation.org/docs/tab-based-navigation.html) and created Tabbar app with TabNavigator stack and each tab has StackNavigator screens. I purposefully commented the tabBarComponent and tabBarPosition because I want the Tabs to appear like native for Android (Top Tabbbar) and IOS (Bottom Tabbar) with same code base. The IOS Tab bar works correctly but when I look at the Android tabbar, the top portion of the tab bar is overlap/overflowing to the Android status bar (I mean the section where the time, battery and wifi symbols appear). Also, the icons and label font size are bigger compared to IOS tab bar size which makes the label to wrap to next line (see "Abcd's ef" tab). What needs to be done, in order for the Android Tabbar to show correctly like the IOS tabbar but at the top i.e., without overflow, wrap text and correct icon and label size. I have provided below the code as well as screenshots of Android and IOS Tabbar.
FYI, I am using Expo on Android and IOS device (not simulators) with create-react-native-app application
[IOS][1]
[Android][2]
[Android Screen with issue details][3]
***Commented Code:***
//tabBarComponent: TabBarBottom,
//tabBarPosition: 'bottom',
***Codes:***
<code>
import React, { Component } from 'react';
import { View, Text, StyleSheet, Platform } from 'react-native';
import FirstScreen from './tabs/FirstScreen';
//import SecondScreen from './tabs/SecondScreen';
import FagsHome from './FagsHome';
import Movies from './Movies';
import MenuSecondScreen from './MenuSecondScreen';
import ThirdScreen from './tabs/ThirdScreen';
import FourthScreen from './tabs/FourthScreen';
import FifthScreen from './tabs/FifthScreen';
import { TabNavigator, TabBarBottom, StackNavigator } from 'react-navigation';
import IconOcticons from 'react-native-vector-icons/Octicons';
import IconFontAwesome from 'react-native-vector-icons/FontAwesome';
// What's Up
const WhatsupStackMain = StackNavigator(
{
FirstScreen: {
screen: FirstScreen,
},
Movies: {
screen: Movies,
},
},
{
initialRouteName: 'FirstScreen',
}
);
const WhatsupStack = StackNavigator(
{
Main: {
screen: WhatsupStackMain,
},
MenuFags: {
screen: MenuSecondScreen,
},
},
{
mode: 'card',
headerMode: 'none',
}
);
// Fags
const FagsStackMain = StackNavigator(
{
FagsHome: {
screen: FagsHome,
},
Movies: {
screen: Movies,
},
},
{
initialRouteName: 'FagsHome',
}
);
const FagsStack = StackNavigator(
{
Main: {
screen: FagsStackMain,
},
MenuFags: {
screen: MenuSecondScreen,
},
},
{
mode: 'card',
headerMode: 'none',
}
);
// Tags
const TagsStackMain = StackNavigator(
{
ThirdScreen: {
screen: ThirdScreen,
},
Movies: {
screen: Movies,
},
},
{
initialRouteName: 'ThirdScreen',
}
);
const TagsStack = StackNavigator(
{
Main: {
screen: TagsStackMain,
},
MenuFags: {
screen: MenuSecondScreen,
},
},
{
mode: 'card',
headerMode: 'none',
}
);
// Settings
const SettingsStackMain = StackNavigator(
{
FourthScreen: {
screen: FourthScreen,
},
Movies: {
screen: Movies,
},
},
{
initialRouteName: 'FourthScreen',
}
);
const SettingsStack = StackNavigator(
{
Main: {
screen: SettingsStackMain,
},
MenuFags: {
screen: MenuSecondScreen,
},
},
{
mode: 'card',
headerMode: 'none',
}
);
// Profile
const ProfileStackMain = StackNavigator(
{
FifthScreen: {
screen: FifthScreen,
},
Movies: {
screen: Movies,
},
},
{
initialRouteName: 'FifthScreen',
}
);
const ProfileStack = StackNavigator(
{
Main: {
screen: ProfileStackMain,
},
MenuFags: {
screen: MenuSecondScreen,
},
},
{
mode: 'card',
headerMode: 'none',
}
);
// Tabs
export default TabNavigator(
{
'Abcd\'s ef': { screen: WhatsupStack },
Ghij: { screen: FagsStack },
Klmn: { screen: TagsStack },
Settings: { screen: SettingsStack },
Profile: { screen: ProfileStack },
},
{
navigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, tintColor }) => {
const { routeName } = navigation.state;
let iconName;
if (routeName === 'Abcd\'s ef') {
//iconName = `ios-information-circle${focused ? '' : '-outline'}`;
//return <Icon name={focused ? 'globe' : 'globe'} size={22}
//style={{ color: focused ? '#ff0066' : 'black'}}/>;
return <IconOcticons name={'globe'} size={22} style={{ color: focused ? '#ff0066' : 'black'}}/>;
} else if (routeName === 'Ghij') {
//iconName = `ios-options${focused ? '' : '-outline'}`;
return <IconFontAwesome name={'users'} size={22} style={{ color: focused ? '#ff0066' : 'black'}}/>
} else if (routeName === 'Klmn') {
//iconName = `ios-options${focused ? '' : '-outline'}`;
return <IconFontAwesome name={'heart'} size={22} style={{ color: focused ? '#ff0066' : 'black'}}/>
} else if (routeName === 'Settings') {
//iconName = `ios-options${focused ? '' : '-outline'}`;
return <IconOcticons name={'gear'} size={22} style={{ color: focused ? '#ff0066' : 'black'}}/>
} else if (routeName === 'Profile') {
//iconName = `ios-options${focused ? '' : '-outline'}`;
return <IconFontAwesome name={'user'} size={22} style={{ color: focused ? '#ff0066' : 'black'}}/>
}
// 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: '#ff0066',
inactiveTintColor: 'gray',
showIcon: true,
upperCaseLabel: false,
},
//tabBarComponent: TabBarBottom,
//tabBarPosition: 'bottom',
animationEnabled: true,
swipeEnabled: true,
}
);
</code>
[1]: https://i.stack.imgur.com/0oVwG.png
[2]: https://i.stack.imgur.com/QQhN4.png
[3]: https://i.stack.imgur.com/oFeiG.png
use allowFontScaling:false in tabBarOptions , by adding this font size will not scale on the basis of devices fontSize.
tabBarOptions:{
allowFontScaling:false
}
Related
I'm trying to use React-slick with gatsby-plugin images and I have the page setup like this.
import React from "react";
import { graphql } from "gatsby"
import Slider from "react-slick";
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";
import { GatsbyImage } from "gatsby-plugin-image"
const settings = {
autoPlay: true,
arrows: false,
dots: true,
infinite: true,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1,
};
const ImgSlide = ({ data }) => {
return (
<div>
<Slider {...settings}>
<div>
<GatsbyImage fluid={data.image1.childImageSharp.fluid} />
</div>
<div>
<GatsbyImage fluid={data.image2.childImageSharp.fluid} />
</div>
</Slider>
</div>
);
};
export const pageQuery = graphql`
query {
image1: file(relativePath: { eq: "images/icon.png" }) {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
image2: file(relativePath: { eq: "images/icon.png" }) {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
}
`
export default ImgSlide;
When i run Gatsby develop I get an error saying image1 is not defined. I really don't know what I'm missing here. I think it has something to do with how I'm trying to define image1 but I'm pretty sure I've used relativePath properly unless I'm not specifying the location properly.
I do have the same image specified twice that is just because I have not imported the photos in just yet I'm just testing to make it work.
gatsby-config setup is
module.exports = {
siteMetadata: {
title: "Inkd Era",
description: "Clothing and brand built for tattoo and tattoed culture",
},
plugins: [
"gatsby-plugin-sass",
"gatsby-plugin-image",
"gatsby-plugin-react-helmet",
"gatsby-plugin-sitemap",
{
resolve: "gatsby-plugin-manifest",
options: {
icon: "src/images/icon.png",
},
},
"gatsby-transformer-remark",
"gatsby-plugin-sharp",
"gatsby-transformer-sharp",
{
resolve: "gatsby-transformer-remark",
options: {
plugins: [
{
resolve: "gatsby-remark-images",
options: {
maxWidth: 650,
},
},
],
},
},
{
resolve: "gatsby-source-filesystem",
options: {
name: "images",
path: `${__dirname}/src/images/`,
},
__key: "images",
},
{
resolve: "gatsby-source-filesystem",
options: {
name: "pages",
path: `${__dirname}/src/pages/`,
},
__key: "pages",
},
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `Inkd Era`,
short_name: `Inkd era`,
start_url: `/`,
background_color: `#000`,
theme_color: `#fafafa`,
display: `standalone`,
icon: `content/assets/gatsby-icon.png`,
},
},
],
};
The structure for the new <GatsbyImage> component when passing the image itself is using the image prop, not fluid. In addition, the query needs to fetch gatsbyImageData, not fluid as you can see in the docs:
import { graphql } from "gatsby"
import { GatsbyImage, getImage } from "gatsby-plugin-image"
function BlogPost({ data }) {
const image = getImage(data.blogPost.avatar)
return (
<section>
<h2>{data.blogPost.title}</h2>
<GatsbyImage image={image} alt={data.blogPost.author} />
<p>{data.blogPost.body}</p>
</section>
)
}
export const pageQuery = graphql`
query {
blogPost(id: { eq: $Id }) {
title
body
author
avatar {
childImageSharp {
gatsbyImageData(
width: 200
placeholder: BLURRED
formats: [AUTO, WEBP, AVIF]
)
}
}
}
}
`
In your scenario, you are mixing the gatsby-image approach, from Gatsby v2 with the new gatsby-plugin-image, which stills in beta, but it's from the v3.
If you want to use the <GatsbyImage>, adapt the query and the component to the needs, otherwise, use the gatsby-image properly like:
import Img from `gatsby-image`
<Img fluid={data.image1.childImageSharp.fluid} />
The component for route 'FilmDetail' must be a React Component
I'm trying to use react-navigation but I can't get it to work. I've tried removing brackets while importing and can still reproduce the error:
Navigaton.js
import React from 'react'
import { StyleSheet, Image } from 'react-native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs'
import { createStackNavigator } from 'react-navigation-stack'
import { createAppContainer } from 'react-navigation'
import Search from '../Components/Search'
import FilmDetail from '../Components/FilmDetail'
import Favorites from '../Components/Favorites'
const SearchStackNavigator = createStackNavigator({
Search: {
screen: Search,
navigationOptions: {
title: 'Rechercher'
}
},
FilmDetail: {
screen: FilmDetail
}
})
const MoviesTabNavigator = createBottomTabNavigator(
{
Search: {
screen: SearchStackNavigator,
navigationOptions: {
tabBarIcon: () => {
return <Image
source={require('../Images/ic_search.png')}
style={styles.icon}/>
}
}
},
Favorites: {
screen: Favorites,
navigationOptions: {
tabBarIcon: () => {
return <Image
source={require('../Images/ic_favorite.png')}
style={styles.icon}/>
}
}
}
},
{
tabBarOptions: {
activeBackgroundColor: '#DDDDDD',
inactiveBackgroundColor: '#FFFFFF',
showLabel: false,
showIcon: true
}
}
)
const styles = StyleSheet.create({
icon: {
width: 30,
height: 30
}
})
export default createAppContainer(MoviesTabNavigator)
App.js
import React from 'react'
import Navigation from './Navigation/Navigation'
import { Provider } from 'react-redux'
import Store from './Store/configureStore'
export default class App extends React.Component {
render() {
return (
<Provider store={Store}>
<Navigation/>
</Provider>
)
}
}
FilmDetail.js
import React from 'react'
import { StyleSheet, View, Text, ActivityIndicator, ScrollView, Image, Button ,TouchableOpacity} from 'react-native'
import {getImageFromApi} from '../API/TMDBApi'
import getFilmDetailFromApi from '../API/TMDBApi'
import moment from 'moment'
import numeral from 'numeral'
import { connect } from 'react-redux'
class FilmDetail extends React.Component {
constructor(props) {
super(props)
this.state = {
film: undefined,
isLoading: true
}
}
componentDidMount() {
getFilmDetailFromApi(this.props.navigation.state.params.idFilm).then(data => {
this.setState({
film: data,
isLoading: false
})
})
}
componentDidUpdate() {
console.log("componentDidUpdate : ")
console.log(this.props.favoritesFilm)
}
_displayLoading() {
if (this.state.isLoading) {
return (
<View style={styles.loading_container}>
<ActivityIndicator size='large' />
</View>
)
}
}
_toggleFavorite() {
const action = { type: "TOGGLE_FAVORITE", value: this.state.film }
this.props.dispatch(action)
}
_displayFavoriteImage() {
var sourceImage = require('../Images/ic_favorite_border.png')
if (this.props.favoritesFilm.findIndex(item => item.id === this.state.film.id) !== -1) {
// Film dans nos favoris
sourceImage = require('../Images/ic_favorite.png')
}
return (
<Image
style={styles.favorite_image}
source={sourceImage}
/>
)
}
_displayFilm() {
const { film } = this.state
if (film != undefined) {
return (
<ScrollView style={styles.scrollview_container}>
<Image
style={styles.image}
source={{uri: getImageFromApi(film.backdrop_path)}}
/>
<Text style={styles.title_text}>{film.title}</Text>
<TouchableOpacity style={styles.favorite_container} onPress={() => this._toggleFavorite()}>{this._displayFavoriteImage()}</TouchableOpacity>
<Text style={styles.description_text}>{film.overview}</Text>
<Text style={styles.default_text}>Sorti le {moment(new Date(film.release_date)).format('DD/MM/YYYY')}</Text>
<Text style={styles.default_text}>Note : {film.vote_average} / 10</Text>
<Text style={styles.default_text}>Nombre de votes : {film.vote_count}</Text>
<Text style={styles.default_text}>Budget : {numeral(film.budget).format('0,0[.]00 $')}</Text>
<Text style={styles.default_text}>Genre(s) : {film.genres.map(function(genre){
return genre.name;
}).join(" / ")}
</Text>
<Text style={styles.default_text}>Companie(s) : {film.production_companies.map(function(company){
return company.name;
}).join(" / ")}
</Text>
</ScrollView>
)
}
}
render() {
return (
<View style={styles.main_container}>
{this._displayLoading()}
{this._displayFilm()}
</View>
)
}
}
const styles = StyleSheet.create({
main_container: {
flex: 1
},
loading_container: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center'
},
scrollview_container: {
flex: 1
},
image: {
height: 169,
margin: 5
},
title_text: {
fontWeight: 'bold',
fontSize: 35,
flex: 1,
flexWrap: 'wrap',
marginLeft: 5,
marginRight: 5,
marginTop: 10,
marginBottom: 10,
color: '#000000',
textAlign: 'center'
},
description_text: {
fontStyle: 'italic',
color: '#666666',
margin: 5,
marginBottom: 15
},
default_text: {
marginLeft: 5,
marginRight: 5,
marginTop: 5,
},favorite_container: {
alignItems: 'center'
},favorite_image: {
width: 40,
height: 40
}
})
const mapStateToProps = (state) => {
return {
favoritesFilm: state.favoritesFilm
}
}
export default connect(mapStateToProps)(FilmDetail)
Your displayLoading and displayFilm functions need to return null. Currently they only return if the happy path is followed, but that can lead to weird stuff happening if they don't return null for the other paths where they shouldn't display themselves.
I'm not sure if that will fix your error or not, I am not seeing anything else sticking out to me, but I would implement that and see if your issue goes away.
If that doesn't work, try not using React-Navigation for a second and just import/render the FilmDetail component by itself to see if a different error comes up that may be the underlying issue.
If not let me know and I'll look again.
I fix it by changing my "react-navigation": "^1.6.1" to "react-navigation": "^4.3.9" and instead of using #react-navigation/bottom-tabs i tried using react-navigation-tabs
I've implemented https://reactnavigation.org/docs/en/auth-flow.html as described with a SwitchNavigator. However, my AuthScreen is never unmounted when I navigate to App.
I'm, using a SwitchNavigator, with in it a screen and a DrawerNavigator, as well as some StackNavigators. I've tried changing the structure of my navigators, but that doesn't seem to have any effect.
const AppStack = createDrawerNavigator(
{
StackA: {
name: 'someStackNavigator',
screen: someStackNavigator
},
},
{
...
});
const AppNavigator = createSwitchNavigator(
{
App: AppStack,
Auth: {
screen: AuthScreen
}
},
{
initialRouteName: 'App'
});
const AppContainer = createAppContainer(AppNavigator);
export default AppContainer;
How do I force the Auth screen in the SwitchNavigator to be unmounted if you navigate to a screen in the other stacks/drawers?
Like this?
import React, { Component } from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import {
createSwitchNavigator,
createStackNavigator,
createAppContainer,
createDrawerNavigator,
} from 'react-navigation';
class Screen extends Component {
render() {
return (
<View style={styles.container}>
<Text>Screen</Text>
</View>
);
}
}
class AuthScreen extends Component {
componentDidMount() {
console.log('componentDidMount');
}
componentWillUnmount() {
console.log('componentWillUnmount');
}
render() {
return (
<View style={styles.container}>
<Text>Auth Screen</Text>
<TouchableOpacity onPress={() => this.props.navigation.navigate('App')}>
<Text>Login</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
marginTop: 40,
justifyContent: 'center',
alignItems: 'center',
},
});
const SomeStackNavigator = createStackNavigator({
ScreenA: Screen,
ScreenB: Screen,
});
const AppStack = createDrawerNavigator({
StackA: {
name: 'StackA',
screen: SomeStackNavigator,
},
StackB: {
name: 'StackB',
screen: SomeStackNavigator,
},
});
const AppNavigator = createSwitchNavigator(
{
App: AppStack,
Auth: {
screen: AuthScreen,
},
},
{
initialRouteName: 'Auth',
},
);
const AppContainer = createAppContainer(AppNavigator);
export default AppContainer;
You can try it here. You can see in the console that AuthScreen is unmounted when the login button is clicked.
MainNavigator
const MainNavigator = StackNavigator(
{
Start:{ screen:Start },
Login:{ screen:Login },
mainFlow:{
screen: TabNavigator({
Profile: { screen: Profile },
List: { screen: List },
MenuStack: { screen: StackNavigator({
Menu: {screen: Menu},
OpenChannel: { screen: OpenChannel },
OpenChannelCreate: { screen: OpenChannelCreate },
Chat: { screen: Chat },
Member: { screen: Member },
BlockUser: { screen: BlockUser },
GroupChannel: { screen: GroupChannel },
GroupChannelInvite: { screen: GroupChannelInvite },
},{
initialRouteName: 'Menu',
headerMode: 'none',
})}
},{
initialRouteName: 'Profile'
})
}
},{
initialRouteName: 'Start',
}
);
How can I jump from Menu of mainFlow's menuStack to Login Screen of MainNavigator .
I've tried some ways like passing parents navigation to child navigation as params but I failed to pass navigation from tabNavigation to child StackNavigation...
I really need your help!
I am a student studying vue.
I used Vue-chartjs to draw a graph, and I'd like to display the value on a pie graph.
But I don't know what to do.
Please help me...
the current situation (image) : enter image description here
My wish (image) : enter image description here
Vue.component('pie-chart', {
extends : VueChartJs.Pie,
props: ['data', 'options'],
mounted(){
this.renderPieChart();
},
computed: {
attendanceData : function(){
return this.data
}
},
methods : {
renderPieChart : function(){
this.renderChart(
{
labels: ['a','b','c','d'],
datasets: [{
backgroundColor: ['#10a236', '#f9cd41', '#fe7272', '#5c7add'],
data: [10,20,30,40]
}]
},
{
responsive: true,
maintainAspectRatio: false,
pieceLabel: {
render: 'value',
precision: 1,
}
}
)
}
},
watch : {
attendanceData : function(){
this.$data._chart.destroy();
this.renderPieChart();
}
}
});
As The dicusstion on tooltip of chart.js at Stackoverflow, uses plugin is one solution.
then as Vue chart.js guide said,
in mounted(), uses this.addPlugin to add your plugin like below demo:
Vue.config.productionTip = false
//below plugin is copied from https://stackoverflow.com/a/37989832/5665870
let pluginConfig = {
id: 'my-plugin',
beforeRender: function (chart) {
if (chart.config.options.showAllTooltips) {
// create an array of tooltips
// we can't use the chart tooltip because there is only one tooltip per chart
chart.pluginTooltips = [];
chart.config.data.datasets.forEach(function (dataset, i) {
chart.getDatasetMeta(i).data.forEach(function (sector, j) {
chart.pluginTooltips.push(new Chart.Tooltip({
_chart: chart.chart,
_chartInstance: chart,
_data: chart.data,
_options: chart.options.tooltips,
_active: [sector]
}, chart));
});
});
// turn off normal tooltips
chart.options.tooltips.enabled = false;
}
},
afterDraw: function (chart, easing) {
if (chart.config.options.showAllTooltips) {
// we don't want the permanent tooltips to animate, so don't do anything till the animation runs atleast once
if (!chart.allTooltipsOnce) {
if (easing !== 1)
return;
chart.allTooltipsOnce = true;
}
// turn on tooltips
chart.options.tooltips.enabled = true;
Chart.helpers.each(chart.pluginTooltips, function (tooltip) {
tooltip.initialize();
tooltip.update();
// we don't actually need this since we are not animating tooltips
tooltip.pivot();
tooltip.transition(easing).draw();
});
chart.options.tooltips.enabled = false;
}
}
}
Vue.component('pie-chart', {
extends : VueChartJs.Pie,
props: ['data', 'options'],
mounted(){
this.addPlugin(pluginConfig);
this.renderPieChart();
},
computed: {
attendanceData : function(){
return this.data
}
},
methods : {
renderPieChart : function(){
this.renderChart(
{
labels: ['a','b','c','d'],
datasets: [{
backgroundColor: ['#10a236', '#f9cd41', '#fe7272', '#5c7add'],
data: [10,20,30,40]
}]
},
{
responsive: true,
maintainAspectRatio: false,
pieceLabel: {
render: 'value',
precision: 1
},
showAllTooltips: true
}
)
}
},
watch : {
attendanceData : function(){
//this.$data._chart.destroy();
//this.renderPieChart();
}
}
})
var vm = new Vue({
el: '#app',
data: {
message: 'Hello World'
}
})
<script src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js"></script>
<script src="https://unpkg.com/vue-chartjs/dist/vue-chartjs.min.js"></script>
<div id="app">
<pie-chart></pie-chart>
</div>