I'm trying to detect when a user presses on a custom UI component I have written (it displays a video feed). I've tried using all the touchable components, and would ideally want to use the TouchableWithoutFeedback component, but none of them detect presses on my component. Additionally, when I select my component with the inspector, I get the error Expected to find at least one React renderer but I'm not sure how to set up my component correctly to have a renderer.
The native UI component:
public class DroneVideoFeedManager extends SimpleViewManager<DroneVideoFeed> {
#Override
public String getName() {
return "DroneLiveVideo";
}
#Override
public DroneVideoFeed createViewInstance(ThemedReactContext context) {
return new DroneVideoFeed(context, null);
}
}
My UI component Javascript wrapper is as follows:
import PropTypes from 'prop-types';
import {
requireNativeComponent,
ViewPropTypes,
} from 'react-native';
const iface = {
name: 'DroneLiveVideo',
propTypes: {
resizeMode: PropTypes.oneOf(['cover', 'contain', 'stretch']),
...ViewPropTypes, // include the default view properties
},
};
module.exports = requireNativeComponent('DroneLiveVideo', iface);
And my attempt to detect a press:
<TouchableWithoutFeedback
onPress={() => console.log('pressed!')}
>
<DroneLiveView
style={{
width: '100%',
height: '100%',
}}
/>
</TouchableWithoutFeedback>
This is the first time I have attempted to implement a native UI component in React Native, so apologies in advance if I am doing things incorrectly.
I found a solution, it's perhaps a little convoluted and not the best way of doing things but it works!
I changed my javascript wrapper to return a view with my native UI component, and another view above it (using absolute positioning). This view appears to handle touches and allows touchables to work with my component.
My changed UI component wrapper is as follows:
import React, {
Component,
} from 'react';
import {
requireNativeComponent,
View,
} from 'react-native';
class DroneVideo extends Component<{}> {
constructor(props) {
super(props);
}
render() {
return (
<View
{...this.props}
>
<View
style={{
width: '100%',
height: '100%',
position: 'absolute',
zIndex: 2,
}}
></View>
<DroneVideoNative
style={{
width: '100%',
height: '100%',
position: 'absolute',
zIndex: 1,
}}
/>
</View>
);
}
}
let DroneVideoNative = requireNativeComponent('DroneLiveVideo', DroneVideo);
export default DroneVideo;
Related
I am trying to use react-native-snap-carousel but however, the swiping effect is not working as expected - it is often difficult to swipe left and right, it requires user to swipe harder to move to another picture (as illustrated in the link below).
Swiping issue with React Native Snap Carousel
I am not able to find any documented soluton but I found one possible prop - swipeThreshold. I try various value, but still the issue persist.
Does anyone know the solution to this?
I suggest you to use react-native-image-slider.
it's flexible and easy to use.
https://www.npmjs.com/package/react-native-image-slider
I made a component named slider.js:
import React, { Component } from 'react';
import {
View,
StyleSheet,
Image,
} from 'react-native';
import ImageSlider from 'react-native-image-slider';
export default class Slider extends Component {
render() {
return (
<ImageSlider
loop
autoPlayWithInterval={3000}
images={this.props.dataSource}
customSlide={({ index, item, style, width }) => (
<View key={index} style={[style, styles.customSlide]}>
<Image source={{ uri: item }} style={styles.customImage} />
</View>
)}
/>
);
}
}
const styles = StyleSheet.create({
customImage: {
height: 180,
marginRight: 20,
marginLeft: 20,
borderWidth: 1,
borderRadius: 10,
marginTop: 8,
},
customSlide: {
backgroundColor: '#eee',
},
});
you can add this to your project and use it wherever you need it like this:
import Slider from '../component/slider';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
images: [
'https://placeimg.com/640/480/nature',
'https://placeimg.com/640/480/tech',
'https://placeimg.com/640/480/animals',
'https://placeimg.com/640/480/tech',
],
}
render() {
return (
<View style={{flex: 1, backgroundColor: '#eee'}}>
<Slider dataSource={this.state.images} />
</View>
);
}
}
If I understand correctly -- making the outermost container as "flex: 1" should let the component span the whole screen.
However, the code I wrote is not working properly.
import React from 'react';
import { View, Text } from 'react-native';
export default function test() {
return (
<View style={{ flex: 1, borderColor: 'red', borderWidth: 5 }}>
<Text>test</Text>
</View>
);
}
The simulator screenshot is here
Can anyone please point out where I did wrong?
Thank a lot!
Where are you calling this component? Yes, the flex will expand, but it is dependent on that parent component container. It looks like your parent is the one restricting this component.
Ensure the parent is also flexing and filling the content. Here is some more details around flex layout: https://facebook.github.io/react-native/docs/flexbox
Change your code to import the Component as a class:
import React from 'react';
import { View, Text } from 'react-native';
export default test extends React.Component {
render() {
return (
<View style={{ flex: 1, borderColor: 'red', borderWidth: 5 }}>
<Text>test</Text>
</View>
);
}
}
I am using "react-native camera" library to access the camera. So here is my code
.
import React, { Component } from "react";
import {
AppRegistry,
Dimensions,
StyleSheet,
Text,
TouchableHighlight,
View
} from "react-native";
import Camera from "react-native-camera";
import { RNCamera, FaceDetector } from "react-native-camera";
export default class App extends Component<Props> {
render() {
return (
<View style={styles.container}>
<Camera
ref={cam => {
this.camera = cam;
}}
style={styles.preview}
aspect={Camera.constants.Aspect.fill}
>
<Text style={styles.capture} onPress=
{this.takePicture.bind(this)}>
take photo
</Text>
</Camera>
</View>
);
}
takePicture() {
const options = {};
//options.location = ...
this.camera
.capture({ metadata: options })
.then(data => console.log(data))
.catch(err => console.error(err));
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: "row"
},
preview: {
flex: 1,
justifyContent: "flex-end",
alignItems: "center"
},
capture: {
flex: 0,
backgroundColor: "#fff",
borderRadius: 5,
color: "#000",
padding: 10,
margin: 40
}
});
Here i am able to access the back camera and whenever i am clicking on take photo, it capture image and show that instantly. But i need two changes here.
Using this code, the back camera is getting accessed but i want to access the front camera.
Also, the image i captured, should not be shown instantly. I want a button , and whenever i click on that button, it navigates to different page and show all the images there.
Is it possible in react native ?? If yes, then please suggest me the changes that i require to make in this code
To answer your second question specifically, you have two options.
A) After taken the photo, store it as base64 uri into your state or redux, then whenever you need it, display the base64 uri as a image.
B) Utilize the package react-native-fs to access file system, storing the taken photo in iOS as cache, and retrieving it whenever needed.
Based on personal experience dealing with it, I would recommend option A
To switch your camera to back camera to front camera there exists a prop in Camera component called mirrorMode, if it is true it will show the front camera, otherwise, it will be the default mode that is back camera:
<Camera
...
mirrorImage={this.state.mirrorMode}
>
You can create a state and a button that change the state to switch between that 2 cameras.
So there are two components sort of like this:
<View>
<Component1 />
<Component2 />
</View>
Both, Component1 & Component2 can be dragged and dropped within the View. By default, Component2 will render above the Component1 (since it is above in the stack). I want to make it so that whenever I press Component1 (for drag and drop) it dynamically comes infront of Component2 (Higher zIndex) and if I press Component1 and drag and drop, Component1 comes infront of Component2.
Anyone has any idea on how this can be done?
Edit 1:
I'm using zIndex, but for some reason it's working on iOS but not working on Android. Here's the basic code:
<View>
<View style={{position:'absolute',zIndex:2,backgroundColor:'red',width:500,height:500}}/>
<View style={{position:'absolute',zIndex:1,backgroundColor:'green',width:500,height:500,marginLeft:50}}/>
</View>
Setting dynamic zIndex for child components looks like the way to go. (zIndex on docs)
I would store the zIndexes of each child in the state. And I would wrap Component1 and Component2 with a touchable component if they are not already. When dragging & dropping starts, I'd update the zIndex stored in the state so that the required child would have higher zIndex.
Since I don't exactly know how you structured the components and their layouts, I am unable to provide a example code piece.
EDIT
Workaround for missing zIndex implementation on Android
I'd go something like this, if nothing else works:
import React from 'react';
import {
StyleSheet,
View,
} from 'react-native';
const style = StyleSheet.create({
wrapper: {
flex: 1,
position: 'relative',
},
child: {
position: 'absolute',
width: 500,
height: 500,
},
});
class MyComponent extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
reverseOrderOfChildren: false,
};
}
render() {
const firstChild = <View style={[style.child, {backgroundColor: 'red'}]} />
const secondChild = <View style={[style.child, {backgroundColor: 'green'}]} />
if (this.state.reverseOrderOfChildren) {
return (
<View style={style.wrapper}>
{secondChild}
{firstChild}
</View>
);
}
return (
<View style={style.wrapper}>
{firstChild}
{secondChild}
</View>
);
}
}
Haven't noticed much sample code/guides on how to use the CameraRoll library from React Native, I found the example in the docs a bit "vague" and confusing.
First time I'm using any of the API's so I do not fully understand how I'm suppose to use the library either. So far I've imported it like:
import {
AppRegistry,
Image,
StyleSheet,
TextInput,
Navigator,
CameraRoll,
Alert,
TouchableHighlight,
Button,
Text,
View
} from 'react-native';
quite confused with "Linking" etc, but as far as I know, this should be all I need to do in order to use the lib.
And how do I use it for something as simple as to open the gallery on the click of a button and let the user choose an image that should then be displayed in the app.
Thanks in advance, hope someone has some code to clarify this.
Here is some sample code that will grab the first 25 photos from your camera roll and display them in a ScrollView. I modified this from an example I found online here
import React, { Component, PropTypes } from 'react'
import {
CameraRoll,
Image,
ScrollView,
StyleSheet,
TouchableHighlight,
View,
} from 'react-native';
class CameraRollView extends Component {
constructor(props) {
super(props)
var controls = props.controls
this.state = {
images: [],
selected: '',
fetchParams: { first: 25 },
groupTypes: 'SavedPhotos',
}
this._storeImages = this._storeImages.bind(this)
this._logImageError = this._logImageError.bind(this)
this._selectImage = this._selectImage.bind(this)
}
componentDidMount() {
// get photos from camera roll
CameraRoll.getPhotos(this.state.fetchParams, this._storeImages, this._logImageError);
}
// callback which processes received images from camera roll and stores them in an array
_storeImages(data) {
const assets = data.edges;
const images = assets.map( asset => asset.node.image );
this.setState({
images: images,
});
}
_logImageError(err) {
console.log(err);
}
_selectImage(uri) {
// define whatever you want to happen when an image is selected here
this.setState({
selected: uri,
});
console.log('Selected image: ', uri);
}
render() {
return (
<View style={{flex: 1, backgroundColor: 'white'}}>
<ScrollView style={styles.container}>
<View style={styles.imageGrid}>
{ this.state.images.map(image => {
return (
<TouchableHighlight onPress={() => this._selectImage(image.uri)}>
<Image style={styles.image} source={{ uri: image.uri }} />
</TouchableHighlight>
);
})}
</View>
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
imageGrid: {
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'center'
},
image: {
width: 100,
height: 100,
margin: 10,
},
});
export default CameraRollView
Hmm, the package you are seeking is probably react-native-image-picker. It allows you to take a photo or select one from your native device gallery.
LINK: https://github.com/react-community/react-native-image-picker
In response to the linking issue. When you save a package using:
npm install --save react-native-image-picker
What is happening here is the --save part prepares the packages dependencies to be connected to native iOS and Android. This linking is done using the command react-native link.
In some cases packages require some manual linking aswell (for example, this package requires a small amount of native iOS and Android configuration)