horizontal scrollview inside react native drawer - react-native

I was asked to add an horizontal scrollview inside of a drawer. (Think Instagram stories but in a drawer.) The animation works very inconsistent. The most annoying is swiping to the left, the scrollview often doesn't scroll and the drawer starts the closing animation instead.
The drawer already exists for awhile, so setup issues are not the problem.
Here is my code:
// Drawer.navigator
const DrawerContent = () => {
// UI of the drawer
return <Drawer activeRoute={activeRoute} />;
};
return (
<DrawerNav.Navigator
drawerContent={DrawerContent}
drawerStyle={{ width: 320 }}
initialRouteName="Home"
drawerContentOptions={{
someColor: theme.someColor,
}}
>
// other screens
</DrawerNav.Navigator>
import { ScrollView } from 'react-native';
const Container = styled.View`
height: 62.5px;
flex-direction: row;
align-items: center;
justify-content: center;
`;
const ThingWrapper = styled(Flex)`
height: 62.5px;
align-items: center;
justify-content: center;
.lastBubble {
margin-right: 16px;
}
`;
...
<Container>
<ScrollView
horizontal
vertical={false}
directionalLockEnabled
nestedScrollEnabled
showsHorizontalScrollIndicator={false}
pinchGestureEnabled={false}
contentContainerStyle={{
zIndex: 9999,
}}
>
{thingsToRender.map((thing, index) => {
return (
<ThingWrapper>
<AnyThing thingId={thing.id} />
</ThingWrapper>
);
})}
</ScrollView>
</Container>
I think element focus might be the main problem here, but I don't know how to fix this. Any help is greatly appreciated. Thanks!

I fixed it by creating this object and giving it as a param to every screen. As a con this disable the drawer swipe open/close.
const drawerScreenOptions = {
gestureEnabled: true,
swipeEnabled: false,
};
// Drawer.navigator
const DrawerContent = () => {
// UI of the drawer
return <Drawer activeRoute={activeRoute} />;
};
return (
<DrawerNav.Navigator
drawerContent={DrawerContent}
drawerStyle={{ width: 320 }}
initialRouteName="Home"
>
// !! Give options to all screens
<DrawerNav.Screen
name="screenX"
component={ScreenXNavigator}
options={drawerScreenOptions}
/>
</DrawerNav.Navigator>

Related

How can I use Pressable inside Animated in React native?

I applied Animated.View to the Card component and ScrollView to the CardMain component. And pressable is applied to the child component, called ModeContainer. In ModeContainer, changemodefunc is executed when onPress is triggered.
When I run in emulator and press ModeContainer(Pressable), onPress runs fine, changemodefunc works fine. However, problem is if I connect it to a real device and run it, it will not run even if I press ModeContainer(Pressable). How do we solve this problem?
i'm using window and Emulator
this is my code
import {
Animated,
View,
ScrollView,
} from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
const Container = styled(LinearGradient)`
flex: 1;
justify-content: center;
align-items: center;
`;
const SecondContainer = styled.View`
flex: 9.1;
`;
const Card = styled(Animated.createAnimatedComponent(View))`
flex: 1;
`;
const CardWapper = styled(LinearGradient)`
flex: 1;
`;
const CardMain = styled(ScrollView)`
flex: 9;
`;
const ModeWrapper = styled.View`
flex:1;
`;
const ModeContainer = styled.Pressable`
`;
const IconCon = styled.Pressable`
width: 50px;
`;
<Container
>
<SecondContainer
>
<Card
style={{
transform: [...POSITION.getTranslateTransform()],
}}
>
<CardWapper>
<CardMain>
<ModeWrapper>
(
<ModeContainer
onPress={() => changemodefunc('black')}>
<IconCon
>
</IconCon>
</ModeContainer>
)
</ModeWrapper>
</CardMain>
</CardWapper>
</Card>
</SecondContainer>
</Container>

WebView inconsistently showing white screen react-native

I'm using a WebView to show an iframe of a twitch-stream in my react-native app, however at some points when it renders the WebView only shows up as a blank white screen until you scroll/move the UI and at other times it works as intended.
There are no errors emitted when the WebView is blank, it seems to load as intended so not really sure why it just shows a blank white screen.
Here is the WebView code:
<Animated.View
style={{
height: anim,
width: width,
overflow: 'hidden',
}}
>
<WebView
onLoadEnd={() => {
useAnimation()
}}
source={{
uri: `https://host.com/iframe/?channel=${channelName}`,
}}
style={{
height: heightByRatio,
width: width,
flex: 0,
}}
mediaPlaybackRequiresUserAction={false}
allowsInlineMediaPlayback={true}
/>
</Animated.View>
I had a very similar issue of webviews sometimes loading blank on android devices. I can't say I figured out why it was happening, but I solved it by delaying the load of the webview and putting a 2px border around the container wrapping the webview. Neither solution worked on its own, both were needed.
export default class WebviewExample extends Component<Props> {
constructor(props) {
super(props);
this.state = {};
}
componentDidMount() {
setTimeout(() => {
this.setState({loadWebview: true});
});
}
render() {
return (
<View style={styles.view}>
{this.state.loadWebview &&
<WebView />
}
</View>
);
}
}
const styles = StyleSheet.create({
view: {
borderWidth: 2,
borderColor: 'transparent',
}
});

Cascade text color with Styled Components on React Native

I'm trying to create a component with React Native that includes a <Text> component inside the wrapped component:
const MyComponent = props => (
<View {...props}>
<Text {...props}>Hello world</Text>
<View>
)
const MyRedComponent = styled(MyComponent)`
color: #000;
margin-left: 10px;
background: #F00;
`
I'm composing my component this way so I could change the the text color from the same styled component as I'm changing the background color:
const MyBlueComponent = styled(MyRedComponent)`
color: #FFF;
background: #00F;
`
However with this approach there is a problem that all of the styles get applied to the <Text> component, not only the color; in this example the <Text> component also gets the margin-left style from the parent styles which is not preferred. I'd only like the text color to be cascaded to the <Text> component.
Is this possible using Styled Components with React Native?
You can create a wrapper function using StyleSheet.flatten and pick the color from the resulting object:
const MyComponent = props => (
<View {...props}>
<Text style={{ color: StyleSheet.flatten(props.styles).color }}>Hello world</Text>
<View>
)
const MyRedComponent = styled(MyComponent)`
color: #000;
margin-left: 10px;
background: #F00;
`
It makes sense to extract the picking to its own function. For example you could create the following wrapper:
const pickColorFromStyles = styles => {
const { color } = StyleSheet.flatten(styles)
return { color }
}
...and use that function in your component:
const MyComponent = props => (
<View {...props}>
<Text style={pickColorFromStyles(props.styles)}>Hello world</Text>
<View>
)
Notice the warning with using StyleSheet.flatten from the documentation page:
NOTE: Exercise caution as abusing this can tax you in terms of optimizations. IDs enable optimizations through the bridge and memory in general. Refering to style objects directly will deprive you of these optimizations.

React Native - FlatList Not Rendering

(Note: I'm using Expo for this app)
I'm attempting to render a FlatList that displays a list of printers. Here's the code:
<FlatList
data={printers}
keyExtractor={printer => printer.id}
renderItem={({ item }) => {
return (
<Printer
printerTitle={item.name}
selected={item.selected}
last={item === last(printers)}
/>
);
}}
/>
Here's the code for the <Printer /> component:
const Printer = props => {
const { last, printerTitle, selected } = props;
return (
<View style={[styles.container, last ? styles.lastContainer : null]}>
<View style={styles.innerContainer}>
<View style={styles.leftContainter}>
{selected ? (
<Image source={selected ? Images.checkedCircle : null} />
) : null}
</View>
<View style={styles.printerDetails}>
<Text style={styles.printerTitle}>{printerTitle}</Text>
</View>
</View>
</View>
);
};
...
export default Printer;
I can't seem to get the <Printer /> component to render. I have tried including a similar custom component (that has worked in a FlatList in another part of the app) in the renderItem prop, and it doesn't work either.
However, when I replace the <Printer /> component with <Text>{item.name}</Text> component, the printer name renders like I would expect it to.
Has anyone run into this issue before, or does anyone have a solution?
In my case, where I'm rendering a custom component for each item in the list, it wasn't rendering because I accidentally had {} surrounding the return part of the renderItem prop instead of ().
Changing:
<FlatList
data={array}
renderItem={({item, index}) => { <CustomItemComponent /> }}
/>
to this:
<FlatList
data={array}
renderItem={({item, index}) => ( <CustomItemComponent /> )}
/>
Solved my issues.
I suspect there are two issues at hand: one is that your FlatList is not filling the screen (namely its parent view) and the other is that your Printer component is not being sized correctly.
For the first issue, put a style with { flex: 1 } on your FlatList. This way it will fill its parent view.
For the second issue, try adding { borderColor: 'red', borderWidth: 1 } to your Printer components, just so that you can more easily see where they're being rendered. If they seem like they have no width, make sure you haven't overridden alignSelf on the Printer component's root view. If they seem like they have no height, add height: 100 temporarily just so you can see what the contents of the Printer components look like.
Within your Printer component, make sure to specify the width and height of your image on the Image component like { width: 40, height: 30 } or whatever the dimensions of your image is in logical pixels.
I have same problem.
Resolve with adding width to FlatList
render() {
const dimensions = Dimensions.get('window');
const screenWidth = dimensions.width;
return(
<FlatList
style={{
flex: 1,
width: screenWidth,
}}
... some code here
/>
)
}
You can't use the keyExtractor in this way, make this function like below. It might solve your problem.
_keyExtractor = (item, index) => index;
If you update your question with you printer component code we can help you better.
In my case I accidentally made it a pair tag: <FlatList></FlatList>, which for some reason breaks rendering of list items.
in my case Container was not having width of 100%:
const Container = styled.View`
border: 1px solid #ececec;
margin-top: 43px;
padding-top: 36px
padding-bottom: 112px;
width: 100%;
`;
const StyledFlatList = styled(
FlatList as new () => FlatList<SimilarRewards_viewer['merchants']['edges'][0]>
)`
width: 100%;
height: 150px;
flex: 1;
padding-left: 15px;
padding-right: 15px;
`;

How do I prevent a user clicking through an overlay?

I have an overlay positioned absolute, it has backgroundColor and it covers the whole screen. It's overlaying several button components which I can still click on through the overlay.
How do I prevent this behavior? I want to swallow all click events landing on the overlay first.
Code:
// Overlay
export default class Overlay extends Component {
render() {
return (
<View style={styles.wrapper} />
);
}
}
const styles = StyleSheet.create({
wrapper: {
position: "absolute",
top: 0,
left: 0,
bottom: 0,
right: 0,
backgroundColor: "black",
opacity: 0.7
}
});
// Container
export default class Container extends Component {
render() {
return (
<View>
<Overlay />
<Button onPress={() => this.doSomething()}>
<Text>Hello</Text>
</Button>
</View>
);
}
}
Write the absolute position component after other components to render it over the other components.
export default class Container extends Component {
render() {
return (
<View>
<Button onPress={() => this.doSomething()} title="Hello" />
<Overlay /> // provide appropriate height and width to the overlay styles if needed...
</View>
);
}
}
Solution 1- You can try to use Modal component from react-native
Solution 2- Wrap TouchableWithoutFeedback having blank onPress around your overlay. Don't forget to give full height and width to TouchableWithoutFeedback
something like
<TouchableWithoutFeedback>
<Overlay/>
<TouchableWithoutFeedback/>