I am not able to display images (both from the assets and web) in custom marker callout : the image in callout is always shown as a blank rectangle.
class CustomCalloutView extends React.Component {
render() {
return (
<View>
<View>
<Text style={{
fontWeight: "bold",
}}>
Test
</Text>
</View>
<View>
<Image
source={{ uri: 'https://facebook.github.io/react/logo-og.png' }}
style={{ width: 100, height: 100 }}
/>
</View>
</View>
)
}
}
And the main Map component is:
<MapView
style={{ flex: 1 }}
initialRegion={{
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}>
{this.state.markers.map(marker => (
<Marker
key={marker.id}
coordinate={marker.latlng}>
<Callout>
<CustomCalloutView />
</Callout>
</Marker>
))}
</MapView>);
The marker is correctly shown, and the callout renders, but the image is not shown. The same image works if i use it in a normal view.
I am using expo (expo.io) but also tried emulator and installed APK on the device (android; no info about ios).
Use Image inside Text component.
Something like this:
<Text>
<Image style={{ height: 100, width:100 }} source={{ ... }} resizeMode="cover" />
</Text>
Another workaround by using WebView.
I think is the proper solution for this right now.
<View>
<WebView style={{ height: 100 , width: 230, }} source={{ uri: ... }} />
</View>
Positioning the <Image/> was a bit challenge in the custom Callout for Android. It's a bit mystery for Android, IMHO. Especially, with the trick to display it by wrapping around Text. Looks like, it affects the styling, too. I've had to figure out monotonously the https://reactnative.dev/docs/image#resizemode with this "fix" along with some custom styling what works, pff.
I've ended up with 2 different styles, one for Android, one for iOS.
{Platform.OS === "android" ? <Text style={styles.imageWrapperAndroid}>
<Image
resizeMode="cover"
source={
event.imageUrl
? { uri: event.imageUrl }
: require("../assets/images/no-image.jpeg")
}
style={styles.imageAndroid}
/>
</Text> : <Image
source={
event.imageUrl
? { uri: event.imageUrl }
: require("../assets/images/no-image.jpeg")
}
style={styles.imageIOS}
/>}
...
const styles = StyleSheet.create({
imageAndroid: {
height: 200,
width: 330,
},
imageIOS: {
height: "50%",
width: "100%",
},
imageWrapperAndroid: {
height: 200,
flex: 1,
marginTop: -85,
width: 330,
},
...
});
Related
Everyone.
I need your help.
I made one app with react native expo cli.
But one issue occurred.
I used the ScrollView for horizontal pagination.
*<SafeAreaView>
<ScrollView
snapToInterval={wp("100%")}
horizontal
pagingEnabled
nestedScrollEnabled
decelerationRate="fast"
>
{[...Array(this.state.pageCount)].map((num, index) => {
return (
<View
key={"view" + index}
style={{
width: wp("100%"),
height: "100%",
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
alignContent: "center",
justifyContent: "center",
}}
>
{this.state.categories
.slice(index * 6, index * 6 + 6)
.map((item, key) => (
<TouchableOpacity
key={"touch" + key}
style={styles.itemStyle}
onPress={() => this.openModal(item)}
onLongPress={() => this.selectItem(item)}
>
<Image
source={{ uri: item.Foto }}
style={{ height: 120, width: "90%" }}
resizeMode="cover"
/>
<Text style={{ fontSize: 18 }}>{item.Precio}</Text>
<Text style={{ fontSize: 12 }}>{item.Gemas}</Text>
</TouchableOpacity>
))}
</View>
);
})}
</ScrollView>
</SafeAreaView>*
But the pagination only works on Android Phone and doesn't work on iPhone.
Please help me.
Your <ScrollView> should have style flex: 1, to allow the view fit the screen size.
The width of the Views inside the Scroll should have a numerical value. A width of 100% inside a scrollview is undefined. Your approach should be related to the dimension of the screen.
// import dimensions lib
import Dimensions from 'react-native';
...
...
...
// capture the width of the screen
const screenWidth = Dimensions.get('screen').width;
...
...
...
{[...Array(this.state.pageCount)].map((num, index) => {
return (
<View
key={"view" + index}
style={{
width: screenWidth,
height: "100%",
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
alignContent: "center",
justifyContent: "center",
}}
>
{this.state.categories
.slice(index * 6, index * 6 + 6)
.map((item, key) => (
<TouchableOpacity
key={"touch" + key}
style={styles.itemStyle}
onPress={() => this.openModal(item)}
onLongPress={() => this.selectItem(item)}
>
<Image
source={{ uri: item.Foto }}
style={{ height: 120, width: "90%" }}
resizeMode="cover"
/>
<Text style={{ fontSize: 18 }}>{item.Precio}</Text>
<Text style={{ fontSize: 12 }}>{item.Gemas}</Text>
</TouchableOpacity>
))}
</View>
);
})}
I use srcollview to nest flatlist to render data. After the rendering is successful, however, when running on Android, the view cannot be scrolled, but running on IOS does not.
<View >
<FlatList
data={categoryState}
renderItem={item => <ItemCombination data={item} click={loading} detail={detail} />}
listKey={(item, index) => index.toString()}
numColumns={3}
ListFooterComponent={
<View style={{ width: 794, backgroundColor: '#fff', alignItems: 'center', maxHeight: 300 }} >
{
show ?
showLoading ?
<ActivityIndicator color='#21b6a8' size='large' style={{ marginVertical: 20 }} />
:
{/* unable to scroll */}
<ScrollView style={{ width: Platform.OS === 'web' ? 780 : 794, height: 300 }} showsVerticalScrollIndicator={true} contentContainerStyle={{ alignItems: 'center' }}>
{/* unable to scroll */}
<FlatList
data={menuItems}
renderItem={item => <Item data={item} click={menuItemClick} categoryId={categoryId} />}
keyExtractor={(item, index) => item.id + index.toString()}
numColumns={3}
showsVerticalScrollIndicator={false}
/>
</ScrollView>
:
<View></View>
}
</View>
}
/>
</View>
you can use the built-in nestedscrollenabled prop for the children FlatList component.
<FlatList nestedScrollEnabled />
Nested scrolling is supported by default on iOS. so for android you need to add this.
Flatlist in ListFooterComponent won't work in Android because It has Flatlist's scroll property which scrolls the container of the list with a footer also. Some workaround is like
<FlatList
......
ListFooterComponent={
<View style={{ width: 794, backgroundColor: '#fff', alignItems: 'center', maxHeight: 300 }} >
{
show ?
showLoading ?
<ActivityIndicator color='#21b6a8' size='large' style={{ marginVertical: 20 }} />
:
{/* remove scroll and have map on items to render data footer */}
menuItems.map(item => { render <View> ...</View> }
:
}
</View>
}
/>
I am having a problem with react-native paper list accordion it is not working on android! I mean the list is showing but not when you click the accordion :(. on ios everything is working fine! any idea on how I can solve that :( thx
I am using the latest android version on sumsung
<List.Accordion
key={id}
theme={{ colors: { primary: '#4169e1' } }}
style={{ backgroundColor: 'white', marginBottom: 1 }}
onPress={() => { LayoutAnimation.easeInEaseOut(); }}
title={title}>
<Divider />
<List.Item
titleStyle={styles.textContainer}
title={
<View>
<Text style={styles.text}>{text}</Text>
</View>
} key={index} />
</List.Accordion>
You need to put your <List.Accordion> item inside the <List.AccordionGroup> or <List.Section>
<List.AccordionGroup title={title} key={id}>
<List.Accordion
key={id}
theme={{ colors: { primary: '#4169e1' } }}
style={{ backgroundColor: 'white', marginBottom: 1 }}
onPress={() => { LayoutAnimation.easeInEaseOut(); }}
title={title}>
<Divider />
<List.Item
titleStyle={styles.textContainer}
title={
<View>
<Text style={styles.text}>{text}</Text>
</View>
} key={index} />
</List.Accordion>
</List.AccordionGroup>
I am following the tutorial in the link: https://medium.com/appandflow/react-native-scrollview-animated-header-10a18cb9469e .
However I can't seem to understand how to add tabs to this such that the tab headers get fixed to top when scrolled up. Can anyone please suggest how to achieve this?
I was able to achieve it using ScrollableTab and Tab in native-base library.
Code looks like this
<Tabs
prerenderingSiblingsNumber={3}
onChangeTab={({ i }) => {
this.setState({ height: this.heights[i], activeTab: i })
}}
renderTabBar={(props) => (
<Animated.View style={{ transform: [{ translateY: tabY }], zIndex: 1, width: "100%", backgroundColor: "white", paddingTop: HEADER_MAX_HEIGHT }}>
<ScrollableTab
{...props}
renderTab={(name, page, active, onPress, onLayout) => (
<TouchableOpacity key={page}
onPress={() => onPress(page)}
onLayout={onLayout}
activeOpacity={0.4}>
<Animated.View
style={{
flex: 1,
height: 100,
backgroundColor: tabBg
}}>
<TabHeading scrollable
style={{
backgroundColor: "transparent",
width: Dimensions.get('window').width / 2
}}
active={active}>
<Animated.Text style={{
fontWeight: active ? "bold" : "normal",
color: 'black',
padding: 10,
fontSize: active ? 20 : 18
}}>
{name}
</Animated.Text>
</TabHeading>
</Animated.View>
</TouchableOpacity>
)}
underlineStyle={{ backgroundColor: 'black' }}
/>
</Animated.View>
)}>
<Tab heading="Tab 1">
{this.tabContent(30, 0)}
</Tab>
<Tab heading="Tab 2">
{this.tabContent(15, 1)}
</Tab>
</Tabs>
use this:
expo install react-native-gesture-handler react-native-reanimated
Then basic usage look like this to replace in <Animated.View ......<Text>....</Text>..... ></Animated.View>:
<TabView
navigationState={{ index, routes }}
onIndexChange={setIndex}
renderScene={SceneMap({
first: FirstRoute,
second: SecondRoute,
})}
/>
I hope it'll help you..!
In case anybody else falls on this thread, I developed a new package, react-native-animated-screen, that does exactly what you need
Check it out
https://www.npmjs.com/package/react-native-animated-screen
import React from 'react';
import { Image, Text, View } from 'react-native';
import AnimatedScreen from 'react-native-animated-screen';
const Component = () => {
return (
<AnimatedScreen.Wrapper>
<AnimatedScreen.Header>
<View>
<Text>Title</Text>
<AnimatedScreen.CollapsibleElement>
<Text>Subtitle</Text>
</AnimatedScreen.CollapsibleElement>
<AnimatedScreen.Element>
<YourTabsComponen />
</AnimatedScreen.Element>
</View>
</AnimatedScreen.Header>
<AnimatedScreen.ScrollView>
<View style={{ height: '300%' }}>
<View>
<Text>Body</Text>
</View>
</View>
</AnimatedScreen.ScrollView>
</AnimatedScreen.Wrapper>
);
};
In the example above only the title and YourTabBComponentare going to remain after scrolling, the subtitle (as all the elements wrapped in a CollapsibleElement) will disappear.
Ideally you could also have the tabs to appear only when entirely scrolled using the interpolate prop or the animatedStyle of the AnimatedScreen.Element
// using interpolate the animation will flow from 0 to scrollY === headerMaxHeight
<AnimatedScreen.Element interpolate={{ opacity: [0, 1], height: [0, 60] }}>
<TabComponent />
</AnimatedScreen.Element>
// alternatevely you can have more control with an animatedStyle
<AnimatedScreen.Element animatedStyle={scrollY => ({
opacity: scrollY.interpolate({
inputRange: [100, 200],
outputRange: [0, 1]
extrapolate: 'clamp'
})
})}>
<TabComponent />
</AnimatedScreen.Element>
In case anybody else falls on this thread, I developed a new package, react-native-animated-screen, that does exactly what you need
Check it out
https://www.npmjs.com/package/react-native-animated-screen
import React from 'react';
import { Image, Text, View } from 'react-native';
import AnimatedScreen from 'react-native-animated-screen';
const Component = () => {
return (
<AnimatedScreen.Wrapper>
<AnimatedScreen.Header>
<View>
<Text>Title</Text>
<AnimatedScreen.CollapsibleElement>
<Text>Subtitle</Text>
</AnimatedScreen.CollapsibleElement>
<AnimatedScreen.Element>
<YourTabsComponen />
</AnimatedScreen.Element>
</View>
</AnimatedScreen.Header>
<AnimatedScreen.ScrollView>
<View style={{ height: '300%' }}>
<View>
<Text>Body</Text>
</View>
</View>
</AnimatedScreen.ScrollView>
</AnimatedScreen.Wrapper>
);
};
In the example above only the title and YourTabBComponentare going to remain after scrolling, the subtitle (as all the elements wrapped in a CollapsibleElement) will disappear.
Ideally you could also have the tabs to appear only when entirely scrolled using the interpolate prop or the animatedStyle of the AnimatedScreen.Element
// using interpolate the animation will flow from 0 to scrollY === headerMaxHeight
<AnimatedScreen.Element interpolate={{ opacity: [0, 1], height: [0, 60] }}>
<TabComponent />
</AnimatedScreen.Element>
// alternatevely you can have more control with an animatedStyle
<AnimatedScreen.Element animatedStyle={scrollY => ({
opacity: scrollY.interpolate({
inputRange: [100, 200],
outputRange: [0, 1]
extrapolate: 'clamp'
})
})}>
<TabComponent />
</AnimatedScreen.Element>
I want to achieve a behavior like android's CoordinatorLayout enter always for my ToolBar i tried too many solutions some did work but not fully like https://github.com/maolion/mao-rn-android-kit which is really cool but with one setback as it doesn't work with ListView i also tried Animated but the scroll event throttle on android is just not working most of the times it does not even work.
Using mao-rn-android-kit
<CoordinatorLayoutAndroid ref={(component) => this.coordinatorLayout = component} fitsSystemWindows={false}>
<AppBarLayoutAndroid
layoutParams={{
width: 'match_parent',
height: 112
}}
style={{ backgroundColor:"#528eff" }}>
<View layoutParams={{height: 56, width: this.windowWidth, scrollFlags: (
AppBarLayoutAndroid.SCROLL_FLAG_SCROLL |
AppBarLayoutAndroid.SCROLL_FLAG_ENTRY_ALWAYS)}} style={{height: 56}}>
<ToolbarAndroid
titleColor={'#FFF'}
title={this.props.title}
navIcon={images.arrowBack}
onIconClicked={() => this._goBack()}
onActionSelected={() => {}}
actions={[{title: 'Search', icon: images.search, show: 'always'}]}
style={[{backgroundColor: '#528eff', width: this.windowWidth, height: 56}]}/>
</View>
<View layoutParams={{height: 56, width: this.windowWidth}}
style={{flex: 0, flexDirection: 'row', justifyContent: 'center', width: this.windowWidth, backgroundColor: '#528eff'}}>
<TouchableOpacity onPress={() => this.getDocuments('high')}
style={[styles.highNormalLowDocListHeaderStateTextContainer, highSelected.borderStyle]}>
<Text
style={[styles.highNormalLowDocListHeaderStateText, highSelected.textStyle]}>HIGH</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.getDocuments('normal')}
style={[styles.highNormalLowDocListHeaderStateTextContainer, normalSelected.borderStyle]}>
<Text
style={[styles.highNormalLowDocListHeaderStateText, normalSelected.textStyle]}>NORMAL</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.getDocuments('low')}
style={[styles.highNormalLowDocListHeaderStateTextContainer, lowSelected.borderStyle]}>
<Text
style={[styles.highNormalLowDocListHeaderStateText, lowSelected.textStyle]}>LOW</Text>
</TouchableOpacity>
</View>
</AppBarLayoutAndroid>
<View
ref={(component) => this.contentLayout = component}
style={{flex: 1, backgroundColor: 'transparent', height: this.windowHeight - 150}}>
<ListView
style={{height: this.windowHeight - 150, overflow: 'hidden'}}
dataSource={this.state.documents}
enableEmptySections={true}
renderRow={(rowData) => this._renderRow(rowData)}
/>
</View>
</CoordinatorLayoutAndroid>
The key to reacting to the scroll position fluidly is using Animated.event along with the onScroll to update an Animated.value
getInitialState: function() {
return {
scrollY: new Animated.Value(0)
}
},
render() {
return (
<ScrollView
scrollEventThrottle={16}
onScroll={Animated.event(
[{nativeEvent:
{contentOffset:
{y: this.state.scrollY}
}
}]
)}>
// etc ...
}
I could then call interpolate on this.state.scrollY and feed this value into a transform style on another component that I wanted to update as the ScrollView scrolled.