I am trying to place a floating action button in the lower right corner of my app but it is placing it in the top left way off screen.
Returned view:
<View>
<View style={{flexDirection: 'row'}}>
<TouchableOpacity onPress={this.onPress} activeOpacity={.5} >
<Image
source={require('./assets/images/hamburger.png')}
style={{ width: 30, height: 25, marginLeft: 15}}
/>
</TouchableOpacity>
</View>
<FloatingAction style={styles.bottom}/>
</View>
Styles:
const styles = StyleSheet.create({
bottom: {
flex: 1,
position: 'absolute',
bottom: 10,
right:10
},
});
My current view displays a header and a bottom tab view. I am able to place multiple FAB's in each tab screen but that produces an undesirable behavior. Thank you for any help.
Edit:
What I have:
What I want:
Your issue was on adding { flex: 1, position: 'absolute',} to the button style together. The parent component that covers all the phone screen would use flex: 1, your button component is the one that receives the style for the position.
Always creating a new component makes stuff easier to read and understand. So let's say you have a button component (<FloatingButton/>), you would do something like this:
import React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import FloatingButton from './FloatingButton';
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<Text>
I'm just a Text
</Text>
<FloatingButton
style={styles.floatinBtn}
onPress={() => alert(`I'm being clicked!`)}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
floatinBtn: {
position: 'absolute',
bottom: 10,
right: 10,
}
});
You will get this result:
This is the button component:
import React from 'react';
import { View, TouchableOpacity } from 'react-native';
export default props => (
<TouchableOpacity onPress={props.onPress} style={props.style}>
<View
style={{
backgroundColor: 'blue',
width: 45,
height: 45,
borderRadius: 45,
}}
/>
</TouchableOpacity>
);
Check the snack demo: https://snack.expo.io/#abranhe/floating-btn
// this should occupy the whole screen
<View style={{flex:1}}>
<View style={{flexDirection: 'row'}}>
<TouchableOpacity onPress={this.onPress} activeOpacity={.5} >
<Image
source={require('./assets/images/hamburger.png')}
style={{ width: 30, height: 25, marginLeft: 15}}
/>
</TouchableOpacity>
</View>
<FloatingAction style={styles.bottom}/>
</View>
const styles = StyleSheet.create({
bottom: {
position: 'absolute',
bottom: 10,
right:10
},
});
Just use that CSS in your code:
.floating-btn {
position:fixed;
bottom:10;
right: 10;
}
That's it
Related
I am trying to get my ScrollView to scroll down so I can see all my views but it keeps bouncing back up to the top.
What it looks like
The White panels below Physiological Classification are in the ScrollView and are supposed to scroll but it just bounces back to the top.
Here is where my ScrollView is
_renderContent = (section) => {
section.arrow = !(section.arrow);
return (
<ScrollView>
<QuestionPanels
Questions={section.Questions}
pickerDefaultValues={section.pickerDefaultValues}
pickerItemNames={section.pickerItemNames}
/>
</ScrollView>
);
};
Question Panels is just a component that generates Views based on a json file. If relevant here is the code for that as well.
import React, { Component, useState, setState} from 'react';
import { ScrollView, View, Text } from 'react-native'
import styles from '../../Styles/GeneralStyles';
import Picker from '../Picker/Picker'
import appData from '../../DataSheet/appData.json';
const Panel = (props) => {
return (
<View style={styles.dropDownCardPanel}>
<View style={styles.QuestionPanel}>
<Text style={styles.QuestionText}>{props.Question}</Text>
</View>
<View style={styles.AnswerPanel}>
<Picker
defaultVal= {props.pickerDefaultValues}
showButton={false}
pickerItemNames={props.pickerItemNames}
/>
</View>
</View>
);
}
export default class QuestionairePanels extends Component {
constructor(props){
super(props)
}
render() {
var panelList = [];
for(let i = 0; i < this.props.Questions.length; i++){
panelList.push(
<Panel
key={i}
Question={this.props.Questions[i]}
pickerDefaultValues ={this.props.pickerDefaultValues[i]}
pickerItemNames = {this.props.pickerItemNames[i]}
/>
);
}
return(
<View>
{panelList}
</View>
);
}
}
Here are the styles that matter for this
dropDownCardPanel: {
height: 200,
flexDirection: "row",
backgroundColor: '#faf2f2',
paddingTop: 5,
paddingBottom: 5,
borderBottomWidth: 1,
borderColor: 'black',
},
dropDownCardPanelText: {
fontSize: 15,
color: "black",
marginLeft: 10
},
icon: {
left: 20,
},
QuestionPanel: {
height: "100%",
width: "60%",
borderRightWidth: 1,
borderColor: 'black',
left: 3,
marginRight: 5,
alignItems: "center",
justifyContent:'center'
},
QuestionText: {
fontSize: 20,
},
AnswerPanel: {
height: "100%",
width: "40%",
right: 3
}
The reason why I was not able to scroll was that the tag needs a specific height for it to render for a scroll. So to fix this I had to put a view around the and set it to a specific height.
Corrected Code
section.arrow = !(section.arrow);
var scrollHeight = (section.Questions.length > 2) ? 600 : 400;
var headerDisplay = (section.name.match("Physiologic")) ? section.name + " Variables" : "Select Dominant Final Diagnosis";
return (
<View style={{height: scrollHeight}}>
<ScrollView>
<View style={styles.dropDownCardPanelHeader}>
<Text style={styles.dropDownCardPanelHeaderText}>
{headerDisplay}
</Text>
</View>
<QuestionPanels
Questions={section.Questions}
pickerItemNames={section.pickerItemNames}
/>
</ScrollView>
</View>
Later I will try to use Flex to set the height so the react native project can scale to all screens but so far it works for iOS
I am making a react native app and for some reason when I tap on the text input to type something it disappears under the keyboard. I want it to come to the top of the keyboard like the way Instagram messenger and other messenger apps do it. I tried using keyboardAvoidView and setting the behavior to padding and height but none of it worked.
import {
View,
Text,
StyleSheet,
SafeAreaView,
TextInput,
TouchableOpacity,
} from "react-native";
import CommunityPost from "../components/CommunityPost";
import { Context as CommunityContext } from "../context/CommunityContext";
const Key = ({ navigation }) => {
const { createCommunityPost, errorMessage } = useContext(CommunityContext);
const [body, setBody] = useState("");
return (
<View style={styles.container}>
<SafeAreaView />
<CommunityPost />
<View style={styles.inputContainer}>
<TextInput
style={styles.input}
multiline={true}
placeholder="Type..."
placeholderTextColor="#CACACA"
value={body}
onChangeText={setBody}
/>
<TouchableOpacity
style={{ justifyContent: "center", flex: 1, flexDirection: "row" }}
onPress={() => createCommunityPost({ body })}
>
<Text style={styles.sendText}>Send</Text>
</TouchableOpacity>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "flex-start",
backgroundColor: "#2B3654",
justifyContent: "flex-end",
},
inputContainer: {
justifyContent: "flex-end",
flexDirection: "row",
},
sendText: {
color: "white",
fontSize: 25,
},
input: {
fontSize: 25,
color: "white",
borderColor: "#2882D8",
borderWidth: 1,
borderRadius: 15,
width: "80%",
marginBottom: 30,
marginLeft: 10,
padding: 10,
},
});
export default Key;
You must KeyboardAvoidingView component provided by react native.
<KeyboardAvoidingView
behavior={Platform.OS == "ios" ? "padding" : "height"}
style={styles.container}
>
<SafeAreaView />
<CommunityPost />
<View style={styles.inputContainer}>
<TextInput
style={styles.input}
multiline={true}
placeholder="Type..."
placeholderTextColor="#CACACA"
value={body}
onChangeText={setBody}
/>
<TouchableOpacity
style={{ justifyContent: "center", flex: 1, flexDirection: "row" }}
onPress={() => createCommunityPost({ body })}
>
<Text style={styles.sendText}>Send</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
For these situations we can use one of these methods:
1.wrapping Component with <ScrollView></ScrollView>
2.wrapping Component with <KeyboardAvoidingView></KeyboardAvoidingView>
Sometimes our wrong given styles can make these happens too such as : Having a fixed value for our styles, check your margins and use one of the given methods
I hope it helps
Try using keyboardVerticalOffset and test it with different values.
For more info check this out
For those who want to keep the code clean, just use the FlatList component and add a View component involving the component with the states: {flex: 1, height: Dimensions.get ("window"). Height}.
Below left a component ready for anyone who wants to use, just wrap your component in this way:
<FormLayout>
{... your component}
</FormLayout>
Here is the solver component:
import React from 'react'
import { View, StyleSheet, FlatList, Dimensions } from 'react-native'
import Background from './Background'
const FormLayout = ({ children }) => {
const renderContent = <View style={styles.container}>
{children}
</View>
return <FlatList
ListHeaderComponent={renderContent}
showsVerticalScrollIndicator={false}
/>
}
const styles = StyleSheet.create({
container: {
flex: 1,
height: Dimensions.get('window').height * 0.95
}
})
export default FormLayout
I have a TextInput that when pressed gets covered by the keyboard. So I wrapped it in a KeyboardAvoidingView. But regardless of the behavior that I set for this view, the TextInput won't move above the keyboard. Using position as the behavior moves the TextInput but only half way above the keyboard, while the other two don't seem to work at all.
I also tried wrapping my entire component with a KeyboardAvoidingView, but doing so breaks the entire layout.
Can anyone help me? I never managed to get KeyboardAvoidingView to work for me and now I really need it. Thanks in advance!
Here is my component. Also worth mentioning is that this component is top level(well, almost top level since it's wrapped in a Router)
const { height, width } = Dimensions.get('screen')
const style = StyleSheet.create({
main: {
height,
width,
flexDirection: 'column',
},
iconSelecter: {
width,
height: 196,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: Colors.primary,
marginTop: 32
},
icon: {
height: 164,
width: 164,
},
saveButton: {
width: 96,
height: 96,
borderRadius: 100,
backgroundColor: Colors.secondary,
alignItems: "center",
justifyContent: "center",
alignSelf: 'center',
position: 'absolute',
bottom: 96 + 32
},
saveIcon: {
height: 54,
width: 54,
},
textInputWrapper: {
borderBottomColor: Colors.textInputBorder,
width: 288,
borderBottomWidth: 1,
alignSelf: 'center',
marginTop: 96,
height: 48,
},
textInput: {
fontWeight: "300",
fontSize: 14,
margin: 0
},
hintWrapper: {
alignSelf: 'center',
marginTop: 4
},
hint: {
fontSize: 12,
fontFamily: "Roboto-Thin",
fontStyle: 'normal',
}
})
const CreateActivity = ({ goBack }: NavigationProps) => {
//////////////////////////////
//State and logic
///////////////
return (
// TODO: Add touchable opacity to dismiss keyboard
<View style={style.main}>
<Appbar title="New activity" canGoBack goBack={goBack} />
<View style={{ flex: 1 }}>
<View style={style.iconSelecter}>
<GestureRecognizer onSwipeLeft={nextIcon} onSwipeRight={lastIcon}>
<Image style={style.icon} source={icons[currentIconIndex]?.file}></Image>
</GestureRecognizer>
</View>
<View style={style.hintWrapper}>
<Text style={style.hint}>Swipe to cycle through the icons</Text>
</View>
<KeyboardAvoidingView>
<View style={style.textInputWrapper}>
<TextInput style={style.textInput} placeholder={"Give this activity a name"} value={name} onChangeText={setName}></TextInput>
</View>
</KeyboardAvoidingView>
<TouchableNativeFeedback onPress={createActivity} background={TouchableNativeFeedback.Ripple("#fff", true)}>
<View style={style.saveButton}>
<Image style={style.saveIcon} source={require("../../assets/icons/light/save.png")}></Image>
</View>
</TouchableNativeFeedback>
</View>
</View>
)
}
export default CreateActivity;
I suggest that you to try wrap all the content of the screen in <KeyboardAvoidingView /> (or make it one of the outermost elements), otherwise it only will slide up its children (the View and the TextInput) leaving the rest of the content in its original position, making the layout look overlaped and weird. If you do that, the value "position" should work fine.
Something like this:
<View style={style.main}>
<Appbar title="New activity" canGoBack goBack={goBack} />
<KeyboardAvoidingView behavior="position" >
<View style={{ flex: 1 }}> // --> Remove flex: 1 if you experience some issue with the positioning
<View style={style.iconSelecter}>
<GestureRecognizer onSwipeLeft={nextIcon} onSwipeRight={lastIcon}>
<Image style={style.icon} source={icons[currentIconIndex]?.file}></Image>
</GestureRecognizer>
</View>
<View style={style.hintWrapper}>
<Text style={style.hint}>Swipe to cycle through the icons</Text>
</View>
<KeyboardAvoidingView>
<View style={style.textInputWrapper}>
<TextInput style={style.textInput} placeholder={"Give this activity a name"} value={name} onChangeText={setName}></TextInput>
</View>
</KeyboardAvoidingView>
<TouchableNativeFeedback onPress={createActivity} background={TouchableNativeFeedback.Ripple("#fff", true)}>
<View style={style.saveButton}>
<Image style={style.saveIcon} source={require("../../assets/icons/light/save.png")}></Image>
</View>
</TouchableNativeFeedback>
</View>
</KeyboardAvoidingView>
</View>
Also see the comment in the code above. Check if you really need to use of flex: 1 in all the outer wrapper elements, and take a look to the height you are setting in the style.main based on dimentions. I don't think that it is necesary and I think it could lead to some measure issues if you fix the height of the parent container.
EDIT:
I was just digging in react-native docs and I realize that there is a zIndex that you could use to avoid ablsolute positioning. It is a relative style prop so it needs to be set between sibling views, like this:
export default class MyComponent extends React.Component {
render() {
return (
<View>
<View style={[styles.appbarShape, styles.appbarZIndex]} ><Text>Header</Text></View>
<KeyboardAvoidingView behavior="position" style={styles.contentZIndex}>
{other children}
<TextInput placeholder="enter text"/>
</KeyboardAvoidingView>
</View>
);
}
}
const styles = StyleSheet.create({
appbarShape: {
height: 80,
width: Dimensions.get('window').width,
justifyContent: 'center',
alignSelf: "stretch",
backgroundColor: "#FFF"
},
appbarZIndex: {
zIndex: 3,
},
contentZIndex: {
zIndex: 0
}
});
Since the view that represents the appbar has a greater zIndex it shows up over the ones with a lower zIndex
Check this out working in this snack https://snack.expo.io/5VXAcw4Y0
Docs: https://reactnative.dev/docs/layout-props
Hope it helps!
Use react-native-keyboard-aware-scroll-view
<KeyboardAwareScrollView extraHeight={135} enabledOnAndroid={true}
extraScrollHeight={70} style={styles.mainContainer}
automaticallyAdjustContentInsets={true}
enableOnAndroid={true}
keyboardShouldPersistTaps='handled'
scrollEnabled={true} >
//your form
</KeyboardAwareScrollView>
const styles = StyleSheet.create({
mainContainer: { flex: 1, marginHorizontal: 15, marginVertical: 15 },
});
Day 1 with React-Native . Trying to load multiple images in a React-Native app. However, the app crashes with the error:
Error: The component cannot contain children. If you want to
render content on top of the image, consider using the
<ImageBackground> component or absolute positioning.
I tried solutions to these existing questions, however they failed to resolve my issue:
How to use ImageBackground to set background image for screen in react-native.
Tile component issues with latest react 0.50.0 #709
Also tried replacing <ImageBackground> with <Image>, however that did not resolve the issue as well.
Here's the code to my App.js :
import React, { Component } from 'react';
import {
StyleSheet,
View,
Image
} from 'react-native';
const playIcon = require('./images/play.png');
const volumeIcon = require('./images/sound.png');
const hdIcon = require('./images/hd-sign.png');
const fullScreenIcon = require('./images/full-screen.png');
const remoteImage = { uri:'https://s3.amazonaws.com/crysfel/public/book/new-york.jpg' };
export default class App extends Component<{}> {
render() {
return (
<Image source={remoteImage} style={styles.fullscreen}>
<View style={styles.container}>
<Image source={playIcon} style={styles.icon} />
<Image source={volumeIcon} style={styles.icon} />
<View style={styles.progress}>
<View style={styles.progressBar} />
</View>
<Image source={hdIcon} style={styles.icon} />
<Image source={fullScreenIcon} style={styles.icon} />
</View>
</Image>
);
}
}
const styles = StyleSheet.create({
fullscreen: {
flex: 1,
},
container: {
position: 'absolute',
backgroundColor: '#202020',
borderRadius: 5,
flexDirection: 'row',
height: 50,
padding: 5,
paddingTop: 16,
bottom: 30,
right: 10,
left: 10,
borderWidth: 1,
borderColor: '#303030',
},
icon: {
tintColor: '#fff',
height: 16,
width: 16,
marginLeft: 5,
marginRight: 5,
},
progress: {
backgroundColor: '#000',
borderRadius: 7,
flex: 1,
height: 14,
margin: 10,
marginTop: 2,
},
progressBar: {
backgroundColor: '#bf161c',
borderRadius: 5,
height: 10,
margin: 2,
width: 80,
},
});
What is possibly causing this issue and how to resolve it?
<Image> with nested content is no longer supported. Use <ImageBackground> instead.
<View style={styles}>
<ImageBackground style={styles} source={source} resizeMode={resizeMode} >
{children}
</ImageBackground>
{...}
</View>
Also you need to add a parent component (View) to wrap all your components.
It's not work because you must wrap all your components with parent View.
Image cannot be the parent view.
something like this:
render() {
return (
<View>
<Image source={remoteImage} style={styles.fullscreen}>
<View style={styles.container}>
<Image source={playIcon} style={styles.icon} />
<Image source={volumeIcon} style={styles.icon} />
<View style={styles.progress}>
<View style={styles.progressBar} />
</View>
<Image source={hdIcon} style={styles.icon} />
<Image source={fullScreenIcon} style={styles.icon} />
</View>
</Image>
</View>
);
}
I've been dabbling with some react native code and found that my view does not have a right boundary in both android and iOS renders. So when I add a horizontal margin, the view displays margin only on the left like this.
I am also attaching my code and styles to guide me on where I would have gone wrong.
Login.js
import React,{Component} from 'react';
import {View,ToolbarAndroid,Text, Image, StatusBar,TextInput, TouchableOpacity} from 'react-native';
import styles from './styles.js'
class LogIn extends Component {
constructor(props) {
super(props)
this.state = {hostName: '', userName: '', password: ''}
}
onButtonPress() {
this.props.onSubmit && this.props.onSubmit(this.state);
}
render() {
return(
<Image style={styles.container} source={images.background}>
<StatusBar backgroundColor="#00EF6C00" translucent={true}/>
<View style={styles.logocontainer}>
<FitImage source={images.logo} resizeMode="contain" resizeMethod="scale" style= {{width: 300,position: 'absolute', left: 50, height: 100}}/>
</View>
<View style={styles.comp_container}>
<TextInput placeholder="Host Name" style={{height: 40}} onChangeText={(text) => this.setState({hostName: text})}/>
<TextInput placeholder="User Name" style={{height: 40}} onChangeText={(text) => this.setState({userName: text})}/>
<TextInput placeholder="Password" style={{height: 40}} onChangeText={(text) => this.setState({password: text})}/>
<TouchableOpacity onPress={this.onButtonPress.bind(this)} style={{height: 40, flex: 1, flexDirection: 'row'}}>
<Text style={{flex: 1}}> Submit </Text>
</TouchableOpacity>
</View>
</Image>
)
}
}
LogIn.propTypes = {
onSubmit: React.PropTypes.func,
}
export default LogIn;
Also Please find the attached stylesheet for further information on style
import { StyleSheet } from 'react-native'
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column'
},
toolbar: {
backgroundColor: '#EF6C00',
height: 56,
elevation: 3,
},
textInput: {
borderRadius: 20,
borderColor: "#FFFFFF",
height: 40,
},
button: {
height: 40,
},
logocontainer: {
flex: 1,
flexDirection: 'column',
alignItems: 'stretch',
justifyContent: 'center',
},
comp_container: {
flex: 2,
flexDirection: 'column',
justifyContent: 'center',
marginHorizontal: 16,
}
});
export default styles
Edit: It is almost palpable that the problem should be with react-native unable to decide where the view boundary is. So instead of wrapping within the view, it decides to extent it. I also would love to get to know of any tools which can help me debug the UI issues, like the uiautomationviewer for android.
You do not specify width nor resizeMode in background image so it overflows screen. By default alignItems is stretch, TouchableOpacity fills container on horizontal and also overflows screen.