React Native Not Responding to Touch on Android Only - android

I am trying to update a Flatlist to present as seen in this video:
https://www.youtube.com/watch?v=6XxpUhQqpjY
My elements include touchable components such as TextInput and Buttons.
This works perfectly in iOS. However, on Android, the Flatlist scrolls using the FlingGesture, but none of the touchable components responds to touch. When I tap on a TextInput the keyboard is not invoked.
I'm using NativeBase and React Navigation if that's helpful.
<Content>
<FlingGestureHandler key='up'
direction={Directions.UP}
onHandlerStateChange={ev => { if (ev.nativeEvent.state === State.END) {
//setActiveIndex()
if (activeIndex === data.length -1) {
return
}
setActiveIndex(activeIndex + 1)
}
}}
>
<FlingGestureHandler
key='down'
direction={Directions.DOWN}
onHandlerStateChange={ev => {if (ev.nativeEvent.state === State.END) {
//setActiveIndex()
if (activeIndex === 0) {
return
}
setActiveIndex(activeIndex - 1)
}
}}
>
<FlatList
scrollEnabled={false}
removeClippedSubviews={false}
refreshControl={<RefreshControl refreshing={games.loadingGames}
onRefresh={onRefresh} />}
contentContainerStyle={{
flex: 5,
justifyContent: 'flex-start',
padding: SPACING * 2
}}
style={{minHeight: Dimensions.get('screen').height-240}}
data={games.sort((a,b) => {
return (b.status === a.status) ? new Date(a.startDateTime) - new Date(b.startDateTime) : new Date(b.startDateTime) - new Date(a.startDateTime)
})}
CellRendererComponent={({item, index, children, style, ...props}) => {
// console.log(`props`, props)
const newStyle = [
style,
{ zIndex: games.length - index }
]
return (
<View style={newStyle} index={index} {...props}>
{children}
</View>
)
}}
keyExtractor={(item) => item.gameId.toString()}
renderItem={({item, index}) => {
const inputRange = [index -1, index, index + 1]
const translateY = scrollXAnimated.interpolate({
inputRange,
outputRange: [50, 0, -100]
})
const scale = scrollXAnimated.interpolate({
inputRange,
outputRange: [.8, 1, 1.3]
})
const opacity = scrollXAnimated.interpolate({
inputRange,
outputRange: [1 - 1/VISIBLE_ITEMS, 1, 0]
})
const game = item
return index >= activeIndex && index < activeIndex+2 && (
<GameItem
style={{
minHeight: ITEM_HEIGHT,
minWidth: ITEM_WIDTH,
opacity,
transform: [
{
translateY,
},
{ scale },
],
}}
onLayout={getItemDimensions}
game={game}
selectGame={selectGame}
onChangeText={onChangeScore}
onChangeStars={onChangeStars}
onSubmit={submitPrediction} />
)
}}
/>
</FlingGestureHandler>
</FlingGestureHandler>
</Content>
I have tried a lot of different solutions but cannot seem to resolve the issue.

If you are using android you should import GestureHandlerRootView from react-native-gesture-handler and wrap your component that contained FlingGestureHandler with it. Something like this :
return(<GestureHandlerRootView style={{flex:1}}>
<FlingGestureHandler key='up'
direction={Directions.UP}
onHandlerStateChange={ev => { if (ev.nativeEvent.state === State.END) {
//setActiveIndex()
if (activeIndex === data.length -1) {
return
}
setActiveIndex(activeIndex + 1)
}
}}
....rest of your code
</GestureHandlerRootView>);

Related

react-native-nfc-manager stops working after I use expo-barcode-scanner

I have a small problem using the nfc plugin react-native-nfc-manager and expo-barcode-scanner on android 12.
I have multiple inputs which users can fill by either scanning a barcode with the camera or using an nfc tag.
On its own both functions work perfectly.
But if I scan an barcode/qrcode with the camera my nfc tags don't work anymore until I restart the app.
useEffect(() => {
nfcScann();
}, []);
useEffect(() => {
NfcManager.setEventListener(NfcEvents.DiscoverTag, (tag) => {
if (benutzerRef.current.isFocused()) {
onChangeBenutzer(Ndef.text.decodePayload(tag.ndefMessage[0].payload));
vorgangRef.current.focus();
} else if (etc...
NfcManager.setEventListener(NfcEvents.DiscoverBackgroundTag, (tag) => {
if (benutzerRef.current.isFocused()) {
onChangeBenutzer(Ndef.text.decodePayload(tag.ndefMessage[0].payload));
vorgangRef.current.focus();
} else if (etc...
}, [NfcManager]);
const nfcScann = () => {
NfcManager.isSupported().then((supported) => {
if (supported) {
NfcManager.start();
NfcManager.registerTagEvent();
} else {
Alert.alert("", "NFC not supported");
}
});
};
Thats how I implemented my nfc scan.
useEffect(() => {
if (isLoading) {
askForCameraPermission();
getData();
setLoading(false);
}
}, []);
const askForCameraPermission = () => {
(async () => {
const { status } = await BarCodeScanner.requestPermissionsAsync();
setHasPermission(status == "granted");
})();
};
const handleBarCodeScanned = ({ type, data }) => {
setScanned(true);
setCamera(false);
switch (isInput) {
case //Chosing which input gets the data
default:
Alert.alert(
"Fehler",
"Fehler beim schreiben der gescannten Daten. Bitte versuchen Sie es erneut."
);
break;
}
};
{isCamera && (
<View
style={{
height: "100%",
backgroundColor: "#000000",
}}
>
<View
style={{
alignItems: "flex-end",
position: "absolute",
top: 0,
right: 0,
zIndex: 1,
}}
>
<TouchableOpacity
onPress={() => {
setCamera(false);
}}
style={{
width: 50,
height: 50,
justifyContent: "center",
alignItems: "center",
padding: 2,
borderRadius: 100,
backgroundColor: "rgb(0,0,0,0)",
marginRight: 10,
}}
>
<Icon
name="close-circle-outline"
size={40}
type="material-community"
color="white"
/>
</TouchableOpacity>
</View>
<BarCodeScanner
onBarCodeScanned={handleBarCodeScanned}
style={StyleSheet.absoluteFillObject}
></BarCodeScanner>
</View>
)}
And thas how I implemented the barcodescanner. In the end I only start and stop the scanner by setting isCamera true or false.
Sadly after I used it once my nfc stops working and only on android 12.
I suspect that the camera is either still active somehow or nfc does not get turned back on after I used the camera.
Can anyone help me solve this problem?

React native F2 chart does not show up on android

Does anyone knows why it does not show up on android? it works perfectly fine on iOS. I'm using this lib btw https://github.com/aloneszjl/react-native-f2chart. In example, it seems to work with both iOS and android, but I can't get it to work on android. Any help would be appreciated
const HomeTab = () => {
const data = [
{
date: '2017-06-05',
value: 116,
},
{
date: '2017-06-06',
value: 129,
},
{
date: '2017-06-07',
value: 135,
},
];
const initScript = data => `
(function(){
chart = new F2.Chart({
id: 'chart',
pixelRatio: window.devicePixelRatio,
});
chart.source(${JSON.stringify(data)}, {
value: {
tickCount: 5,
min: 0
},
date: {
type: 'timeCat',
range: [0, 1],
tickCount: 3
}
});
chart.tooltip({
custom: true,
showXTip: true,
showYTip: true,
snap: true,
crosshairsType: 'xy',
crosshairsStyle: {
lineDash: [2]
}
});
chart.axis('date', {
label: function label(text, index, total) {
var textCfg = {};
if (index === 0) {
textCfg.textAlign = 'left';
} else if (index === total - 1) {
textCfg.textAlign = 'right';
}
return textCfg;
}
});
chart.line().position('date*value');
chart.render();
})();
`;
return(
<View style={{ height: 200, width: 400}}>
<Chart
style={{flex: 1, width: 400}}
initScript={initScript(data)}
/>
</View>
)
}

React Native FlatList scrollToBottom not working

Greeting everyone,
I am working on react-native FlatList and my problem is that I am unable to scroll to bottom. Here is my FlatList code:
<FlatList style = { styles.list }
ref="flatList1"
data = {
this.state.conversation_arr
}
onContentSizeChange={(contentWidth, contentHeight) => {
this.flat_list_height = contentHeight;
// this.scrollNow();
}}
onLayout={this.scrollNow()}
renderItem = { this._renderItem }
keyExtractor = { item => item.message_id }
/>
scrollNow() {
console.log("******",this.refs);
if(this.refs.flatList1){
this.refs.flatList1.scrollToEnd();
}
}
When the code reaches to
this.refs.flatList1.scrollToEnd();
Error appears on the screen saying
Type Error, cannot read property -1 of undefined.
here is the screenshot.
cannot read property -1 of undefined
I am basically trying to implement chat feature for my application, and therefor i need to scroll to bottom of the list once chat is loaded.
Any kind of help is appreciated.
Thanks
COMPLETE CODE
import React, {
Component
} from 'react';
import {
StyleSheet,
View,
Text,
TextInput,
ActivityIndicator,
TouchableOpacity,
FlatList,
} from 'react-native';
export default class Conversation extends Component {
state = {
conversation_arr: undefined,
last_message_loaded: false,
show_activty_indicator: true,
message_text : undefined,
message_text_length : 0
};
params = this.props.navigation.state;
last_evaluated_key = {
message_id: undefined,
timestamp: undefined
}
conversation = undefined;
thread_info = undefined;
flat_list_height = 0;
static navigationOptions = ({ navigation }) => ({
title: navigation.state.params.header_title,
});
constructor(props) {
super(props);
this._renderItem = this._renderItem.bind(this);
this._fetchConversation();
this.scrollNow = this.scrollNow.bind(this);
this.handleInputTextContent = this.handleInputTextContent.bind(this);
this.sendMessage = this.sendMessage.bind(this);
console.disableYellowBox = true;
this.thread_info = this.params.params.thread_info;
}
// scrollNow() {
// console.log("******",this.refs);
// if(this.refs.flatList1){
// // debugger;
// this.refs.flatList1.scrollToEnd();
// }
// console.log("******", this.flatlist1);
// if(this.flatlist1){
// this.flatlist1.scrollToEnd();
// }
// console.log("###", this.flat_list_height);
// }
scrollNow = () => {
console.log("******", this.flatList1);
if(this.state.conversation_arr && this.state.conversation_arr.length > 0 && this.flatList1){
// debugger;
// setTimeout(() => {
// console.log("timer over now");
this.flatList1.scrollToEnd();
// }, 1000)
// this.flatList1.scrollToEnd();
console.log("Scrolling now at length", this.state.conversation_arr.length);
}
// !!this.refs["myFlatList"] && this.refs["myFlatList"].scrollToEnd()
}
componentDidUpdate(){
console.log("componentDidUpdatecomponentDidUpdate")
}
componentWillUnmount(){
console.log("componentWillUnmountv")
}
render() {
return (
<View style={ styles.container }>
{
this.state.show_activty_indicator &&
<View style={[styles.activity_indicator_container]}>
<ActivityIndicator
animating = { this.state.show_activty_indicator }
size="large"
color="#444444"
/>
</View>
}
<FlatList style = { styles.list }
// inverted
// ref="myFlatList"
// ref={(ref) => this.flatList1 = ref}
ref={(ref) => { this.flatList1 = ref; }}
data = {
this.state.conversation_arr
}
onContentSizeChange={(contentWidth, contentHeight) => {
this.flat_list_height = contentHeight;
// this.scrollNow();
}}
onLayout={this.scrollNow}
renderItem = { this._renderItem }
keyExtractor = { item => item.message_id }
/>
<View style={ styles.bottom_box }>
<Text style={ styles.message_length }> {this.state.message_text_length}/160 </Text>
<View style={ styles.message_box }>
<View style={{flex: 3}} >
<TextInput
style={styles.input_text}
value={this.state.message_text}
onChangeText={this.handleInputTextContent}
placeholder='Type a message here...'
underlineColorAndroid='transparent'
/>
</View>
<View style={{flex: 1}} >
<TouchableOpacity
style={styles.send_button}
onPress={this.sendMessage} >
<Text style={[styles.label_send]}>SEND</Text>
</TouchableOpacity>
</View>
</View>
</View>
</View>
);
}
handleInputTextContent(text){
if(text.length > 160){
text = text.substring(0,159)
this.setState({ message_text : text });
} else {
this.setState({ message_text : text });
this.setState({ message_text_length : text.length });
}
}
sendMessage(){
console.log(this.state.message_text);
if(this.state.message_text && this.state.message_text.length > 0) {
console.log("Send message now");
}
}
_renderItem(item, index){
// console.log(item.item);
item = item.item;
let view = (
<Text style = { [styles.msg_common] }> { item.message_content } </Text>
)
return view ;
}
processPaymentMessages(dataArr) {
return dataArr;
}
_fetchConversation() {
new WebApi().fetchThreadConversation().then(result => {
console.log("resutlresult", result);
if (result && result.data && result.data.LastEvaluatedKey) {
this.last_evaluated_key.message_id = result.data.LastEvaluatedKey.message_id;
this.last_evaluated_key.timestamp = result.data.LastEvaluatedKey.timestamp;
} else {
this.setState({
last_message_loaded: true
});
this.last_evaluated_key = null;
}
if (!this.conversation) {
this.conversation = [];
}
for (let i = 0; i < result.data.Items.length; i++) {
item = result.data.Items[i];
this.conversation.push(item);
}
// console.log(this.conversation);
this.setState({ conversation_arr : this.conversation });
this.setState({ show_activty_indicator : false });
console.log(this.state.conversation_arr.length);
}, error => {
console.log("web api fetch data error", error);
})
}
}
const styles = StyleSheet.create({
activity_indicator_container: {
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff'
},
container: {
flex: 1,
paddingTop: 8,
backgroundColor:"#fff"
},
list : {
paddingLeft: 8,
paddingRight:8,
marginBottom : 85,
},
gray_item: {
padding: 10,
height: 44,
backgroundColor:"#fff"
},
white_item : {
padding: 10,
height: 44,
backgroundColor:"#f5f5f5"
},
msg_common : {
flex: 1,
justifyContent: 'flex-end',
alignItems: 'flex-end',
},
colored_item_common : {
padding : 12,
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
item_insider_common : {
backgroundColor:"#fff",
fontSize : 16,
padding : 12,
borderWidth : 1,
borderRadius : 8,
width : "90%",
fontWeight : "bold",
textAlign: 'center',
},
purple_item_insider : {
color : "#7986cb",
borderColor: "#7986cb",
},
green_item_insider : {
color : "#66bb6a",
borderColor: "#66bb6a",
},
bottom_box:{
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
flex: 1,
},
message_length: {
height : 20,
textAlign: 'right', alignSelf: 'stretch'
},
message_box: {
// position: 'absolute',
// left: 0,
// right: 0,
// bottom: 0,
flex: 1,
flexDirection: "row"
},
input_text: {
width: '100%',
height: 60,
color: '#000',
backgroundColor:"#eee",
padding: 16,
},
send_button: {
alignItems: 'center',
flex: 1,
height: 60,
padding: 16,
backgroundColor : '#f1592b'
},
label_send: {
color: '#fff'
}
})
You need to give a callback to onLayout like this:
onLayout={this.scrollNow}
The updated code is: I tried it. It works.
import React, { Component } from 'react';
import { FlatList, Text } from 'react-native';
export default class App extends Component {
render() {
return (
<FlatList
ref={(ref) => { this.flatList1 = ref; }}
data={[0, 0, 0, 0, 0, 0, 0, 0]}
onContentSizeChange={(contentWidth, contentHeight) => { this.flat_list_height = contentHeight; }}
onLayout={this.scrollNow}
renderItem={this.renderItem}
keyExtractor={item => item.message_id}
/>
);
}
renderItem =() => <Text style={{marginTop: 100}}>Just Some Text</Text>
scrollNow =() => {
if (this.flatList1) {
this.flatList1.scrollToEnd();
}
}
}
Have you tried passing an empty array when "this.state.conversation_arr" is undefined or null. Checking this._renderItem can be helpful also, weather it is trying to access -1 of any argument.
There are 2 parts wrong in your code.
the ref in FlatList is a function, not a string.
If you don't use arrow function, the FlatList cannot access the "this" in scrollNow() function.
I tested with similar code. The code below should work.
import * as React from 'react';
import { StyleSheet, View, Text, FlatList } from 'react-native';
export default class Conversation extends React.Component {
flatList1;
_interval;
state = { conversation_arr: [] };
componentDidMount() {
let buffer = [];
for (let i = 1; i < 40; i++) {
buffer.push({ message_id: i, message_content: `I'm the message ${i}` });
}
this._interval = setInterval(() => {
this.setState(() => {
return { conversation_arr: buffer };
});
this.flatList1.scrollToIndex({
index: buffer.length - 1,
viewPosition: 1,
viewOffset: 0,
});
}, 1000);
}
componentWillUnmount() {
clearInterval(this._interval);
}
render() {
return (
<View style={styles.container}>
<FlatList
ref={ref => {
this.flatList1 = ref;
}}
data={this.state.conversation_arr}
renderItem={this._renderItem}
keyExtractor={item => item.message_id}
getItemLayout={(data, index) => ({
length: 40,
offset: 40 * index,
index,
})}
/>
</View>
);
}
_renderItem = ({ item }) => {
return (
<View>
<Text style={styles.msg_common}>{item.message_content}</Text>
</View>
);
};
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
msg_common: {
height: 40,
fontSize: 18,
paddingHorizontal: 10,
},
});
PS: If you have a long list, let's say more than 100. Using onLayout to scroll down might take some time for initial rendering, which provides a really bad user experience. The much better approach may be
to reverse the list before rendering
provide a sort button and set onRefresh to true during sorting
provide a scroll to bottom button list's footer
Update:
I noticed the onContentSizeChange property is NOT in the documentation.
https://facebook.github.io/react-native/docs/flatlist.html#scrolltoindex
Which version of React-Native are you using?
Update2:
The complete code in TypeScript based on yours. I use setInterval to simulate the delay from API call.
Any async function should be in componentDidMount, because constructor doesn't wait.
getItemLayout is used to help FlatList to figure out height. Notice that this is set before the data arrived.

Animation in react-native

I was looking for the logo to reduce to some default size from the actual size and after completion of that some text data should be shown....
but when i saw the facebook website there was no where i found reducing the size of the logo from default.
How should i achieve this
Animated.timing(
this.spinValue,
{
toValue: 1,
duration: 4000,
easing: Easing.linear
}
i didn't get how to change the size of the image in this...
Along with decreasing the size of the image i want the image to move top so some space left at the bottom there i would like to show other text on completion of the animation...
Sorry if i'm wrong..help me out with some docs or references
I have tried:
const imagePos = this.state.scaleValue.interpolate({
inputRange: [0, 1],
outputRange: [500, 200]
})
const imageTop = this.state.scaleValue.interpolate({
inputRange: [0, 1],
outputRange: [400, 100]
})
return <View>
<Animated.Image style={{ height:imagePos ,width:imagePos ,top : imageTop }} resizeMode={'contain'} source={require('../assets/new_images/logo1.png')} />
</View>
You can for example use "scale" to scale down image size on componentDidMount. If I understood you correctly this is what you want
class Playground extends React.Component {
state = {
scaleValue: new Animated.Value(1),
}
componentDidMount() {
Animated.spring(
this.state.scaleValue,
{toValue: 0.5}
).start();
}
render() {
return (
<Animated.Image
source={{uri: 'http://i.imgur.com/XMKOH81.jpg'}}
style={{
flex: 1,
transform: [
{scale: this.state.scaleValue},
]
}}
/>
);
}
}
I achieved this by using multiple animations
this is my componentdidmount
Animated.timing(
this.state.scaleValue,
{toValue: 1 ,duration : 1000 ,easing : Easing.ease ,delay:0}
).start();
this is my rendet
const imagePos = this.state.scaleValue.interpolate({
inputRange: [0, 1],
outputRange: [200, 150]
})
const imageTop = this.state.scaleValue.interpolate({
inputRange: [0, 1],
outputRange: [0.35*windowHeight, 0.1*windowHeight]
})
const content = this.state.scaleValue.interpolate({
inputRange: [0, 1],
outputRange: [0.6*windowHeight, 0]
})
return <View style={{flex:1,alignItems:'center'}}>
<Animated.Image style={{ height:imagePos ,width:imagePos ,top :imageTop}} resizeMode={'contain'} source={require('../assets/new_images/main_screen.png')} />
<Animated.View style={{flex:1,alignItems:'center',top : content}}>
<View><Text>Hi this is bottom content</Text></View>
</Animated.View>
</View>

How to make a react native input which gives validation state feedback to the user. [Valid, Printine, Error, Editing]

I would like to have an input that updates continuously as the user types and then loses focus. The feedback will be a border around the input.
1 Green: when valid
2 Amber: when typing and is in error state (Green when valid)
3 Red: when in error state and unfocused
4 Nothing: when input is pristine (not touched and empty)
What is the best way to achieve this?
Ideally this will work with both iOS and Android.
TextInput has two functions that will be useful to achieve this:
onBlur and onChangeText
To dynamically set the style on the TextInput, you could attach a variable for the bordercolor like below:
<TextInput
onBlur={ () => this.onBlur() }
onChangeText={ (text) => this.onChange(text) }
style={{ borderColor: this.state.inputBorder, height: 70, backgroundColor: "#ededed", borderWidth: 1 }} />
Then, pass the result from the onChangeText function through a regex or pattern matcher to achieve whatever result you are trying to achieve.
I've set up a working project here that checks if there is whitespace, and throws the errors you are wanting. You can take it and edit it to be more specific to your needs, but the basic premise should work the same. I've also put the code below for the working project that implements the functionality:
'use strict';
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
TextInput
} = React;
var SampleApp = React.createClass({
getInitialState: function() {
return {
inputBorder: '#eded',
defaultVal: ''
}
},
onBlur: function() {
console.log('this.state.defaultVal', this.state.defaultVal)
if(this.state.defaultVal.indexOf(' ') >= 0) {
this.setState({
inputBorder: 'red'
})
}
},
onChange: function(text) {
this.setState({
defaultVal: text
})
if(text.indexOf(' ') >= 0) {
this.setState({
inputBorder: '##FFC200'
})
} else {
this.setState({
inputBorder: 'green'
})
}
},
render: function() {
return (
<View style={styles.container}>
<View style={{marginTop:100}}>
<TextInput
onBlur={ () => this.onBlur() }
onChangeText={ (text) => this.onChange(text) }
style={{ height: 70, backgroundColor: "#ededed", borderWidth: 1, borderColor: this.state.inputBorder }} />
</View>
<View style={{marginTop:30}}>
<TextInput
style={{ height: 70, backgroundColor: "#ededed" }} />
</View>
</View>
);
}
});
var styles = StyleSheet.create({
container: {
flex: 1,
}
});
AppRegistry.registerComponent('SampleApp', () => SampleApp);

Categories

Resources