The ScrollView component has an accessibility issue as it prevents the user navigating to the back button - react-native

We use react-navigation to open a modal with a back button. There is an accessibility problem with this setup as users can't "swipe" left from the title (within the ScrollView) to the back button. After a lot of investigation we pinned it down to the ScrollView component. If we change it to a regular View then there is no problem at all. However obviously this is not desired a the user should be able to scroll.
This is the problematic code.
import React, { FC, memo } from 'react'
import Animated, { useAnimatedScrollHandler } from 'react-native-reanimated'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { useThemedStyle } from '#mylib/ui'
import { stylesCreator } from './styles'
import type { AnimatedScrollViewProps } from './types'
const AnimatedScrollViewComponent: FC<AnimatedScrollViewProps> = ({
scrollOffset,
children
}) => {
const scrollHandler = useAnimatedScrollHandler(event => {
scrollOffset.value = event.contentOffset.y
})
const { bottom: bottomInset } = useSafeAreaInsets()
const styles = useThemedStyle(stylesCreator, bottomInset)
return (
<Animated.ScrollView
style={styles.scrollContainer}
contentContainerStyle={styles.contentContainer}
scrollEventThrottle={50}
onScroll={scrollHandler}
overScrollMode="never"
>
{children}
</Animated.ScrollView>
)
}
export const AnimatedScrollView = memo(AnimatedScrollViewComponent)
We are kind of out options what to investigate next. So I'm hoping anyone has experience with this and can help us out in some way.

Related

How can I solve the old date displaying error in React Native?

I started developing apps using React Native not too long ago.
In the meantime, there was a situation in which the date data selected from the calendar had to be moved to another screen.
At first, I tried to move the date data by sharing data between screens, but the error continued.
But I tried another way to deliver the data well and built it.
The way I thought about it was to take 'async storage' and convert the date data into a string and save it.
This method was successful but had a fatal problem.
First, I found the following situation.
When I first started the app and selected February 1st, the date was not displayed after the screen was moved.
Then I went back to the first screen and clicked February 2nd.
This will display the date on the screen.
But I chose February 2nd, but it says February 1st instead of February 2nd.
This indicates that the detail screen will display the previously selected date rather than the date selected now.
I don't know how to solve this problem.
This is something I've never encountered while programming.
This is my code
Home.js
import React from "react";
import { SafeAreaProvider } from "react-native-safe-area-context";
import { Calendar } from "react-native-calendars";
import { View, Alert } from "react-native";
import AsyncStorage from "#react-native-async-storage/async-storage";
var dateString = "";
const savereturndate = async (value) => {
try {
await AsyncStorage.setItem("selectdate", dateString);
} catch (e) {
Alert.alert("Error", e, [{ text: "OK", onPress: () => null }]);
}
};
function HomeScreen({ navigation }) {
const markedDates = {
"2023-02-01": { marked: true, dotColor: "red" },
};
return (
<SafeAreaProvider>
<View>
<Calendar
markedDates={markedDates}
onDayPress={(day) => {
for (var key in day) {
//console.log("key:" + key + "/" + day[key])
dateString = day[key];
}
savereturndate();
navigation.push("Detail");
}}
/>
</View>
</SafeAreaProvider>
);
}
export default HomeScreen;
Detail.js
import React from "react";
import { SafeAreaProvider } from "react-native-safe-area-context";
import { View, Text, Alert } from "react-native";
import AsyncStorage from "#react-native-async-storage/async-storage";
var returndatedetail = "";
const getreturndate = async () => {
try {
const hello = await AsyncStorage.getItem("selectdate");
returndatedetail = hello.toString();
} catch (e) {
Alert.alert("Error", e, [{ text: "OK", onPress: () => null }]);
}
};
function DetailScreen() {
getreturndate();
return (
<SafeAreaProvider>
<View>
<Text>{returndatedetail}</Text>
</View>
</SafeAreaProvider>
);
}
export default DetailScreen;
This is my development environment.
OS: macOS Monterey(12.6.3)
Development Program: Visual Studio Code (1.71.1)
Simulator: iPhone 14 (ios 16.2)
React native Version: 9.2.0
And I am using expo go to test it.
Can someone help me with this problem?
If so, help me.
I don't know exactly what you're trying to do, but let me go through a few things that I founded in your code.
Screens
As I'm seeing here you have two basic Screens:
Home: Defined by the Calendar in which navigates to the Detail Screens on pressing any of the dates.
Detail: Defined by atm just a screen that shows the user some date.
Problem Fix Proposal
By looking into the definitions of Screens and understanding your problem, I don't think you need to store the currentDate into AsyncStorage. The navigation itself could handle that for you.
Try to do:
Home.js
import React from "react";
import { SafeAreaProvider } from "react-native-safe-area-context";
import { Calendar } from "react-native-calendars";
import { View} from "react-native";
function HomeScreen({ navigation }) {
const markedDates = {
"2023-02-01": { marked: true, dotColor: "red" },
};
return (
<SafeAreaProvider>
<View>
<Calendar
markedDates={markedDates}
onDayPress={(day) => {
navigation.navigate("Detail", { day });
}}
/>
</View>
</SafeAreaProvider>
);
}
export default HomeScreen;
Detail.js:
import React from "react";
import { SafeAreaProvider } from "react-native-safe-area-context";
import { View, Text, Alert } from "react-native";
function DetailScreen({ route }) {
const { day } = route.params;
return (
<SafeAreaProvider>
<View>
<Text>{day}</Text>
</View>
</SafeAreaProvider>
);
}
export default DetailScreen;
Why not just do that? Passing the pressed day to the Detail Screen, where you can handle anything you want. Beyond that everytime the day changes the navigation will basically handle that for you, navigating to a new Screen in the stack or not (if it's already there).

React native package #homee/react-native-mapbox-navigation not showing map (ANDROID)

I am trying to implement a turn by turn navigation in react native, I have used the package '#homee/react-native-mapbox-navigation'. I have used these instructions (https://reactnativeexample.com/smart-mapbox-turn-by-turn-routing-based-on-real-time-traffic-for-react-native/) to set all the gradle.properties / gradle.build and the manifest setting. This is how my app.js looks like:
import React from 'react';
import type {Node} from 'react';
import {
SafeAreaView,
ScrollView,
StatusBar,
StyleSheet,
Text,
useColorScheme,
View,
} from 'react-native';
import {
Colors,
DebugInstructions,
Header,
LearnMoreLinks,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';
import MapboxNavigation from '#homee/react-native-mapbox-navigation';
const App: () => Node = () => {
// const isDarkMode = useColorScheme() === 'dark';
// const backgroundStyle = {
// backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
// };
return (
<View style={styles.container}>
<MapboxNavigation
origin={[-97.760288, 30.273566]}
destination={[-97.918842, 30.494466]}
shouldSimulateRoute={true}
onLocationChange={(event) => {
const { latitude, longitude } = event.nativeEvent;
}}
onRouteProgressChange={(event) => {
const {
distanceTraveled,
durationRemaining,
fractionTraveled,
distanceRemaining,
} = event.nativeEvent;
}}
onError={(event) => {
const { message } = event.nativeEvent;
console.log('error', event)
}}
onCancelNavigation={() => {
// User tapped the "X" cancel button in the nav UI
// or canceled via the OS system tray on android.
// Do whatever you need to here.
}}
onArrive={() => {
// Called when you arrive at the destination.
}}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
export default App;
This is what my simulator is showing:
Is there someone who knows why I am getting an empty screen and how to fix this?
Thx guys!
The code works fine the mistake was that I put the meta-data tag in the wrong section
of the androidManifest.xml. I fixed this and it worked

NativeBase: Button does not work, but ReactNative's Button does

Experiencing a strange issue in my React Native project for Android.
Using React-Navigation, I have a component with a button inside. This button should navigate to a new screen.
Thing is, the built-in button of React Native works like a charm, while the button of Native Base does not. I am completely confused, even more because I use this Native Base Button in another location, too. And there it works fine.
What is going on here?
Here, you see the application works with the built-in React Native button:
On the opposite, using the button of Native Base, it not only does not work, even styles are not applied.
Here is the code with the React Native button:
import React from "react";
import { Button, View, Text, StyleSheet } from "react-native";
import { withNavigation } from "react-navigation";
type Props = { navigation: any };
const ButtonTestScreen: React.FC<Props> = ({ navigation }) => {
return (
<View>
<Button
title="Hi i am a button"
onPress={() => navigation.navigate("Details")}
></Button>
</View>
);
};
export default withNavigation(ButtonTestScreen);
And the code with Native Base button:
import React from "react";
import { Button, View, Text, StyleSheet } from "react-native";
import { withNavigation } from "react-navigation";
import ButtonNavigate from "../../components/atoms/ButtonNavigate/ButtonNavigate";
type Props = { navigation: any };
const ButtonTestScreen: React.FC<Props> = ({ navigation }) => {
return (
<View>
<ButtonNavigate
title="Hi i am a button"
navigateTo="Details"
></ButtonNavigate>
</View>
);
};
const styles = StyleSheet.create({
button_style: {
backgroundColor: "red"
},
text_style: {
color: "#000",
fontSize: 30
}
});
export default withNavigation(ButtonTestScreen);
And the respective ButtonNavigate component itself:
import React from "react";
import { StyleSheet } from "react-native";
import { withNavigation } from "react-navigation";
import { Button, Text } from "native-base";
type Props = {
title: string,
navigateTo: string,
navigation: any
};
const ButtonNavigate: React.FC<Props> = ({ title, navigateTo, navigation }) => {
return (
<Button
rounded
transparent
style={styles.button_style}
onPress={() => navigation.navigate(navigateTo)}
>
<Text style={styles.text_style}>{title}</Text>
</Button>
);
};
const styles = StyleSheet.create({
button_style: {
backgroundColor: "red"
},
text_style: {
color: "#151414"
}
});
export default withNavigation(ButtonNavigate);
I have just tested you code in expo.snack but without navigation and its ok,
see it here
You can test in your app to remove navigation and go step by step until you find the bug.
Folks, reason for this strange behavior is the "rounded" property of Native Base's button. In my application, somehow it causes the button to become non-clickable.
Maybe contributors of Native Base know what to do with this problem, so if you read this, maybe you have an idea.
Solution for my now was simply removing "rounded".
Native Base: 2.13.8
React-Navigation: 4.0.10
In my case it was the "top" in the container property of the button causing this issue. Removed it and adding "marginBottom" to the container above it solved the issue

How to start with left menu collapsed

Is there an easy was to start with the left menu collapsed or do I need to update the layout ?
I'd like to have the menu collapsed by default with only the icons visible.
Thank you.
If you mean Sidebar when saying "left menu", you can hide it by turning on the user saga (the toggle action will continue to work):
// closeSidebarSaga.js
import {
put,
takeEvery,
} from 'redux-saga/effects'
import {
REGISTER_RESOURCE, // React-admin 3.5.0
setSidebarVisibility,
} from 'react-admin'
function* closeSidebar(action) {
try {
if (action.payload) {
yield put(setSidebarVisibility(false))
}
} catch (error) {
console.log('closeSidebar:', error)
}
}
function* closeSidebarSaga() {
yield takeEvery(REGISTER_RESOURCE, closeSidebar)
}
export default closeSidebarSaga
// App.js:
import closeSidebarSaga from './closeSidebarSaga'
<Admin customSagas={[ closeSidebarSaga ]} ... }>
...
</Admin>
In the react-admin library itself, apparently a bug, at some point in time after the login, action SET_SIDEBAR_VISIBILITY = true is called!
You can set the initial state when loading Admin, then there will be no moment when the Sidebar is visible at the beginning, and then it is hidden:
https://marmelab.com/react-admin/Admin.html#initialstate
const initialState = {
admin: { ui: { sidebarOpen: false, viewVersion: 0 } }
}
<Admin
initialState={initialState}
...
</Admin>
To hide the left sideBar divider we need to dispatch setSidebarVisibility action .
This is an example to hide the sideBar by using useDispatch react-redux hook &
setSidebarVisibility action inside the layout file (layout.tsx):
import React from 'react';
/**
* Step 1/2 :Import required hooks (useEffect & useDispatch)
*/
import { useEffect } from 'react';
import { useSelector,useDispatch } from 'react-redux';
import { Layout, Sidebar ,setSidebarVisibility} from 'react-admin';
import AppBar from './AppBar';
import Menu from './Menu';
import { darkTheme, lightTheme } from './themes';
import { AppState } from '../types';
const CustomSidebar = (props: any) => <Sidebar {...props} size={200} />;
export default (props: any) => {
const theme = useSelector((state: AppState) =>
state.theme === 'dark' ? darkTheme : lightTheme
);
/**
* Step 2/2 : dispatch setSidebarVisibility action
*/
const dispatch = useDispatch();
useEffect(() => {
dispatch(setSidebarVisibility(false));
});
return (
<Layout
{...props}
appBar={AppBar}
sidebar={CustomSidebar}
menu={Menu}
theme={theme}
/>
);
};
Since Redux is not used anymore by ReactAdmin, you need to adapt the local storage instead to hide the sidebar. Call this in your App.tsx class:
const store = localStorageStore();
store.setItem("sidebar.open", false);

Is there a way to read the options before use the mergeOptions function in react native navigation v2?

Is there a way to read the options before using the mergeOptions function.
I'm trying to add a sideMenu that opens and closes with the same button. But to handle that logic, Instead of making use of redux, I want to read the options before the merge, so I can simply do something like visible: !pastVisible.
navigationButtonPressed({ buttonId }) {
Navigation.mergeOptions(this.props.componentId, {
sideMenu: {
'left': {
visible: false
}
}
});
console.log(`Se presiono ${buttonId}`);
}
So basically I want to read the value of the visible option before changed it.
By now, I can only achieve this using redux.
import React, {Component} from 'react';
import {View, Text} from 'react-native';
import { Navigation } from 'react-native-navigation';
import { connect } from 'react-redux';
import { toggleSideMenu } from './../../store/actions/index';
class SideDrawer extends Component {
constructor(props) {
super(props);
Navigation.events().registerComponentDidDisappearListener(({ componentId }) => {
this.props.toggleSideMenu(false);
});
}
render() {
return (
<View>
<Text>This is the sidedrawer</Text>
</View>
);
}
}
const mapDispatchToProps = dispatch => {
return {
toggleSideMenu: (visible) => dispatch(toggleSideMenu(visible))
};
};
export default connect(null, mapDispatchToProps)(SideDrawer);
Then I just add the listeners to the sidemenu component. Depending on the case, I update the current state of the component (visible or not).
Finally on the components where I want to use the side drawer button I just implement the navigationButtenPressed method. Then I just call the reducer to know the current visible state and toggled it.
navigationButtonPressed({ buttonId }) {
const visible = !this.props.sideMenu;
Navigation.mergeOptions(this.props.componentId, {
sideMenu: {
'left': {
visible: visible
}
}
});
this.props.toggleSideMenu(visible);
}
If there is a more easy way to achieve this I'll be glad to know about it.