I want to create an overlay on top of react-native camera. However, I want only the center area to be clear and all other area to have some overlay with small opacity.
I have created component which acts as a wrapper and add corners, but I can't get overlay except in center. If I add overlay with background opacity it applies to whole screen including center box.
This is what I have so far.
<Camera style={[cameraStyle.camera]}>
<CustomView center style={[cameraMarkerStyles.container]}>
<CustomView
transparentBg
spaceBetween
style={[cameraMarkerStyles.cameraMarker]}
>
<CustomView row spaceBetween>
<CornerBox status={status} position="topLeft" />
<CornerBox status={status} position="topRight" />
</CustomView>
<CustomView row spaceBetween>
<CornerBox status={status} position="bottomLeft" />
<CornerBox status={status} position="bottomRight" />
</CustomView>
</CustomView>
<CustomView
style={[cameraMarkerStyles.container, cameraMarkerStyles.overlay]}
/>
</CustomView>
</Camera>
Bascially I add a View which is center area, which has 4 boxes at all corners which create the border. And then at the end there is a View which acts as overlay for whole screen. Now that last View if I change the background color to something other than transparent, it covers center area as well.
I have tried changing zIndex, set it to -1 as well. However that also did not work.
One very dirty solution that I have is I can place a View above center area and below center area and on each side of it and then give those views as some background and opacity. In that way we can add overlay just apart from center area.
Does anyone know any good way to implement such kind of layout? Even simple idea is enough, I don't need whole code.
Adding styles just in case anyone needs to see.
const markerSize = 250
const cornerBoxSize = 50
const cornerBoxBorderSize = 5
const cameraMarkerStyles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
},
overlay: {
zIndex: -1,
backgroundColor: 'rgba(0, 0, 0, 0.2)',
},
cameraMarker: {
width: markerSize,
height: markerSize,
},
cornerBox: {
width: cornerBoxSize,
height: cornerBoxSize,
},
topLeftBox: {
borderTopWidth: cornerBoxBorderSize,
borderLeftWidth: cornerBoxBorderSize,
},
})
const cameraStyle = StyleSheet.create({
camera: {
height: Dimensions.get('screen').height,
backgroundColor: 'transparent',
},
})
we talked about this on Twitter but I wanted to make sure the proposed solution was logged...
I suggest you create four translucent gray boxes for the four sides of the screen. The center of the screen will be blank and those four boxes will form a mask on each side of the center-area
Related
For context, I'm trying to make a progress circle following this article; essentially, I'm overlaying coloured semi-circles made from borders on top of a base circular border to represent progress. These semi-circle borders are theoretically made by setting the bottom and left borders to transparent, but when I do this the entire border disappears.
This is the simplified portion of the code that I'm working with:
import { StyleSheet, View } from 'react-native';
export default function App() {
return (
<View style={styles.semicircle}></View>
);
}
const styles = StyleSheet.create({
semicircle: {
width: 200,
height: 200,
borderWidth: 20,
position: 'absolute',
borderLeftColor: 'transparent',
borderBottomColor: 'transparent',
borderRightColor: '#3498db',
borderTopColor: '#3498db',
borderRadius: 100
}
});
When I set the transparent border sides to black instead, the entire circle is visible like so, but having any transparent borders causes the entire border to disappear. How do I fix this? Any help would be greatly appreciated.
I'm using React Navigation and trying to apply a linear gradient from white to transparent to the tab navigator and have it sit at the bottom of the screen.
I've found a good solution for using react-native-linear-gradient with a navigation header here: React Navigation - Gradient color for Header
What isn't clear to me is how to apply this same logic to the tabBar. I tried defining a component like in the linked example and then passing that to backgroundColor, but it threw an error.
Here's my current code for the tabBarOptions:
{
tabBarOptions: {
activeTintColor: 'rgba(248, 164, 2, 0.6)', // Color of tab when pressed
inactiveTintColor: 'rgba(0,0,0,0.5)', // Color of tab when not pressed
showLabel: false,
indicatorStyle: {
backgroundColor: 'transparent'
},
style: {
backgroundColor: 'rgba(255, 255, 255, 1.0)',
borderTopColor: 'transparent',
height: dynamicSize(60),
position: 'absolute',
left: 0,
right: 0,
bottom: 0
},
},
},
I then pass this into the StackNavigator by defining tabs as:
tabs: {
screen: TabVisibleNavigator
},
Decided to go with a hack that seems to work fine:
In the tabBarOptions style set backgroundColor to transparent; positioning to absolute
Create gradient png image, save as an asset in the project
Load png as an element in the bottom of the main View container
Set png style as absolute so that it renders over the background container view
This will load a transparent tab bar over a gradient image. Not the most elegant solution but hopefully it helps someone stuck on the same problem.
this is my component:
const styles = {
menuContainer: {
flex: 1,
flexDirection: 'column'
},
menuItem: {
flex: 1,
borderRadius: ??
}
}
<View style={styles.menuContainer}>
<TouchableOpacity {styles.menuItem}/>
<TouchableOpacity {styles.menuItem}/>
</View>
bordeRadius in react native doesn't work with percentage like 50% and in flex box i don't know the width of each flexItem. do you have any idea without calculate width of each flexItem?
Bad news, If you don't know the container's dimensions ahead of time, then I think you're only option is to use onLayout to calculate each flex container's dimensions.
{nativeEvent: { layout: {x, y, width, height}}}
If you can declare a fixed width & height, then it's easy, but sounds like this isn't going to be news to you.
circle: {
width: 100,
height: 100,
borderRadius: 100/2
}
There's a feature request submitted on this feature already. Show your support by up-voting it here...
https://react-native.canny.io/feature-requests/p/borderradius-percentages
Sorry!
I think that we cannot give border-radius to the flex so we can use width and height by getting device Dimensions and give the border-radius to the view.
So, I want to create a layout similar to whats below. [Refer the Image]
So the background has a full screen MapView (React Native Maps) with Markers over it, which needs to be clickable.
And there is a Scrollview with full screen height over the MapView which initially has some top-margin associated with its contents.
But the issue if I arrange my Views this way, the Markers on the map are not clickable in the initial state.
<View>
<MapView>
<Marker clickEventHere></Marker>
<Marker clickEventHere></Marker>
</MapView>
<ScrollView fullscreen>
<View marginTop></View>
</ScrollView>
<View>
I am unsure if its really possible to solve this out.
Initial State
After Scrolling
Solution Tried
yScrolled = event.nativeEvent.contentOffset.y;
yValue = this.state.yValue - yScrolled;
upwardScroll = yScrolled > 0;
if(upwardScroll && (yValue > 0)){
this.setState({
yValue: yValue
});
}
if(yScrolled === 0){
yScrolled = -10;
}
if(!upwardScroll && (yValue <= scrollViewMarginTop)){
yValue = this.state.yValue - yScrolled;
console.debug("UPDATE DOWNWARD");
this.setState({
yValue: yValue
});
}
I'd start with adding absolute positioning to your ScrollView, (position: absolute) starting at whatever y coordinate you would like. I would make this y value a state, eg
yValue: new Animated.Value(start_value) or simply yValue: start_value
I would then use ScrollView's prop onScroll event to handle the change in this y coordinate, for example for the first 100 pixels of a scroll it would simply change the yValue instead of scrolling the view.
This should enable you to press the markers you have in your parent view, and use the same component structure that you have provided.
Note: You would need to do this for collapsing the scrollview also.
Note2: if this doesn't give you the result you were looking for, i'd suggest looking into using some sort of collapsable component for this task, eg https://github.com/oblador/react-native-collapsible
Hope this helps
EDIT: To collapse the scrollview you could first identify if the scroll direction is downwards ( which i think youve done via upwardScroll ) and then..
1) Either simply add the content offset to your yValue
2) If you used Animated.Value for yValue, you can have an animate function that animates the scrollview downwards to your desired position. I think this would look nicer as the user would only need a simple downwards flick to collapse the view, which seems like the industry standard.
There is also a library that is called react-native-touch-through-view that can do this for you. This it how it works basically:
<View style={{ flex: 1 }}>
// Your map goes here
</View>
<TouchThroughWrapper style={{
position: 'absolute'',
top: 0,
left: 0,
width: '100%',
height: '100%',
}}>
<ScrollView
style={{
backgroundColor: 'transparent',
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
// Maybe in your case is flex: 1 enough
}}
bounces={false}
showsVerticalScrollIndicator={false}
>
<TouchThroughView
style={{
height: 400, // This is the "initial space" to the top
}}
/>
// The "slide up stuff" goes here
</ScrollView>
</TouchThroughWrapper>
For example, this then can look like this:
So the map is overlayed by the TouchThroughView that passes all the events right to the view behind. In my case this worked better than using pointer-events box-none.
In my app I'm using <ScrollView /> to view pages of a book scrolling horizontally. When a user gets to the end of the <ScrollView /> there is a bounce that shows a white area to the right that is only visible if the user drags the last page to the left. I want to add some text there that says "The End" vertically. How can I add content to the right of the <ScrollView /> in the bounce area?
I ALMOST figured it out. This is close but shows up in the right side of the last page but not off the page on the right in the bounce area. I want it to show up "to the right of the page" not "on the right side of the page." Any other ideas?
Create a <View style={styles.end} /> with this style:
theEnd: {
position: 'absolute',
top: 0,
right: 0,
width: 100,
height: 768, // Device height
alignItems: 'center',
}
Place it right before the <ScrollView /> and put whatever you want to show inside of the View component with the "theEnd" style.
This probably doesn't apply to your content, but I had the same situation except with a large image for the ScrollView content. I wanted both horizontal and vertical scrolling, where the edge of the image would show up only in the bounce margin. I figured out that the scale transformation works great for this:
<ScrollView horizontal={true}>
<Image
source={require('./img/map.jpg')}
style={{transform: [{scale: 1.1}]}}
/>
</ScrollView>
So the image takes up 110% of the height and width of its box (which is then inside a yet smaller ScrollView).
EDIT: FYI, after testing, discovered this only works on iOS, not Android. (Android won't allow vertical scrolling if you set horizontal to true, and also I think it didn't render the parts outside of the normal viewing area, so the bounce margin was empty.)
there is a prop for this called contentContainerStyle
<ScrollView
horizontal={true}
contentContainerStyle={{
paddingLeft: 25,
paddingRight: 25,
}}>
*** CONTENT ***
</ScrollView>