Animation not showing in React Native mobile app - react-native

I have created a React Native app to test animations. I have a background and when the user presses this background I want an animation to appear over the background and animate. The code:
import * as React from 'react';
import { StyleSheet, Text, View, TouchableOpacity, Image, ImageBackground, Animated, Easing, Platform
} from 'react-native';
import { frame1 } from '../app-master-test/assets/index';
import { frame2 } from '../app-master-test/assets/index';
import { frame3 } from '../app-master-test/assets/index';
import { frame4 } from '../app-master-test/assets/index';
import { frame5 } from '../app-master-test/assets/index';
import { frame6 } from '../app-master-test/assets/index';
import { frame7 } from '../app-master-test/assets/index';
import { frame8 } from '../app-master-test/assets/index';
import { background } from '../app-master-test/assets/index';
const Images= [
{ id: 1, source: frame1},
{ id: 2, source: frame2 },
{ id: 3, source: frame3 },
{ id: 4, source: frame4 },
{ id: 5, source: frame5 },
{ id: 6, source: frame6 },
{ id: 7, source: frame7 },
{ id: 8, source: frame8 },
]
const length = Images.length;
export default class Timer extends React.Component {
constructor(props){
super(props);
this.state = {
isOn: false,
}
this.animations = new Animated.Value(0);
this.opacity = [];
Images.map((item, index) => {
this.opacity.push(
this.animations.interpolate({
inputRange: [index - 1, index, index + 1],
outputRange: [0, 1, 0],
}),
);
});
}
onItemMouseDown = () => {
Animated.loop(
Animated.timing(this.animations, {
toValue: length - 1,
duration: 2000 * length,
easing: Easing.linear,
useNativeDriver: true,
}),
).start();
console.log(this.animations)
this.setState({
isOn:true,
}, () => {
console.log(this.state.isOn)
})
}
onItemMouseUp = () => {
this.setState({
isOn:false
}, () => {
console.log(this.state.isOn)
})
}
render() {
return(
<ImageBackground source={background} style={styles.background}>
<TouchableOpacity
onPressIn={this.onItemMouseDown}
onPressOut={this.onItemMouseUp}
>
<Text style={styles.touchbutton}>Touch this</Text>
</TouchableOpacity>
{this.state.isOn === true ?
<View style={styles.container}>
{/* <Image source={frame1}></Image> */} //I can render this image if this.state.isOn is true
{Images.map((item, index) => { //but this does not show ANYTHING!
const opacity = this.opacity[index];
{/* console.log(item)
console.log(index) */}
return(
<Animated.View
key={item.id}
style={[styles.anim, {animations: item, opacity}]}
/>
)
})}
</View>
: null }
</ImageBackground>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: 'center',
},
background: {
flex: 1,
resizeMode: "cover",
justifyContent: "center",
alignItems: 'center',
},
anim: {
width: 100,
height: 100,
},
touchbutton: {
flex: 1,
position: 'relative',
marginTop: 300,
},
touchbuttontest: {
flex:1,
position: 'relative',
marginTop: 200,
}
});
As mentioned, nothing appears. I'm not sure whether it's this bit:
<Animated.View
key={item.id}
style={[styles.anim, {animations: item, opacity}]}
/>
particularly the style line. I'm not sure that is correct. I don't fully understand what is going on there. I don't know what to put instead of animations: item. I think it should be a property of something but what, I don't know.
I've watched this and none of what is suggests works:
https://egghead.io/lessons/react-animate-styles-of-a-react-native-view-with-animated-timing

there is no problem in your code you can give backgroundColor:"red" in anim to check if it is working or not
you have to make position:"absolute" to container for start animation from top and you have to wrap image inside Animated.View
you can check demo here :https://snack.expo.io/#nomi9995/animation
import * as React from "react";
import {
StyleSheet,
Text,
View,
TouchableOpacity,
Image,
ImageBackground,
Animated,
Easing,
Platform,
} from "react-native";
import { frame1 } from "../app-master-test/assets/index";
import { frame2 } from "../app-master-test/assets/index";
import { frame3 } from "../app-master-test/assets/index";
import { frame4 } from "../app-master-test/assets/index";
import { frame5 } from "../app-master-test/assets/index";
import { frame6 } from "../app-master-test/assets/index";
import { frame7 } from "../app-master-test/assets/index";
import { frame8 } from "../app-master-test/assets/index";
import { background } from "../app-master-test/assets/index";
const Images = [
{ id: 1, source: frame1 },
{ id: 2, source: frame2 },
{ id: 3, source: frame3 },
{ id: 4, source: frame4 },
{ id: 5, source: frame5 },
{ id: 6, source: frame6 },
{ id: 7, source: frame7 },
{ id: 8, source: frame8 },
];
const length = Images.length;
export default class Timer extends React.Component {
constructor(props) {
super(props);
this.state = {
isOn: false,
};
this.animations = new Animated.Value(0);
this.opacity = [];
Images.map((item, index) => {
this.opacity.push(
this.animations.interpolate({
inputRange: [index - 1, index, index + 1],
outputRange: [0, 1, 0],
})
);
});
}
onItemMouseDown = () => {
Animated.loop(
Animated.timing(this.animations, {
toValue: length - 1,
duration: 2000 * length,
easing: Easing.linear,
useNativeDriver: true,
})
).start();
console.log(this.animations);
this.setState(
{
isOn: true,
},
() => {
console.log(this.state.isOn, "nominominomi");
}
);
};
onItemMouseUp = () => {
this.setState(
{
isOn: false,
},
() => {
console.log(this.state.isOn);
}
);
};
render() {
return (
<ImageBackground source={background} style={styles.background}>
<TouchableOpacity
onPressIn={this.onItemMouseDown}
onPressOut={this.onItemMouseUp}
>
<Text style={styles.touchbutton}>Touch this</Text>
</TouchableOpacity>
{this.state.isOn === true ? (
<View style={styles.container}>
{Images.map((item, index) => {
const opacity = this.opacity[index];
return (
<Animated.View
key={item.id}
style={[styles.anim, { animations: item, opacity }]}
>
<Image
source={item.source}
style={{ height: 100, width: 100, zIndex: 100 }}
/>
</Animated.View>
);
})}
</View>
) : null}
</ImageBackground>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: 'center',
position:"absolute"
},
background: {
flex: 1,
resizeMode: "cover",
justifyContent: "center",
alignItems: 'center',
},
anim: {
position:"absolute",
width: 100,
height: 100,
},
touchbutton: {
flex: 1,
position: 'relative',
marginTop: 300,
},
touchbuttontest: {
flex:1,
position: 'relative',
marginTop: 200,
}
});

Related

ReactiveSearch default query not enforced

Trying to apply a default query in the reactive search component and it doesn't have an effect
import React from 'react';
import {
NavigationScreenProps,
NavigationScreenConfig, NavigationActions,
} from 'react-navigation';
import {
ChatHeader,
ChatHeaderNavigationStateParams,
} from '#src/components/messaging';
import {
Conversation,
} from '#src/core/model';
import {conversation5} from '#src/core/data/conversation';
import {StyleSheet, Text, Image, TouchableWithoutFeedback} from 'react-native';
import {
ReactiveBase,
DataSearch,
ReactiveList,
} from '#appbaseio/reactivesearch-native';
import {ScrollView, View} from 'react-native';
import {Icon, ListItem} from '#kitten/ui';
import LottieView from 'lottie-react-native';
import {SearchHeader} from '#src/components/search/search.header';
import {userProvider} from '../../../../domain/auth/UserProvider';
import {Screen} from '../../../../core/navigation/screens';
import Tts from 'react-native-tts';
import {StarIconOutline} from '#src/assets/icons';
import axios, {AxiosError, AxiosResponse} from 'axios';
import {Config} from '../../../../constants/Config';
import {User} from '#domain/models';
import DoubleClick from 'react-native-double-tap';
import {Notification} from 'react-native-in-app-message';
import AnimatedLoader from 'react-native-animated-loader';
interface State {
newMessageText: string;
conversation: Conversation;
isLoading: boolean;
message: string;
}
const styles = StyleSheet.create({
container: {
padding: 10,
marginTop: 25,
},
image: {
width: 100,
height: 100,
},
result: {
flexDirection: 'row',
width: '100%',
margin: 5,
alignItems: 'center',
},
notification: {
flexDirection: 'row',
width: '100%',
margin: 5,
padding: 5,
alignItems: 'flex-start',
},
item: {
flexDirection: 'column',
paddingLeft: 10,
},
title: {
fontWeight: 'bold',
},
lottie: {
width: 100,
height: 100,
},
iconx: {
width: 50,
height: 40,
marginLeft: -3,
marginBottom: -10,
padding: 5,
},
notificationText: {
marginTop: 11,
},
});
export class SearchContainer extends React.Component<NavigationScreenProps, State> {
private notification: Notification;
private token: string;
public state: State = {
newMessageText: '',
conversation: conversation5,
isLoading: false,
message: '',
};
private infiniteAnimationIconRef: React.RefObject<Icon> = React.createRef();
static navigationOptions: NavigationScreenConfig<any> = ({navigation, screenProps}) => {
const headerProps: ChatHeaderNavigationStateParams = {
interlocutor: navigation.getParam('interlocutor', conversation5.interlocutor),
lastSeen: navigation.getParam('lastSeen', 'today'),
onBack: navigation.getParam('onBack'),
onProfile: navigation.getParam('onProfile'),
};
const header = (navigationProps: NavigationScreenProps) => {
return (
<SearchHeader
{...navigationProps}
{...headerProps}
/>
);
};
return {...navigation, ...screenProps, header};
};
public async componentWillMount(): void {
this.props.navigation.setParams({
onBack: this.onBackPress,
});
await userProvider.get().then((data) => {
this.token = data.token;
}).catch(() => {
this.props.navigation.navigate(Screen.Login);
});
}
public componentDidMount() {
this.setState({
isLoading: false,
});
}
private onBackPress = (): void => {
this.props.navigation.goBack(null);
};
private say(deText): void {
Tts.setDefaultLanguage('de-DE');
Tts.setDucking(true);
Tts.speak(deText);
}
private star(id): void {
this.setState({isLoading: true});
axios.post(Config.service.stars.url, {
sentence_id: id,
}, {
headers: {
'Authorization': `Bearer ${this.token}`,
},
}).then((response: AxiosResponse<UserData>) => {
this.setState({message: 'Star added!'});
setTimeout(() => this.notification.show(), 100);
this.setState({isLoading: false});
}).catch((error: AxiosError) => {
let errorMessage = null;
try {
const code = error.response.request.status;
if (code === 401) {
this.props.navigation.navigate(Screen.Login);
} else if (code === 422) {
errorMessage = 'Star was added already for this sentence!';
} else {
errorMessage = 'Service is unavailable, please try again in a few!';
}
} catch (e) {
errorMessage = 'Service is unavailable, please try again in a few!';
}
this.setState({...this.state, message: errorMessage});
setTimeout(() => this.notification.show(), 100);
this.setState({isLoading: false});
});
}
public render(): React.ReactNode {
return (
<ReactiveBase
app='myapp'
url='http://xxx.xxxxxx.io'
headers={{'X-Api-Key': 'xxxxxxxxxxxxxxxxxxxxxxxxx'}}>
<View>
<DataSearch
componentId='searchbox'
dataField={[
'sentence',
'sentence.en',
'sentence.de',
'raw.translated',
]}
value='1'
highlight={true}
placeholder='words or expressions'
defaultQuery={() => ({
query: {
match: {
message: {
query: 'test',
},
},
},
})}
autosuggest={false}
/>
</View>
<Notification
customComponent={(
<View style={styles.notification}>
<LottieView
style={styles.iconx}
source={require('#src/animations/warning.json')}
colorFilters={[{
keypath: 'button',
color: '#F00000',
}, {
keypath: 'Sending Loader',
color: '#F00000',
}]}
autoPlay
loop={true}
/>
<Text style={styles.notificationText}>{this.state.message}</Text>
</View>
)}
ref={(c) => this.notification = c}
/>
<AnimatedLoader
visible={this.state.isLoading}
overlayColor='rgba(255,255,255,0.75)'
source={require('#src/animations/loader.json')}
animationStyle={styles.lottie}
speed={1}
/>
<ScrollView
stickyHeaderIndices={[1]}
nativeID={'scoller'}
>
<View>
<ReactiveList
componentId='results'
dataField='sentence.de'
size={7}
showResultStats={false}
pagination={true}
infiniteScroll={true}
scrollTarget={'scroller'}
react={{
and: 'searchbox',
}}
defaultValue={'Harry Potter'}
onData={(res, idx) => (
<View style={styles.result} key={res._id}>
<DoubleClick
singleTap={() => {
this.star(res._id);
}}
doubleTap={() => {
}}
delay={1000}
>
<Icon name='star-outline' fill='#FF9999' width='30' height='50'/>
</DoubleClick>
<ListItem
onPress={() => this.say(res.sentence.de)}
title={res.sentence.de}
description={res.raw.translated}
/>
</View>
)}
/>
</View>
</ScrollView>
</ReactiveBase>
);
}
}
<DataSearch
componentId='searchbox'
dataField={[
'sentence',
'sentence.en',
'sentence.de',
'raw.translated',
]}
value='1'
highlight={true}
placeholder='words or expressions'
defaultQuery={() => ({
query: {
match: {
message: {
query: 'test',
},
},
},
})}
autosuggest={false}
/>
Try this (i.e. use filter instead of should):
<ReactiveComponent
componentId='filterbox'
customQuery={props => ({
query: {
'bool': {
'filter': [{
'ids': {
'type': 'mydoctype',
'values': ['TK6IRm4BK9UoLvJay0OC', 'Ra6IRm4BK9UoLvJaykMD'],
},
}]
},
}
})}
/>

Glitches with draggable components using react native - implemented using Animated and PanResponder

Drawing inspiration from this question, I have implemented two draggable components as children in a view. The parent view is as follows:
import React, { Component } from "react";
import { Text, View, StyleSheet, Dimensions } from "react-native";
import Draggable from "./Draggable";
export default class FloorPlan extends Component {
constructor() {
super();
const { width, height } = Dimensions.get("window");
this.separatorPosition = (height * 2) / 3;
}
render() {
return (
<View style={styles.mainContainer}>
<View style={[...styles.dropZone, { height: this.separatorPosition }]}>
<Text style={styles.text}>Floor plan</Text>
</View>
<View style={styles.drawerSeparator} />
<View style={styles.row}>
<Draggable />
<Draggable />
</View>
</View>
);
}
}
const styles = StyleSheet.create({
mainContainer: {
flex: 1
},
drawerSeparator: {
backgroundColor: "grey",
height: 20
},
row: {
flexDirection: "row",
marginTop: 25
},
dropZone: {
height: 700,
backgroundColor: "#f4fffe"
},
text: {
marginTop: 25,
marginLeft: 5,
marginRight: 5,
textAlign: "center",
color: "grey",
fontSize: 20
}
});
And the draggable component is implemented as follows:
import React, { Component } from "react";
import {
StyleSheet,
View,
PanResponder,
Animated,
Text,
Dimensions
} from "react-native";
export default class Draggable extends Component {
constructor() {
super();
const { width, height } = Dimensions.get("window");
this.separatorPosition = (height * 2) / 3;
this.state = {
pan: new Animated.ValueXY(),
circleColor: "skyblue"
};
this.currentPanValue = { x: 0, y: 0 };
this.panListener = this.state.pan.addListener(
value => (this.currentPanValue = value)
);
}
componentWillMount() {
this.state.pan.removeListener(this.panListener);
}
componentWillMount() {
this.panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => false,
onMoveShouldSetPanResponder: (evt, gestureState) => false,
onMoveShouldSetPanResponderCapture: (evt, gesture) => {
return true;
},
onPanResponderGrant: (e, gestureState) => {
this.setState({ circleColor: "red" });
},
onPanResponderMove: (event, gesture) => {
Animated.event([
null,
{
dx: this.state.pan.x,
dy: this.state.pan.y
}
])(event, gesture);
},
onPanResponderRelease: (event, gesture) => {
this.setState({ circleColor: "skyblue" });
if (gesture.moveY < this.separatorPosition) {
this.state.pan.setOffset({
x: this.currentPanValue.x,
y: this.currentPanValue.y
});
this.state.pan.setValue({ x: 0, y: 0 });
// this.state.pan.flattenOffset();
} else {
//Return icon to start position
this.state.pan.flattenOffset();
Animated.timing(this.state.pan, {
toValue: {
x: 0,
y: 0
},
useNativeDriver: true,
duration: 200
}).start();
}
}
});
}
render() {
const panStyle = {
transform: this.state.pan.getTranslateTransform()
};
return (
<Animated.View
{...this.panResponder.panHandlers}
style={[
panStyle,
styles.circle,
{ backgroundColor: this.state.circleColor }
]}
/>
);
}
}
let CIRCLE_RADIUS = 30;
let styles = StyleSheet.create({
circle: {
backgroundColor: "skyblue",
width: CIRCLE_RADIUS * 2,
height: CIRCLE_RADIUS * 2,
borderRadius: CIRCLE_RADIUS,
marginLeft: 25
}
});
A draggable component can be dragged onto the FloorPlan and it's location will be remembered for the next pan action. However, sometimes during dragging, a glitch occurs and the icon jumps at the beginning of the pan or completetely disappears.
What could be the problem? I am developing using React Native 0.55.2 and testing using a device running Android 7.

how to implement React native countdown circle

someone, please help me implementing countdown circle in react-native
I want the timer to start at 300 seconds goes down to 0 with an animated circle and text(time) inside that.
I tried using https://github.com/MrToph/react-native-countdown-circle
but here the issue is that text(time) is updated after one complete animation.
You can also see the issue I have opened there.
Below is the code snippet, of my implementation
<CountdownCircle
seconds={300}
radius={25}
borderWidth={3}
color="#006400"
bgColor="#fff"
textStyle={{ fontSize: 15 }}
onTimeElapsed={() =>
console.log('time over!')}
/>
I have changed the library file which you mentioned in your question. I know it's not good but I have tried to solve your problem.
import CountdownCircle from 'react-native-countdown-circle'//you can make your own file and import from that
<CountdownCircle
seconds={30}
radius={30}
borderWidth={8}
color="#ff003f"
bgColor="#fff"
textStyle={{ fontSize: 20 }}
onTimeElapsed={() => console.log("Elapsed!")}
/>
Here is library file which now you can use it as a component also here is that react-native-countdown-circle library file code(modified code)
import React from "react";
import {
Easing,
Animated,
StyleSheet,
Text,
View,
ViewPropTypes
} from "react-native";
import PropTypes from "prop-types";
// compatability for react-native versions < 0.44
const ViewPropTypesStyle = ViewPropTypes
? ViewPropTypes.style
: View.propTypes.style;
const styles = StyleSheet.create({
outerCircle: {
justifyContent: "center",
alignItems: "center",
backgroundColor: "#e3e3e3"
},
innerCircle: {
overflow: "hidden",
justifyContent: "center",
alignItems: "center",
backgroundColor: "#fff"
},
leftWrap: {
position: "absolute",
top: 0,
left: 0
},
halfCircle: {
position: "absolute",
top: 0,
left: 0,
borderTopRightRadius: 0,
borderBottomRightRadius: 0,
backgroundColor: "#f00"
}
});
function calcInterpolationValuesForHalfCircle1(animatedValue, { shadowColor }) {
const rotate = animatedValue.interpolate({
inputRange: [0, 50, 50, 100],
outputRange: ["0deg", "180deg", "180deg", "180deg"]
});
const backgroundColor = shadowColor;
return { rotate, backgroundColor };
}
function calcInterpolationValuesForHalfCircle2(
animatedValue,
{ color, shadowColor }
) {
const rotate = animatedValue.interpolate({
inputRange: [0, 50, 50, 100],
outputRange: ["0deg", "0deg", "180deg", "360deg"]
});
const backgroundColor = animatedValue.interpolate({
inputRange: [0, 50, 50, 100],
outputRange: [color, color, shadowColor, shadowColor]
});
return { rotate, backgroundColor };
}
function getInitialState(props) {
console.log();
return {
circleProgress,
secondsElapsed: 0,
text: props.updateText(0, props.seconds),
interpolationValuesHalfCircle1: calcInterpolationValuesForHalfCircle1(
circleProgress,
props
),
interpolationValuesHalfCircle2: calcInterpolationValuesForHalfCircle2(
circleProgress,
props
)
};
}
const circleProgress = new Animated.Value(0);
export default class PercentageCircle extends React.PureComponent {
static propTypes = {
seconds: PropTypes.number.isRequired,
radius: PropTypes.number.isRequired,
color: PropTypes.string,
shadowColor: PropTypes.string, // eslint-disable-line react/no-unused-prop-types
bgColor: PropTypes.string,
borderWidth: PropTypes.number,
containerStyle: ViewPropTypesStyle,
textStyle: Text.propTypes.style,
updateText: PropTypes.func,
onTimeElapsed: PropTypes.func
};
static defaultProps = {
color: "#f00",
shadowColor: "#999",
bgColor: "#e9e9ef",
borderWidth: 2,
seconds: 10,
children: null,
containerStyle: null,
textStyle: null,
onTimeElapsed: () => null,
updateText: (elapsedSeconds, totalSeconds) =>
(totalSeconds - elapsedSeconds).toString()
};
constructor(props) {
super(props);
this.state = getInitialState(props);
this.restartAnimation();
}
componentWillReceiveProps(nextProps) {
if (this.props.seconds !== nextProps.seconds) {
this.setState(getInitialState(nextProps));
}
}
onCircleAnimated = ({ finished }) => {
// if animation was interrupted by stopAnimation don't restart it.
if (!finished) return;
const secondsElapsed = this.state.secondsElapsed + 1;
const callback =
secondsElapsed < this.props.seconds
? this.restartAnimation
: this.props.onTimeElapsed;
const updatedText = this.props.updateText(
secondsElapsed,
this.props.seconds
);
this.setState(
{
...getInitialState(this.props),
secondsElapsed,
text: updatedText
},
callback
);
};
restartAnimation = () => {
Animated.timing(this.state.circleProgress, {
toValue:
parseFloat(JSON.stringify(this.state.circleProgress)) +
100 / this.props.seconds,
duration: 1000,
easing: Easing.linear
}).start(this.onCircleAnimated);
};
renderHalfCircle({ rotate, backgroundColor }) {
const { radius } = this.props;
return (
<View
style={[
styles.leftWrap,
{
width: radius,
height: radius * 2
}
]}
>
<Animated.View
style={[
styles.halfCircle,
{
width: radius,
height: radius * 2,
borderRadius: radius,
backgroundColor,
transform: [
{ translateX: radius / 2 },
{ rotate },
{ translateX: -radius / 2 }
]
}
]}
/>
</View>
);
}
renderInnerCircle() {
const radiusMinusBorder = this.props.radius - this.props.borderWidth;
return (
<View
style={[
styles.innerCircle,
{
width: radiusMinusBorder * 2,
height: radiusMinusBorder * 2,
borderRadius: radiusMinusBorder,
backgroundColor: this.props.bgColor,
...this.props.containerStyle
}
]}
>
<Text style={this.props.textStyle}>{this.state.text}</Text>
</View>
);
}
render() {
const {
interpolationValuesHalfCircle1,
interpolationValuesHalfCircle2
} = this.state;
return (
<View
style={[
styles.outerCircle,
{
width: this.props.radius * 2,
height: this.props.radius * 2,
borderRadius: this.props.radius,
backgroundColor: this.props.color
}
]}
>
{this.renderHalfCircle(interpolationValuesHalfCircle1)}
{this.renderHalfCircle(interpolationValuesHalfCircle2)}
{this.renderInnerCircle()}
</View>
);
}
}

Using a ScrollView to scroll when ScrollView contains draggable cards - REACT NATIVE

Hopefully you can help me with a bug I'm having a bit of bother sorting out. I'm working on a bug in an app built using React Native. It is building to IOS and Android. I have a ScrollView in a component that contains cards that are draggable objects.
These cards are dragged from the ScrollView they are in, up to buckets at the top of the screen. They disappear from the ScrollView and the remaining ones get reorganised so they stay ordered and neat. That works fine, you press on a box in the list and drag it to the buckets.
There is a bit of whitespace above the list of cards in the ScrollView. The ScrollView functionality works when swiping within this whitespace above the boxes, but I can't swipe on the boxes themselves without it beginning to drag the card.
Here is the component itself:
import React, { Component } from 'react';
import { StyleSheet, Text, View, ScrollView, Dimensions, Alert } from 'react-native';
import { connect } from 'react-redux';
import * as ConstStyles from '../../Consts/styleConsts';
import Bucket from '../Partials/bucketContainers';
import BusyIndicator from 'react-native-busy-indicator';
import loaderHandler from 'react-native-busy-indicator/LoaderHandler';
import CatCard from '../Partials/categoryCard';
import * as FeedActions from '../../../Redux/Feeds/actions';
import * as AuthFunctions from '../../Auth/functions';
export class SetupLikes extends Component {
static navigatorStyle = ConstStyles.standardNav;
constructor(props) {
super(props);
this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
this.card = [];
let button = {
leftButtons: [
{
title: 'Reset',
id: 'reset'
}
],
rightButtons: [
{
title: this.props.newAccount ? 'Go' : 'Done',
id: this.props.newAccount ? '' : 'skip',
disabled: this.props.newAccount
}
]
};
this.props.navigator.setButtons(button);
}
state = {
xOffset: 0,
positions: [],
placedCards: [],
loves: [],
okays: [],
hates: []
};
onNavigatorEvent(event) {
setTimeout(async () => {
if (event.type === 'NavBarButtonPress') {
if (event.id === 'skip') {
this.props.navigator.dismissModal({
animationType: 'slide-down'
});
} else if (event.id === 'reset') {
await this.imgTap();
} else if (event.id === 'go') {
await this.setInterests();
}
}
}, 0);
}
async setInterests() {
loaderHandler.showLoader('Setting your interests...');
let newInterests = [];
this.state.loves.forEach(function(element) {
let cat = this.props.Feeds.categories[element];
let newItem = {
categoryid: cat.id,
sentimentid: 1
};
newInterests.push(newItem);
}, this);
this.state.okays.forEach(function(element) {
let cat = this.props.Feeds.categories[element];
let newItem = {
categoryid: cat.id,
sentimentid: 0
};
newInterests.push(newItem);
}, this);
this.state.hates.forEach(function(element) {
let cat = this.props.Feeds.categories[element];
let newItem = {
categoryid: cat.id,
sentimentid: -1
};
newInterests.push(newItem);
}, this);
let sesId = this.props.User.sessionId;
try {
await this.props.dispatch(FeedActions.setMyInterests(sesId, newInterests));
loaderHandler.hideLoader();
} catch (err) {
loaderHandler.hideLoader();
Alert.alert('Uh oh', 'Something went wrong. Please try again later');
return;
}
await AuthFunctions.setupAppLogin(this.props.dispatch, sesId);
}
async imgTap() {
await this.setState({ placedCards: [], loves: [], okays: [], hates: [], positions: [] });
setTimeout(() => {
let cntr = 0;
this.card.forEach(function(element) {
cntr++;
if (this.state.placedCards.includes(cntr - 1)) return;
if (element) element.snapTo({ index: 0 });
}, this);
}, 5);
this.props.navigator.setButtons({
rightButtons: [
{
title: 'Go',
id: '',
disabled: true
}
],
animated: true
});
}
cardPlaced(id, droppedIndex) {
let newList = this.state.placedCards;
newList.push(id);
let cntr = 0;
let offset = 0;
let newPosIndex = [];
this.props.Feeds.categories.forEach(cats => {
let posY = (offset % 2) * -120 - 20;
let xOffset = Math.floor(offset / 2);
let posX = xOffset * 105 + 10;
newPosIndex[cntr] = {
x: posX,
y: posY,
offset: offset % 2
};
if (!newList.includes(cntr)) offset++;
cntr++;
});
if (droppedIndex === 1) {
let newLoves = this.state.loves;
newLoves.push(id);
this.setState({
loves: newLoves,
placedCards: newList,
positions: newPosIndex
});
} else if (droppedIndex === 2) {
let newOkays = this.state.okays;
newOkays.push(id);
this.setState({
okays: newOkays,
placedCards: newList,
positions: newPosIndex
});
} else if (droppedIndex === 3) {
let newHates = this.state.hates;
newHates.push(id);
this.setState({
hates: newHates,
placedCards: newList,
positions: newPosIndex
});
}
}
reShuffle() {
let cntr = 0;
this.card.forEach(function(element) {
cntr++;
if (this.state.placedCards.includes(cntr - 1)) return;
if (element) element.snapTo({ index: 0 });
}, this);
}
setButton() {
this.props.navigator.setButtons({
rightButtons: [
{
title: this.props.newAccount ? 'Go' : 'Done',
id: 'go'
}
],
animated: true
});
}
onChangeSize(scrollWidth, scrollHeight) {
let { height, width } = Dimensions.get('window');
let farRight = this.state.xOffset + width;
if (farRight > scrollWidth && farRight > 0) {
let xOffset = scrollWidth - width;
this.setState({ xOffset });
}
}
onSnap(index, id) {
this.cardPlaced(id, index);
this.reShuffle();
this.setButton();
if (this.props.Feeds.categories.length === this.state.placedCards.length)
setTimeout(async () => {
await this.setInterests();
}, 1);
}
renderCats() {
let cntr = 0;
var { height, width } = Dimensions.get('window');
let res = this.props.Feeds.categories.map(item => {
let ptr = cntr;
let posY = (cntr % 2) * -120 - 20;
let xOffset = Math.floor(cntr / 2);
let posX = xOffset * 105 + 10;
let vertPos = posY - 200 + ((cntr + 1) % 2) * -120;
posX = this.state.positions[ptr] ? this.state.positions[ptr].x : posX;
posY = this.state.positions[ptr] ? this.state.positions[ptr].y : posY;
let off = this.state.positions[ptr] ? this.state.positions[ptr].offset : ptr % 2;
cntr++;
if (this.state.placedCards.includes(cntr - 1)) return null;
item.key = cntr;
return (
<CatCard
key={ptr}
item={item}
ptr={ptr}
cntr={cntr}
xOffset={this.state.xOffset}
odd={off}
posX={posX}
posY={posY}
yDrop={vertPos}
screenWidth={width}
onSnap={(res, id) => this.onSnap(res, id)}
gotRef={ref => (this.card[ptr] = ref)}
/>
);
});
cntr = 0;
res.forEach(ele => {
if (ele !== null) ele.key = cntr++;
});
let test = this.props.Feeds.categories[0];
return res;
}
onScroll(res) {
this.setState({ xOffset: res.nativeEvent.contentOffset.x });
}
render() {
let colWidth = Math.ceil((this.props.Feeds.categories.length - this.state.placedCards.length) / 2) * 106;
return (
<View style={styles.container}>
<View style={styles.bucketContainer1}>
<Bucket
type={'Love'}
imageToUse={require('../../../img/waveLove.png')}
height={this.state.loveHeight}
count={this.state.loves.length}
backgroundColor={'rgb(238, 136, 205)'}
/>
</View>
<View style={styles.bucketContainer2}>
<Bucket
type={'OK'}
imageToUse={require('../../../img/waveOkay.png')}
height={this.state.okayHeight}
count={this.state.okays.length}
backgroundColor={'rgb(250, 179, 39)'}
/>
</View>
<View style={styles.bucketContainer3}>
<Bucket
type={'Dislike'}
imageToUse={require('../../../img/waveHate.png')}
height={this.state.hateHeight}
count={this.state.hates.length}
backgroundColor={'rgb(112, 127, 208)'}
/>
</View>
<View style={styles.descriptionContainer}>
<Text style={styles.dragLikesTitle}>Drag Likes</Text>
<View style={styles.dividingLine} />
<View>
<Text style={styles.descriptionText}>Drag your likes and dislikes into the bucket above,</Text>
<Text style={styles.descriptionText}>so we can generate your profile!</Text>
</View>
</View>
<ScrollView
ref={ref => (this.scroller = ref)}
onMomentumScrollEnd={res => this.onScroll(res)}
style={styles.scroller}
horizontal={true}
onContentSizeChange={(width, height) => this.onChangeSize(width, height)}
>
<View style={[styles.insideView, { width: colWidth }]}>{this.renderCats()}</View>
</ScrollView>
<BusyIndicator size={'large'} overlayHeight={120} />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignSelf: 'stretch',
alignItems: 'center',
backgroundColor: 'white'
},
bucketContainer1: {
position: 'absolute',
height: 130,
width: 95,
left: 10,
top: 5
},
bucketContainer2: {
position: 'absolute',
height: 130,
width: 95,
top: 5
},
bucketContainer3: {
position: 'absolute',
height: 130,
width: 95,
right: 10,
top: 5
},
insideView: {
width: 2500,
justifyContent: 'flex-end',
overflow: 'visible'
},
cardContainer: {
borderWidth: 1,
borderColor: 'rgb(200,200,200)',
borderRadius: 4,
alignItems: 'center',
width: 100,
backgroundColor: 'white'
},
catImage: {
height: 100,
width: 100,
borderTopRightRadius: 4,
borderTopLeftRadius: 4
},
button: {
backgroundColor: 'rgba(255,0,0,0.2)',
width: 90,
height: 50
},
scroller: {
height: '100%',
width: '100%',
overflow: 'visible'
},
card: {
position: 'absolute',
overflow: 'visible'
},
descriptionContainer: {
top: 140,
width: '100%',
alignItems: 'center',
position: 'absolute'
},
dividingLine: {
height: 1,
width: '100%',
borderWidth: 0.5,
borderColor: 'rgb(150,150,150)',
marginBottom: 5
},
dragLikesTitle: {
fontFamily: 'Slackey',
fontSize: 20,
color: 'rgb(100,100,100)'
},
descriptionText: {
fontSize: 12,
textAlign: 'center',
marginTop: 5
}
});
function mapStateToProps(state) {
return {
User: state.User,
Feeds: state.Feeds
};
}
export default connect(mapStateToProps)(SetupLikes);
Down at the bottom of the render function is where you'll see the ScrollView. It's rendering the categories via a function called renderCats.
It may be that because the cards I am rendering are draggable, that fixing this is an impossibility but I thought I would see if anyone has a better idea of how this may be fixed!
EDIT TO INCLUDE CatCard component...
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
ScrollView,
TouchableOpacity,
FlatList,
Image,
Platform,
Animated,
Easing,
Dimensions
} from 'react-native';
import * as Consts from '../../Consts/colourConsts';
import * as ConstStyles from '../../Consts/styleConsts';
import PropTypes from 'prop-types';
import Interactable from 'react-native-interactable';
import { CachedImage } from 'react-native-img-cache';
class CatCard extends Component {
state = {
initX: this.props.posX,
initY: this.props.posY,
zIndex: 1
};
onSnap(res, point) {
if (res.nativeEvent.index === 0) {
return;
}
let index = res.nativeEvent.index;
setTimeout(() => {
this.props.onSnap(index, point);
let end = new Date();
}, 100);
Animated.timing(this.opacity, {
toValue: 0,
duration: 100,
useNativeDriver: true
}).start();
}
constructor(props) {
super(props);
this.opacity = new Animated.Value(1);
this.height = Dimensions.get('window').height;
}
gotRef(ref) {
this.props.gotRef(ref);
}
render() {
let upY = this.props.posY + this.height + (1 - this.props.odd) * -120;
upY = upY * -1;
upY += 50;
return (
<Interactable.View
ref={ref => {
this.gotRef(ref);
}}
onSnap={res => this.onSnap(res, this.props.ptr)}
style={[styles.card, { zIndex: this.state.zIndex }]}
animatedNativeDriver={true}
dragToss={0.01}
snapPoints={[
{
x: this.props.posX,
y: this.props.posY,
damping: 0.7,
tension: 300,
id: '0'
},
{
x: this.props.xOffset + 10,
y: upY,
tension: 30000,
damping: 0.1
},
{
x: this.props.xOffset + 10 + this.props.screenWidth * 0.33,
y: upY,
tension: 30000,
damping: 0.1
},
{
x: this.props.xOffset + 10 + this.props.screenWidth * 0.66,
y: upY,
tension: 30000,
damping: 0.1
}
]}
initialPosition={{ x: this.state.initX, y: this.state.initY }}
>
<Animated.View
style={[styles.cardContainer, { opacity: this.opacity }]}
>
<CachedImage
source={{ uri: this.props.item.imageUrl }}
style={styles.catImage}
/>
<Text style={styles.cardText}>{this.props.item.name}</Text>
</Animated.View>
</Interactable.View>
);
}
}
CatCard.PropTypes = {
count: PropTypes.any.isRequired,
type: PropTypes.string.isRequired,
imageToUse: PropTypes.any.isRequired,
height: PropTypes.object.isRequired,
backgroundColor: PropTypes.string.isRequired
};
const styles = StyleSheet.create({
card: {
position: 'absolute',
overflow: 'visible'
},
cardContainer: {
borderWidth: 1,
borderColor: 'rgb(200,200,200)',
borderRadius: 4,
alignItems: 'center',
width: 100,
backgroundColor: 'white'
},
cardText: {
fontFamily: 'Slackey',
fontSize: 10
},
catImage: {
height: 100,
width: 98,
borderTopRightRadius: 4,
borderTopLeftRadius: 4
}
});
export default CatCard;
Without seeing CatCard it is hard to know how the dragging is implemented. If you are doing raw PanResponder then you'll need to keep a something in state that keeps track of whether the ScrollView is scrolling and pass that down as a prop to CatCard which would then disallow the drag if the prop were true.
Alternatively, I'd suggest using react-native-interactable. It's a little to wrap your head around but it's a great abstraction from PanResponder. They have loads of examples and I have used it to make a swipeable list item that worked great, even with touchables inside the item.

React Native: `Image` does show the `uri` source

Image doesn't show the uri source.
Image can show the require('') source.
I don't know the reason.
import React, {Component} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
ListView,
Image,
Dimensions,
ScrollView,
} from 'react-native';
const deviceWidth = Dimensions.get('window').width;
export default class AwesomeProject extends Component {
// Initialize the hardcoded data
constructor(props) {
super(props);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
imageArray1: [
{
url: 'http://insights.ubuntu.com/wp-content/uploads/8063/react-native-logo.jpg',
description: 'React Logo'
},
],
imageArray2: [
{
url: 'http://insights.ubuntu.com/wp-content/uploads/8063/react-native-logo.jpg',
description: 'React Logo'
},
{
url: 'http://insights.ubuntu.com/wp-content/uploads/8063/react-native-logo.jpg',
description: 'React Logo'
},
],
};
}
renderRow = (tempArray) => {
const imageStyleNumber = tempArray.length;
let imageStyleString;
switch (imageStyleNumber) {
case 1:
imageStyleString = `imgView1`;
break;
default:
imageStyleString = `imgView9`;
}
return tempArray.map((item, index) => {
if(index > 8){
return ;
}
return (
<View key={index} style={styles[imageStyleString]}>
<Image style={styles.imgIstyle} source={{uri: item.url}}/>
<Text style={styles.imgTDesc}>{item.description}</Text>
</View>
)
})
}
render() {
return (
<ScrollView style={styles.container}>
<View style={styles.rowVImageBox}>
{this.renderRow(this.state.imageArray1)}
</View>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#ebf0f2',
},
rowVImageBox: {
flexDirection:'row',
flexWrap:'wrap',
width: 300,
height: 300,
marginBottom:100,
},
rowVImageBox2: {
flexDirection:'row',
flexWrap:'wrap',
width: 300,
height: 300,
marginBottom:100,
backgroundColor:'blue',
},
imgView1: {
width:290,
height:290,
marginRight:5,
marginBottom:5,
},
imgView2: {
width:140,
height:290,
marginRight:5,
marginBottom:5,
},
imgIstyle:{
width:'100%',
height:'70%',
backgroundColor:'yellow',
},
imgTDesc: {
flex:2,
backgroundColor:'white'
}
});
AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);
Do you run it well?
I have asked my friend. He doesn't know the reason too.
modify the Info.plist.
iOS can load the http resource.