I'm trying to use Parse as the data provider for a ListView in a Reactive Native app. I have followed the Parse guide regarding subscribing to a query but for some unknown reason the the data source is empty. I have verified and writing a test object to Parse works fine.
It seems that observe() should be called before getInitialState() or am I missing something?
'use strict';
var React = require('react-native');
var Strings = require('./LocalizedStrings');
var Parse = require('parse').Parse;
var ParseReact = require('parse-react');
Parse.initialize("api_key_here", "api_key_here");
/*
var TestObject = Parse.Object.extend("TestObject");
var testObject = new TestObject();
testObject.save({foo: "bar"}).then(function(object) {
alert("yay! it worked");
});
*/
var {
View,
Text,
ListView,
StyleSheet
} = React;
var styles = StyleSheet.create({
mainContainer: {
flex: 1,
padding: 30,
marginTop: 65,
flexDirection: 'column',
justifyContent: 'center',
backgroundColor: '#fff'
},
title: {
marginBottom: 20,
fontSize: 22,
textAlign: 'center',
color: '#000'
},
});
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}) // assumes immutable objects
var WorkoutList = React.createClass({
mixins: [ParseReact.Mixin],
observe: function() {
return {
workouts: (new Parse.Query("Workout")).descending("createdAt")
};
},
getInitialState: function() {
return {dataSource: ds.cloneWithRows(this.data.workouts)}
},
renderRow: function() {
return (<View><Text>Testing</Text></View>)
},
render: function() {
return (
<View style = {{flex: 1, flexDirection: 'column'}}>
{Strings.workoutsTabTitle}
<ListView
ref = "listview"
dataSource = {this.state.dataSource}
renderRow = {this.renderRow}
automaticallyAdjustContentInsets = {false}
keyboardDismissMode = "onDrag"
keyboardShouldPersistTaps = {true}
showsVerticalScrollIndicator = {true}
style = {styles.mainContainer}
/>
</View>
)
}
})
module.exports = WorkoutList;
I didn't use ParseReact but the Parse Rest API to fetch data from Parse. The following code is called from componentDidMount.
fetch("https://api.parse.com/1/classes/Workout", {
headers: {
"X-Parse-Application-Id": "Your application Id",
"X-Parse-REST-API-Key": "Your API Key"
}
})
.then((response) => response.json())
.then((responseData) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData.results),
loaded: true,
})
})
.catch(function(error) {
console.log(error)
})
.done();
Using this approach you need to wait until the data is loaded before displaying the ListView. Use this.state.loaded to know when this is the case.
This works too.
observe: function() {
return {
user: ParseReact.currentUser,
abc: (new Parse.Query('abc')).descending('createdAt')
};
},
getInitialState: function () {
return {
dataSource: new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}),
};
},
render: function() {
return (
<View style={styles.full}>
<ListView
dataSource={this.state.dataSource.cloneWithRows(this.data.abc)}
renderRow={this.renderRow}
/>
</View>
);
},
Hope it helps! Cheers!
Related
I am building a ReactNative application for both IOS and Android platforms. My app needs to read data from another device via BLE communication. I am using this package for implementing BLE communication, https://github.com/innoveit/react-native-ble-manager. I am having a problem with receiving characteristic data on IOS even though it is working as expected on the Android platform.
I have added the following to the info.plist file:
Privacy - Bluetooth Always Usage Description: App needs to use Bluetooth to receive data from WaterRower machine
I have a component that scan and list down the BLE devices as follow. It is called, BleDeviceList.js
import React, {
useState,
useEffect,
} from 'react';
import {
SafeAreaView,
StyleSheet,
ScrollView,
View,
Text,
StatusBar,
NativeModules,
NativeEventEmitter,
Button,
Platform,
PermissionsAndroid,
FlatList,
TouchableHighlight,
} from 'react-native';
import {
Colors,
} from 'react-native/Libraries/NewAppScreen';
import BleManager from 'react-native-ble-manager';
const BleManagerModule = NativeModules.BleManager;
const bleManagerEmitter = new NativeEventEmitter(BleManagerModule);
const BleDeviceList = (props) => {
const [isScanning, setIsScanning] = useState(false);
const peripherals = new Map();
const [list, setList] = useState([]);
const [ connectedDevices, setConnectedDevices ] = useState([ ]);
const [ permissionsAllowed, setPermissionsAllowed ] = useState(false)
const startScan = () => {
if (!isScanning) {
BleManager.scan([], 3, true).then((results) => {
console.log('Scanning...');
setIsScanning(true);
}).catch(err => {
console.error(err);
});
}
}
const handleStopScan = () => {
console.log('Scan is stopped');
setIsScanning(false);
}
const handleDisconnectedPeripheral = (data) => {
let peripheral = peripherals.get(data.peripheral);
if (peripheral) {
peripheral.connected = false;
peripherals.set(peripheral.id, peripheral);
setList(Array.from(peripherals.values()));
}
console.log('Disconnected from ' + data.peripheral);
}
const handleUpdateValueForCharacteristic = (data) => {
console.log('Received data from ' + data.peripheral + ' characteristic ' + data.characteristic, data.value);
}
const retrieveConnected = () => {
BleManager.getConnectedPeripherals([]).then((results) => {
if (results.length == 0) {
console.log('No connected peripherals')
}
console.log(results);
for (var i = 0; i < results.length; i++) {
var peripheral = results[i];
peripheral.connected = true;
peripherals.set(peripheral.id, peripheral);
setList(Array.from(peripherals.values()));
}
});
}
const handleDiscoverPeripheral = (peripheral) => {
console.log('Got ble peripheral', peripheral);
if (!peripheral.name) {
peripheral.name = 'NO NAME';
}
peripherals.set(peripheral.id, peripheral);
setList(Array.from(peripherals.values()));
}
const isConnected = (peripheral) => {
return connectedDevices.filter(cd => cd.id == peripheral.id).length > 0;
}
const toggleConnectPeripheral = (peripheral) => {
if (peripheral){
if (isConnected(peripheral)){
BleManager.disconnect(peripheral.id);
setConnectedDevices(connectedDevices.filter(cd => cd.id != peripheral.id))
}else{
BleManager.connect(peripheral.id).then(() => {
let tempConnnectedDevices = [ ...connectedDevices ]
tempConnnectedDevices.push(peripheral);
setConnectedDevices(tempConnnectedDevices);
props.navigation.push('BleRowingSession', { peripheral: peripheral });
let p = peripherals.get(peripheral.id);
if (p) {
p.connected = true;
peripherals.set(peripheral.id, p);
setList(Array.from(peripherals.values()));
props.navigation.push('BleDeviceServiceList', { peripheral: peripheral });
}
console.log('Connected to ' + peripheral.id);
}).catch((error) => {
console.log('Connection error', error);
});
}
}
}
useEffect(() => {
BleManager.start({showAlert: false});
bleManagerEmitter.addListener('BleManagerDiscoverPeripheral', handleDiscoverPeripheral);
bleManagerEmitter.addListener('BleManagerStopScan', handleStopScan );
bleManagerEmitter.addListener('BleManagerDisconnectPeripheral', handleDisconnectedPeripheral );
bleManagerEmitter.addListener('BleManagerDidUpdateValueForCharacteristic', handleUpdateValueForCharacteristic );
if (Platform.OS === 'android' && Platform.Version >= 23) {
PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION).then((result) => {
if (result) {
console.log("Permission is OK");
setPermissionsAllowed(true);
} else {
PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION).then((result) => {
if (result) {
console.log("User accept");
setPermissionsAllowed(true);
} else {
console.log("User refuse");
setPermissionsAllowed(false);
}
});
}
});
} else {
setPermissionsAllowed(true)
}
return (() => {
console.log('unmount');
bleManagerEmitter.removeListener('BleManagerDiscoverPeripheral', handleDiscoverPeripheral);
bleManagerEmitter.removeListener('BleManagerStopScan', handleStopScan );
bleManagerEmitter.removeListener('BleManagerDisconnectPeripheral', handleDisconnectedPeripheral );
bleManagerEmitter.removeListener('BleManagerDidUpdateValueForCharacteristic', handleUpdateValueForCharacteristic );
})
}, []);
const renderConnectButton = (item) => {
if (isConnected(item)) {
return null
}
return (
<Button
title="Connect"
onPress={() => {
toggleConnectPeripheral(item)
}}
/>
)
}
const renderDisconnectButton = (item) => {
if (! isConnected(item)) {
return null
}
return (
<Button
title="Disconnect"
onPress={() => {
toggleConnectPeripheral(item)
}}
/>
)
}
const renderItem = (item) => {
const color = item.connected ? 'green' : '#fff';
return (
<TouchableHighlight>
<View style={[styles.row, {backgroundColor: color}]}>
<Text style={{fontSize: 12, textAlign: 'center', color: '#333333', padding: 10}}>{item.name}</Text>
<Text style={{fontSize: 10, textAlign: 'center', color: '#333333', padding: 2}}>RSSI: {item.rssi}</Text>
<Text style={{fontSize: 8, textAlign: 'center', color: '#333333', padding: 2, paddingBottom: 20}}>{item.id}</Text>
{renderConnectButton(item)}
{renderDisconnectButton(item)}
</View>
</TouchableHighlight>
);
}
const renderContent = () => {
if (! permissionsAllowed) {
return <Text>Bluetooth and locations permissions are required.</Text>
}
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView>
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={styles.scrollView}>
{global.HermesInternal == null ? null : (
<View style={styles.engine}>
<Text style={styles.footer}>Engine: Hermes</Text>
</View>
)}
<View style={styles.body}>
<View style={{margin: 10}}>
<Button
title={'Scan Bluetooth (' + (isScanning ? 'on' : 'off') + ')'}
onPress={() => startScan() }
/>
</View>
<View style={{margin: 10}}>
<Button title="Retrieve connected peripherals" onPress={() => retrieveConnected() } />
</View>
{(list.length == 0) &&
<View style={{flex:1, margin: 20}}>
<Text style={{textAlign: 'center'}}>No peripherals</Text>
</View>
}
</View>
</ScrollView>
<FlatList
data={list}
renderItem={({ item }) => renderItem(item) }
keyExtractor={item => item.id}
/>
</SafeAreaView>
</>
)
}
return (
renderContent()
);
};
const styles = StyleSheet.create({
scrollView: {
backgroundColor: Colors.lighter,
},
engine: {
position: 'absolute',
right: 0,
},
body: {
backgroundColor: Colors.white,
},
sectionContainer: {
marginTop: 32,
paddingHorizontal: 24,
},
sectionTitle: {
fontSize: 24,
fontWeight: '600',
color: Colors.black,
},
sectionDescription: {
marginTop: 8,
fontSize: 18,
fontWeight: '400',
color: Colors.dark,
},
highlight: {
fontWeight: '700',
},
footer: {
color: Colors.dark,
fontSize: 12,
fontWeight: '600',
padding: 4,
paddingRight: 12,
textAlign: 'right',
},
});
export default BleDeviceList;
As you can see in the code, when the Connect button is clicked, it will redirect the user to another component that reads data from another device. The following is the BleRowingSession.js that reads the data from another device.
import React, { useEffect, useState } from 'react';
import { Text, View, StyleSheet, NativeModules, NativeEventEmitter, ScrollView } from 'react-native';
import BleManager from 'react-native-ble-manager';
const BleManagerModule = NativeModules.BleManager;
const bleManagerEmitter = new NativeEventEmitter(BleManagerModule);
const serviceId = "00001826-0000-1000-8000-00805F9B34FB";
const characteristicId = "00002AD1-0000-1000-8000-00805F9B34FB";
let readDataCache = "";
const BleRowingSession = (props) => {
let peripheral = props.route.params.peripheral;
const [ readData, setReadData ] = useState("");
const setUpBleNotification = () => {
BleManager.retrieveServices(peripheral.id).then((peripheralData) => {
console.log('Retrieved peripheral services', peripheralData);
setTimeout(() => {
BleManager.startNotification(peripheral.id, serviceId, characteristicId).then(() => {
console.log('Started notification on ' + peripheral.id);
bleManagerEmitter.addListener('BleManagerDidUpdateValueForCharacteristic', (data) => {
readDataCache = readDataCache + "\n" + data.value.toString()
setReadData(readDataCache);
});
setTimeout(() => {
}, 500);
}).catch((error) => {
console.log('Notification error', error);
});
}, 500)
});
}
useEffect(() => {
setUpBleNotification()
}, [ ])
return (
<View style={styles.container}>
<ScrollView>
<Text>Ble Rowing Session</Text>
<Text>{readData}</Text>
</ScrollView>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center"
}
})
export default BleRowingSession;
For now, the service id and characteristic id are hardcoded. Of course, I had to choose the right device on the first page that displays the list of BLE devices.
When I run the code, it is working as expected on the Android device, it is receiving the characteristic value. When I run the code on the actual IOS device, it is not receiving any data. But it can scan the devices and connect to them. What is wrong with my code and how can I fix it?
Here I am only running two API requests. The first one in the componentDidMount function works fine, but the second one labeled handleMatchFacts does not work. In short, Using React-Native I'm retrieving information from the API, mounting it to the page and then once the Touchablehighlight is clicked it is suppose to retrieve additional information from the API according to the 'id' that is passed in 'onPress'. I am able to console.log the json of the data in the second request, but for some reason when I setState with the new data and render it to the page in ListView, I get an error.
import React from 'react'
import { View, Text, StyleSheet, ListView, TouchableHighlight } from 'react-native'
export default class Main extends React.Component {
constructor() {
super();
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
matches: ds.cloneWithRows([]),
matchFacts: ds.cloneWithRows([])
};
this.handleShowMatchFacts.bind(this)
}
componentDidMount(){
fetch("http://api.football-api.com/2.0/matches?match_date=27.04.2017&to_date=27.04.2017&Authorization=565ec012251f932ea4000001fa542ae9d994470e73fdb314a8a56d76")
.then(res => res.json())
.then(matches => {
this.setState({
matches : this.state.matches.cloneWithRows(matches)
})
})
}
handleShowMatchFacts = id => {
console.log('match', id)
return fetch(`http://api.football-api.com/2.0/matches/${id}?Authorization=565ec012251f932ea4000001fa542ae9d994470e73fdb314a8a56d76`)
.then(res => res.json())
.then(matchFacts => {
console.log('match facts', matchFacts)
let selectedMatch = matchFacts;
this.setState({
matches : this.state.matches.cloneWithRows([]),
matchFacts : this.state.matchFacts.cloneWithRows(selectedMatch)
})
})
}
render() {
return (
<View style={styles.mainContainer}>
<Text
style={styles.header}>
Todays Matches</Text>
<ListView
style={styles.matches}
dataSource={this.state.matches}
renderRow={(matches) =>
<TouchableHighlight
onPress={() => this.handleShowMatchFacts(matches.id)}
underlayColor="green"
><Text style={styles.item}> {matches.localteam_name} {matches.localteam_score} - {matches.visitorteam_score} {matches.visitorteam_name} </Text>
</TouchableHighlight>
}
/>
<ListView
style={styles.matches}
dataSource={this.state.matchFacts}
renderRow={(match) =>
<Text style={styles.item}> {match.localteam_name} {match.localteam_score} - {match.visitorteam_score} {match.visitorteam_name} </Text>
}
/>
</View>
);
}
}
const styles = StyleSheet.create({
mainContainer : {
flex: 1,
padding: 20
},
header : {
textAlign: 'center'
},
matches : {
marginTop: 20
},
item : {
borderRadius: 4,
borderWidth: 0.5,
borderColor: 'green',
marginBottom: 5,
padding: 20,
textAlign: 'center',
},
});
You're probably seeing an issue because the second API request doesn't return an array, it returns an object. The cloneWithRows expects an array. Replacing this line
matchFacts : this.state.matchFacts.cloneWithRows(selectedMatch)
with
matchFacts : this.state.matchFacts.cloneWithRows([selectedMatch])
may help, depending on how you render this new data.
That's just a guess since I don't know what error you're receiving.
I am new to react native and I was implemented a simple idea in my head. Basically, I am doing a 'todo list' like component which theres a add button below and items can be added. The problem arises after clicking on the add button and the list gets updated and the following xcode warning message appears. And I have realised, after implementing the ListView, that the app in the simulator slows down so much i couldn't even inspect. The alert popup would freeze the UI after some text are entered too, and the entire app needs to be built again since I couldn't do anything. Thanks for all the help!
Main component: SurveyQn
'use strict'
import React, {
Component,
StyleSheet,
Text,
TouchableHighlight,
TextInput,
View,
ListView,
AlertIOS
} from 'react-native';
var LongButton = require('./LongButton.js');
class SurveyQn extends Component {
constructor(props) {
super(props);
this.state = {
options: [{option: 'Pizza'}],
};
}
componentWillMount() {
this.dataSource = new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2
})
}
_renderItem(item) {
return (
<LongButton
text={item.option}
onPress={() => {}}
//btnViewStyle={styles.buttonView}
//btnTextStyle={styles.buttonText}
/>
);
}
_addItem() {
AlertIOS.alert(
'Add new option',
null,
[
{
text: 'Add',
onPress: (text) => {
var options = this.state.options;
options.push({option: text})
this.setState({ options: options})
}
},
],
'plain-text'
);
}
render(){
var dataSource = this.dataSource.cloneWithRows(this.state.options);
return (
<View style={styles.container}>
<TextInput
style={styles.question}
placeholder="Question title"
placeholderTextColor="#4B667B"
selectionColor="#4B667B"
onChangeText={(text) => this.setState({text})}/>
<View style={styles.listView}>
<ListView
dataSource={dataSource}
renderRow={this._renderItem.bind(this)}/>
</View>
<TouchableHighlight
onPress={this._addItem.bind(this)}
style={styles.buttonView}
underlayColor='rgba(0,0,0,0)'>
<Text style={styles.buttonText}>
Add option
</Text>
</TouchableHighlight>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
width: 300,
flex :1,
},
listView: {
flex: 1,
},
question: {
height: 30,
fontSize: 20,
fontWeight: "100",
color: '#4B667B',
marginTop: 10,
marginBottom: 10,
},
buttonView: {
width: 300,
paddingVertical: 9,
borderWidth: 1,
borderColor: '#F868AF',
marginBottom: 13,
},
buttonText: {
textAlign: 'center',
fontSize: 25,
color: '#F868AF',
fontWeight: '500'
},
});
ListView item: LongButton
'use strict'
import React, {
Component,
StyleSheet,
Text,
TouchableHighlight,
View,
} from 'react-native';
class LongButton extends Component {
render(){
return (
<TouchableHighlight
onPress={this.props.onPress}
style={this.props.btnViewStyle}
underlayColor='rgba(0,0,0,0)'>
<Text style={this.props.btnTextStyle}>
{this.props.text}
</Text>
</TouchableHighlight>
);
}
}
module.exports = LongButton;
Xcode warning message upon adding item on alert
app[27881:11151280] the behavior of the UICollectionViewFlowLayout is not defined because:
app[27881:11151280] the item height must be less than the height of the UICollectionView minus the section insets top and bottom values, minus the content insets top and bottom values.
app[27881:11151280] The relevant UICollectionViewFlowLayout instance is <_UIAlertControllerCollectionViewFlowLayout: 0x7ff0685b1770>, and it is attached to ; layer = ; contentOffset: {0, 0}; contentSize: {0, 0}> collection view layout: <_UIAlertControllerCollectionViewFlowLayout: 0x7ff0685b1770>.
2016-04-06 07:50:01.545 decisionapp[27881:11151280] Make a symbolic breakpoint at UICollectionViewFlowLayoutBreakForInvalidSizes to catch this in the debugger.
Updates:
I tried this but its not working either. Could it be the alert causing these problems? Its just taking forever to render the alert after clicking on the btn.
class SurveyQn extends Component {
constructor(props) {
super(props);
this.state = {
options: [{option: 'Pizza'}],
dataSource : new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2
})
};
}
componentWillMount() {
var data = this.state.options;
this.state.dataSource.cloneWithRows(data);
}
_renderItem(item) {
return (
{item.option}
);
}
_addItem() {
AlertIOS.alert(
'Add new option',
null,
[
{
text: 'Add',
onPress: (text) => {
var options = this.state.options;
options.push({option: text})
this.setState({ options: options})
}
},
],
'plain-text'
);
}
render(){
return (
<View style={styles.listView}>
<ListView
dataSource={this.state.dataSource}
renderRow={this._renderItem.bind(this)}/>
</View>
<TouchableHighlight
onPress={this._addItem.bind(this)}
style={styles.buttonView}
underlayColor='rgba(0,0,0,0)'>
<Text style={styles.buttonText}>
Add option
</Text>
</TouchableHighlight>
</View>
);
}
}
Before diving into complex EcmaScript notation, you can use simple notation. Here is a simple example of ListView. Please go through it and understand how it works.
var API = require('./API');
module.exports = React.createClass({
getInitialState: function(){
return {
rawData: [],
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2
}),
loaded: false,
}
},
componentWillMount: function(){
this.loadData();
},
loadData: function(){
API.getItems()
.then((data) => {
this.setState({
rawData: this.state.rawData.concat(data),
dataSource: this.state.dataSource.cloneWithRows(data),
loaded: true,
});
});
},
render: function(){
return(
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderItem}
style={styles.listView}>
</ListView>
);
},
renderItem: function(item){
return (
<View>
<Text>Custom Item</Text>
</View>
);
},
}
In API.js, I am fetching data from an API.
getItems: function(){
var REQUEST_URL = 'http://api.example.org/item/get?api_key=xxxx;
return fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseData) => {
return responseData.results.sort(sortByDate);
});
}
The code may not work, since I have not tested. But you can refer my sample project on github. Repo
With this code how would I add a second or multiple panresponders that can be moved independently of each other? If I use the same panresponder instance and code they move together as one. I want to know how to have several independently draggable panresponders.
'use strict';
var React = require('react-native');
var {
PanResponder,
StyleSheet,
View,
processColor,
} = React;
var CIRCLE_SIZE = 80;
var CIRCLE_COLOR = 'blue';
var CIRCLE_HIGHLIGHT_COLOR = 'green';
var PanResponderExample = React.createClass({
statics: {
title: 'PanResponder Sample',
description: 'Shows the use of PanResponder to provide basic gesture handling.',
},
_panResponder: {},
_previousLeft: 0,
_previousTop: 0,
_circleStyles: {},
circle: (null : ?{ setNativeProps(props: Object): void }),
componentWillMount: function() {
this._panResponder = PanResponder.create({
onStartShouldSetPanResponder: this._handleStartShouldSetPanResponder,
onMoveShouldSetPanResponder: this._handleMoveShouldSetPanResponder,
onPanResponderGrant: this._handlePanResponderGrant,
onPanResponderMove: this._handlePanResponderMove,
onPanResponderRelease: this._handlePanResponderEnd,
onPanResponderTerminate: this._handlePanResponderEnd,
});
this._previousLeft = 20;
this._previousTop = 84;
this._circleStyles = {
style: {
left: this._previousLeft,
top: this._previousTop
}
};
},
componentDidMount: function() {
this._updatePosition();
},
render: function() {
return (
<View
style={styles.container}>
<View
ref={(circle) => {
this.circle = circle;
}}
style={styles.circle}
{...this._panResponder.panHandlers}
/>
</View>
);
},
_highlight: function() {
const circle = this.circle;
circle && circle.setNativeProps({
style: {
backgroundColor: processColor(CIRCLE_HIGHLIGHT_COLOR)
}
});
},
_unHighlight: function() {
const circle = this.circle;
circle && circle.setNativeProps({
style: {
backgroundColor: processColor(CIRCLE_COLOR)
}
});
},
_updatePosition: function() {
this.circle && this.circle.setNativeProps(this._circleStyles);
},
_handleStartShouldSetPanResponder: function(e: Object, gestureState: Object): boolean {
// Should we become active when the user presses down on the circle?
return true;
},
_handleMoveShouldSetPanResponder: function(e: Object, gestureState: Object): boolean {
// Should we become active when the user moves a touch over the circle?
return true;
},
_handlePanResponderGrant: function(e: Object, gestureState: Object) {
this._highlight();
},
_handlePanResponderMove: function(e: Object, gestureState: Object) {
this._circleStyles.style.left = this._previousLeft + gestureState.dx;
this._circleStyles.style.top = this._previousTop + gestureState.dy;
this._updatePosition();
},
_handlePanResponderEnd: function(e: Object, gestureState: Object) {
this._unHighlight();
this._previousLeft += gestureState.dx;
this._previousTop += gestureState.dy;
},
});
var styles = StyleSheet.create({
circle: {
width: CIRCLE_SIZE,
height: CIRCLE_SIZE,
borderRadius: CIRCLE_SIZE / 2,
backgroundColor: CIRCLE_COLOR,
position: 'absolute',
left: 0,
top: 0,
},
container: {
flex: 1,
paddingTop: 64,
},
});
module.exports = PanResponderExample;
You can use an array of PanResponders, created like so:
this._panResponders = yourObjectsArray.map((_, index) => (
PanResponder.create({
onMoveShouldSetPanResponder: () => true,
...
})
));
yourObjectsArray is an array that you use for creating as many panResponders as you want, I imagine each object in that array will correspond to a data instance of whatever data structure you use to create the moveable Views.
Then to actually use it in your View:
render: function() {
return yourObjectsArray.map((_, index) => (
<View
style={styles.container}>
<View
... some stuff here ...
{...this._panResponders[index].panHandlers}
/>
</View>
)
};
I use ReactNative to develop my iOS APP,to realize the QRCode scanner function,i took the react-native-camera component which provide the barcode scanner function to my project.everything goes all right,but when i had succeed in recognizing a QRCode,next time i use the model,the screen just got frozen,seems like the app goes crashed. something interesting that as the screen is frozen,and once the model cancelled from the left button of navigation,The module can work properly.
I'm not sure whether it's a inner bug of NavigatorIOS,or just the bug of react-native-camera itself.
here is the QRCode component code:
'use strict';
var React = require('react-native');
var Dimensions = require('Dimensions');
var {
StyleSheet,
View,
Text,
TouchableOpacity,
VibrationIOS,
Navigator,
} = React;
var Camera = require('react-native-camera');
var { width, height } = Dimensions.get('window');
var QRCodeScreen = React.createClass({
propTypes: {
cancelButtonVisible: React.PropTypes.bool,
cancelButtonTitle: React.PropTypes.string,
onSucess: React.PropTypes.func,
onCancel: React.PropTypes.func,
},
getDefaultProps: function() {
return {
cancelButtonVisible: false,
cancelButtonTitle: 'Cancel',
barCodeFlag: true,
};
},
_onPressCancel: function() {
var $this = this;
requestAnimationFrame(function() {
$this.props.navigator.pop();
if ($this.props.onCancel) {
$this.props.onCancel();
}
});
},
_onBarCodeRead: function(result) {
var $this = this;
if (this.props.barCodeFlag) {
this.props.barCodeFlag = false;
setTimeout(function() {
VibrationIOS.vibrate();
$this.props.navigator.pop();
$this.props.onSucess(result.data);
}, 1000);
}
},
render: function() {
var cancelButton = null;
if (this.props.cancelButtonVisible) {
cancelButton = <CancelButton onPress={this._onPressCancel} title={this.props.cancelButtonTitle} />;
}
return (
<Camera onBarCodeRead={this._onBarCodeRead} style={styles.camera}>
<View style={styles.rectangleContainer}>
<View style={styles.rectangle}/>
</View>
{cancelButton}
</Camera>
);
},
});
var CancelButton = React.createClass({
render: function() {
return (
<View style={styles.cancelButton}>
<TouchableOpacity onPress={this.props.onPress}>
<Text style={styles.cancelButtonText}>{this.props.title}</Text>
</TouchableOpacity>
</View>
);
},
});
var styles = StyleSheet.create({
camera: {
width:width,
height: height,
alignItems: 'center',
justifyContent: 'center',
},
rectangleContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'transparent',
},
rectangle: {
height: 250,
width: 250,
borderWidth: 2,
borderColor: '#00FF00',
backgroundColor: 'transparent',
},
cancelButton: {
flexDirection: 'row',
justifyContent: 'center',
backgroundColor: 'white',
borderRadius: 3,
padding: 15,
width: 100,
marginBottom: 10,
},
cancelButtonText: {
fontSize: 17,
fontWeight: '500',
color: '#0097CE',
},
});
module.exports = QRCodeScreen;
And In another Component I push this qrCode to the new sence:
'use strict';
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
TouchableOpacity,
NavigatorIOS,
AlertIOS,
Navigator,
} = React;
var QRCodeScreen = require('./QRCodeScreen');
var cameraApp = React.createClass({
render: function() {
return (
<NavigatorIOS
style={styles.container}
initialRoute={{
title: 'Index',
backButtonTitle: 'Back',
component: Index,
}}
/>
);
}
});
var Index = React.createClass({
render: function() {
return (
<View style={styles.contentContainer}>
<TouchableOpacity onPress={this._onPressQRCode}>
<Text>Read QRCode</Text>
</TouchableOpacity>
</View>
);
},
_onPressQRCode: function() {
this.props.navigator.push({
component: QRCodeScreen,
title: 'QRCode',
passProps: {
onSucess: this._onSucess,
},
});
},
// onPressCancel:function(){
//
// this.props.navigator.getContext(this).pop();
//
// },
_onSucess: function(result) {
AlertIOS.alert('Code Context', result, [{text: 'Cancel', onPress: ()=>console.log(result)}]);
// console.log(result);
},
});
var styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
contentContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}
});
AppRegistry.registerComponent('Example', () => cameraApp);
Any answer will be helpful!
I think it's a inner bug of NavigatorIOS, or maybe just sth else wrong.
Blew is my code, it is ok.
'use strict';
const React = require('react-native');
const {
AppRegistry,
StyleSheet,
Text,
View,
TouchableOpacity,
Navigator,
} = React;
var QRCodeScreen = require('./QRCodeScreen');
const CameraApp = () => {
const renderScene = (router, navigator) => {
switch (router.name) {
case 'Index':
return <Index navigator={navigator}/>;
case 'QRCodeScreen':
return <QRCodeScreen
onSucess={router.onSucess}
cancelButtonVisible={router.cancelButtonVisibl}
navigator={navigator}
/>;
}
}
return (
<Navigator
style={styles.container}
initialRoute={{
name: 'Index',
}}
renderScene={renderScene}
/>
);
};
const Index = ({navigator}) => {
const onPressQRCode = () => {
navigator.push({
name: 'QRCodeScreen',
title: 'QRCode',
onSucess: onSucess,
cancelButtonVisible: true,
});
};
const onSucess = (result) => {
console.log(result);
};
return (
<View style={styles.contentContainer}>
<TouchableOpacity onPress={onPressQRCode}>
<Text>Read QRCode</Text>
</TouchableOpacity>
</View>
);
};
module.exports = CameraApp;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
contentContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}
});
you can try Library react native qrcode
https://github.com/moaazsidat/react-native-qrcode-scanner. on me ,
its run. you can try . in ios and android.