React Native FlatList Grid custom view - android

I am developing a react native app that shows data in the flatlist grid view.
for that, I followed the code which I found on the expo. I work fine. But what I need is, I want the first row should render one item only. so that I can use the empty space to show some data first.
here is the Expo link.
https://snack.expo.io/#savadks1818/react-native-flatlist-grid
and here is the code
import React from 'react';
import { StyleSheet, Text, View, FlatList, Dimensions } from 'react-native';
const data = [
{ key: 'A' }, { key: 'B' }, { key: 'C' }, { key: 'D' }, { key: 'E' }, { key: 'F' }, { key: 'G' }, { key: 'H' }, { key: 'I' }, { key: 'J' },
{ key: 'K' },
// { key: 'L' },
];
const formatData = (data, numColumns) => {
const numberOfFullRows = Math.floor(data.length / numColumns);
let numberOfElementsLastRow = data.length - (numberOfFullRows * numColumns);
while (numberOfElementsLastRow !== numColumns && numberOfElementsLastRow !== 0) {
data.push({ key: `blank-${numberOfElementsLastRow}`, empty: true });
numberOfElementsLastRow++;
}
return data;
};
const numColumns = 3;
export default class App extends React.Component {
renderItem = ({ item, index }) => {
if (item.empty === true) {
return <View style={[styles.item, styles.itemInvisible]} />;
}
return (
<View
style={styles.item}
>
<Text style={styles.itemText}>{item.key}</Text>
</View>
);
};
render() {
return (
<FlatList
data={formatData(data, numColumns)}
style={styles.container}
renderItem={this.renderItem}
numColumns={3}
/>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginVertical: 20,
},
item: {
backgroundColor: '#4D243D',
alignItems: 'center',
justifyContent: 'center',
flex: 1,
margin: 3,
height: Dimensions.get('window').width / numColumns, // approximate a square
},
itemInvisible: {
backgroundColor: 'transparent',
},
itemText: {
color: '#fff',
},
});

you can do this by adding new obects in the data array in desired position
const data = [
{ key: 'A' },
{ empty: true, key: 'xxx' },
{ empty: true, key: 'xxx' },
{ key: 'B' },
{ key: 'C' },
{ key: 'D' },
{ key: 'E' },
{ key: 'F' },
{ key: 'G' },
{ key: 'H' },
{ key: 'I' },
{ key: 'J' },
{ key: 'K' },
{ key: 'L' },
];
to add item do
data.splice(1, 0, { empty: true, key: 'xxx' });

Related

how to reject or answer an incoming call witihn react native app with custom buttons(can i use react-native-call-keep)

I am using react-native-call-detection package to save incoming call number (and send it on server later), I also want to reject/answer the incoming call based on the pressed button (based on server response later).
what package should I use to do it? I just found react-native-call-keep but all examples gave fake phone number to the functons and I don't know how to use its functions or how to get my call uuid.I just know there is reject/answer call function and I should call addEventListener functions before calling functions.
here is my current code:
import React, {useEffect, useState} from 'react';
import RNCallKeep from 'react-native-callkeep';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
TouchableHighlight,
PermissionsAndroid,
} from 'react-native';
import CallDetectorManager from 'react-native-call-detection';
import RNCallKeep from 'react-native-callkeep';
export default class MasterScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
featureOn: false,
incoming: false,
number: null,
};
}
componentDidMount() {
this.askPermission();
this.startListenerTapped();
this.setupCallKeep();
}
setupCallKeep() {
const options = {
android: {
alertTitle: 'Permissions Required',
alertDescription:
'This application needs to access your phone calling accounts to make calls',
cancelButton: 'Cancel',
okButton: 'ok',
imageName: 'ic_launcher',
additionalPermissions: [PermissionsAndroid.PERMISSIONS.READ_CONTACTS],
},
};
try {
RNCallKeep.setup(options);
RNCallKeep.setAvailable(true); // Only used for Android, see doc above.
} catch (err) {
console.error('initializeCallKeep error:', err.message);
}
}
askPermission = async () => {
try {
const permissions = await PermissionsAndroid.requestMultiple([
PermissionsAndroid.PERMISSIONS.READ_CALL_LOG,
PermissionsAndroid.PERMISSIONS.READ_PHONE_STATE,
]);
console.log('Permissions are:', permissions);
} catch (err) {
console.warn(err);
}
};
startListenerTapped = () => {
this.setState({featureOn: true});
this.callDetector = new CallDetectorManager(
(event, phoneNumber) => {
console.log(event);
if (event === 'Disconnected') {
this.setState({incoming: false, number: null});
} else if (event === 'Incoming') {
this.setState({incoming: true, number: phoneNumber});
} else if (event === 'Offhook') {
this.setState({incoming: true, number: phoneNumber});
} else if (event === 'Missed') {
this.setState({incoming: false, number: null});
}
},
true,
() => {},
{
title: 'Phone State Permission',
message:
'This app needs access to your phone state in order to react and/or to adapt to incoming calls.',
},
);
};
stopListenerTapped = () => {
this.setState({featureOn: false});
this.callDetector && this.callDetector.dispose();
};
render() {
return (
<View style={styles.body}>
<Text>incoming call number: {this.state.number}</Text>
<TouchableOpacity
onPress={/*what to do */} style={{
width: 200,
height: 200,
justifyContent: 'center',
}}><Text>answer</Text></TouchableOpacity>
<TouchableOpacity
onPress={/*what to do */} style={{
width: 200,
height: 200,
justifyContent: 'center',
}}>
<Text>reject</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
body: {
backgroundColor: 'honeydew',
justifyContent: 'center',
alignItems: 'center',
flex: 1,
},
text: {
padding: 20,
fontSize: 20,
},
button: {},
});`
Use RNCallKeep.rejectCall. Like so
<TouchableOpacity
onPr ess={() => RNCallKeep.rejectCall(uuid)}
st yle={{
width: 200,
height: 200,
justifyContent: 'center',
}}
>
<Text>reject</Text>
</TouchableOpacity>

React native deep linking not moving through to 2nd deep link

When using react native deep linking, I am struggling to use a uri with a 2nd path. There are examples in the documentation https://reactnavigation.org/docs/4.x/deep-linking
The issue I am having is blahh://account --android will link to the correct screen however, blahh://account/keys --android will not. This is the same if I add any path to the screens in the AccountStack
I am using react navigation version 4.
const AccountStack = createStackNavigator(
{
Account: {
screen: Account,
path: '',
navigationOptions: {
...accountNavigationOptions,
...Account.navigationOptions,
},
},
AccountLoginAndSecurity: {
screen: AccountLoginAndSecurity,
path: '',
navigationOptions: () => ({
...defaultNavigationOptions,
headerTransitionPreset: 'uikit',
}),
},
CreateAccount: {
screen: CreateAccount,
path: '',
navigationOptions: () => ({
...defaultNavigationOptions,
headerTransitionPreset: 'uikit',
}),
},
KeysList: {
screen: KeysList,
path: 'keys',
navigationOptions: () => ({
...defaultNavigationOptions,
headerTransitionPreset: 'uikit',
}),
},
AccountSwitch: createAnimatedSwitchNavigator(
{
AccountLoading: {
screen: AccountLoading,
path: '',
params: {
theme: 'orange',
navigateScreen: 'CreateAccountOrLogin',
},
},
CreateAccountOrLogin: CreateAccountOrLogin,
Continue: AccountMenu,
},
{
initialRouteName: 'AccountLoading',
transition: createSwitchTransition(),
}
),
},
{
defaultNavigationOptions: accountNavigationOptions,
}
);
export const TabNavigator = createBottomTabNavigator(
{
Explore: {
screen: ExploreStack,
path: '',
},
Bookings: {
screen: YourBookingsStack,
path: '',
},
Account: {
screen: AccountStack,
path: 'account',
},
},
{
defaultNavigationOptions: ({ navigation }) => ({
// eslint-disable-next-line react/display-name
tabBarIcon: ({ focused }): React.ReactNode => {
const { routeName } = navigation.state;
let iconName;
if (routeName === 'Explore') {
focused
? (iconName = require('assets/icons/bottom_tab_icons/explore_tab_icon.png'))
: (iconName = require('assets/icons/bottom_tab_icons/explore_tab_icon_unselected.png'));
} else if (routeName === 'Bookings') {
focused
? (iconName = require('assets/icons/bottom_tab_icons/bookings_tab_icon.png'))
: (iconName = require('assets/icons/bottom_tab_icons/bookings_tab_icon_unselected.png'));
} else if (routeName === 'Account') {
focused
? (iconName = require('assets/icons/bottom_tab_icons/account_tab_icon.png'))
: (iconName = require('assets/icons/bottom_tab_icons/account_tab_icon_unselected.png'));
}
return <Image source={iconName} />;
},
tabBarOptions: {
showLabel: false,
style: {
elevation: 3,
borderTopColor: 'transparent',
backgroundColor: '#fff',
height: 50,
},
},
}),
navigationOptions: () => ({
headerBackTitle: null,
headerTitleStyle: { color: 'orange' },
}),
}
);
I just looked at the codebase and Account links through to the account screen before going to the keys screen.
Account: {
screen: Account,
path: '',
navigationOptions: {
...accountNavigationOptions,
...Account.navigationOptions,
},
},
so the fix was to add an empty path to this in the accountstack then it worked fine when going to npx uri-scheme open blahh://account/keys --android

React native F2 chart does not show up on android

Does anyone knows why it does not show up on android? it works perfectly fine on iOS. I'm using this lib btw https://github.com/aloneszjl/react-native-f2chart. In example, it seems to work with both iOS and android, but I can't get it to work on android. Any help would be appreciated
const HomeTab = () => {
const data = [
{
date: '2017-06-05',
value: 116,
},
{
date: '2017-06-06',
value: 129,
},
{
date: '2017-06-07',
value: 135,
},
];
const initScript = data => `
(function(){
chart = new F2.Chart({
id: 'chart',
pixelRatio: window.devicePixelRatio,
});
chart.source(${JSON.stringify(data)}, {
value: {
tickCount: 5,
min: 0
},
date: {
type: 'timeCat',
range: [0, 1],
tickCount: 3
}
});
chart.tooltip({
custom: true,
showXTip: true,
showYTip: true,
snap: true,
crosshairsType: 'xy',
crosshairsStyle: {
lineDash: [2]
}
});
chart.axis('date', {
label: function label(text, index, total) {
var textCfg = {};
if (index === 0) {
textCfg.textAlign = 'left';
} else if (index === total - 1) {
textCfg.textAlign = 'right';
}
return textCfg;
}
});
chart.line().position('date*value');
chart.render();
})();
`;
return(
<View style={{ height: 200, width: 400}}>
<Chart
style={{flex: 1, width: 400}}
initScript={initScript(data)}
/>
</View>
)
}

How to use react-native-flash-message with react-native-navigation

I am using Wix's react-native-navigation and I want to use react-native-flash-message. In the official document https://www.npmjs.com/package/react-native-flash-message, they have given we can use globally as well as locally but in my code, I am not getting where should I use it.
following is my code.
this is my app.js
import { Navigation } from "react-native-navigation";
import { Provider } from "react-redux";
import registerScreens from './components/Screens'
import Icon from 'react-native-vector-icons/FontAwesome';
import configureStore from "./store/configureStore";
const store = configureStore();
registerScreens(Provider, store);
// Start a App
Navigation.events().registerAppLaunchedListener(() => {
Promise.all([
Icon.getImageSource("bars", 30, 'black'),
Icon.getImageSource("share-alt", 30, 'black')
]).then(sources => {
Navigation.setRoot({
root: {
sideMenu: {
left: {
component: {
name: 'app.NavigationDrawer',
passProps: {
text: 'This is a left side menu screen'
}
}
},
center: {
stack: {
id: 'mainStack',
children: [
{
stack: {
id: 'tab1Stack',
children: [
{
component: {
name: 'app.Component'
}
}
],
options: {
topBar: {
background: {
color: '#50A7C2',
},
title: {
text: 'Namaz Timing',
fontSize: 20,
//color: 'white',
fontFamily: 'Ubuntu',
alignment: 'left'
},
leftButtons: [
{
id: 'buttonOne',
icon: sources[0]
}
],
rightButtons: [
{
id: 'buttonTwo',
icon: sources[1]
}
]
}
}
}
},
],
options: {
topBar: {
background: {
color: '#50A7C2',
}
},
}
}
}
}
}
});
});
});
And this is my function where I want to use it
import qs from 'qs';
import { AsyncStorage } from 'react-native';
export async function addMasjid(Name, Address, email, Timing1, Timing2, Timing3, Timing4, Timing5, Timing6, Timing7) {
const Data = await AsyncStorage.getItem('tokenData');
parsed = JSON.parse(Data)
var token = parsed.access_token;
return fetch(`URL`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
},
body: qs.stringify({
'name': Name,
'address': Address,
'email': email,
'time_': Timing,
'time_': Timing,
'time_': Timing,
'time_': Timing,
'time_': Timing,
'time_': Timing,
'time_': Timing,
})
})
.then(res => res.json())
.catch(err => console.log(err))
Import the Flash Message component in your App.js and call it in the bottom.
App.js
import React from "react";
import { View } from "react-native";
import FlashMessage from "react-native-flash-message";
export default class App extends React.Component {
render() {
return (
<View style={{ flex: 1 }}>
// your entire code
<FlashMessage position="top" /> <--- at the bottom
</View>
);
}
}
Now, in your file where you wanna use it.
import { showMessage, hideMessage } from "react-native-flash-message";
Then, just use showMessage in the function you want to. Example:
const someFunc = () => {
showMessage({
message : 'some message',
type: 'success'
... other attributes
})
}

React Native FlatList scrollToBottom not working

Greeting everyone,
I am working on react-native FlatList and my problem is that I am unable to scroll to bottom. Here is my FlatList code:
<FlatList style = { styles.list }
ref="flatList1"
data = {
this.state.conversation_arr
}
onContentSizeChange={(contentWidth, contentHeight) => {
this.flat_list_height = contentHeight;
// this.scrollNow();
}}
onLayout={this.scrollNow()}
renderItem = { this._renderItem }
keyExtractor = { item => item.message_id }
/>
scrollNow() {
console.log("******",this.refs);
if(this.refs.flatList1){
this.refs.flatList1.scrollToEnd();
}
}
When the code reaches to
this.refs.flatList1.scrollToEnd();
Error appears on the screen saying
Type Error, cannot read property -1 of undefined.
here is the screenshot.
cannot read property -1 of undefined
I am basically trying to implement chat feature for my application, and therefor i need to scroll to bottom of the list once chat is loaded.
Any kind of help is appreciated.
Thanks
COMPLETE CODE
import React, {
Component
} from 'react';
import {
StyleSheet,
View,
Text,
TextInput,
ActivityIndicator,
TouchableOpacity,
FlatList,
} from 'react-native';
export default class Conversation extends Component {
state = {
conversation_arr: undefined,
last_message_loaded: false,
show_activty_indicator: true,
message_text : undefined,
message_text_length : 0
};
params = this.props.navigation.state;
last_evaluated_key = {
message_id: undefined,
timestamp: undefined
}
conversation = undefined;
thread_info = undefined;
flat_list_height = 0;
static navigationOptions = ({ navigation }) => ({
title: navigation.state.params.header_title,
});
constructor(props) {
super(props);
this._renderItem = this._renderItem.bind(this);
this._fetchConversation();
this.scrollNow = this.scrollNow.bind(this);
this.handleInputTextContent = this.handleInputTextContent.bind(this);
this.sendMessage = this.sendMessage.bind(this);
console.disableYellowBox = true;
this.thread_info = this.params.params.thread_info;
}
// scrollNow() {
// console.log("******",this.refs);
// if(this.refs.flatList1){
// // debugger;
// this.refs.flatList1.scrollToEnd();
// }
// console.log("******", this.flatlist1);
// if(this.flatlist1){
// this.flatlist1.scrollToEnd();
// }
// console.log("###", this.flat_list_height);
// }
scrollNow = () => {
console.log("******", this.flatList1);
if(this.state.conversation_arr && this.state.conversation_arr.length > 0 && this.flatList1){
// debugger;
// setTimeout(() => {
// console.log("timer over now");
this.flatList1.scrollToEnd();
// }, 1000)
// this.flatList1.scrollToEnd();
console.log("Scrolling now at length", this.state.conversation_arr.length);
}
// !!this.refs["myFlatList"] && this.refs["myFlatList"].scrollToEnd()
}
componentDidUpdate(){
console.log("componentDidUpdatecomponentDidUpdate")
}
componentWillUnmount(){
console.log("componentWillUnmountv")
}
render() {
return (
<View style={ styles.container }>
{
this.state.show_activty_indicator &&
<View style={[styles.activity_indicator_container]}>
<ActivityIndicator
animating = { this.state.show_activty_indicator }
size="large"
color="#444444"
/>
</View>
}
<FlatList style = { styles.list }
// inverted
// ref="myFlatList"
// ref={(ref) => this.flatList1 = ref}
ref={(ref) => { this.flatList1 = ref; }}
data = {
this.state.conversation_arr
}
onContentSizeChange={(contentWidth, contentHeight) => {
this.flat_list_height = contentHeight;
// this.scrollNow();
}}
onLayout={this.scrollNow}
renderItem = { this._renderItem }
keyExtractor = { item => item.message_id }
/>
<View style={ styles.bottom_box }>
<Text style={ styles.message_length }> {this.state.message_text_length}/160 </Text>
<View style={ styles.message_box }>
<View style={{flex: 3}} >
<TextInput
style={styles.input_text}
value={this.state.message_text}
onChangeText={this.handleInputTextContent}
placeholder='Type a message here...'
underlineColorAndroid='transparent'
/>
</View>
<View style={{flex: 1}} >
<TouchableOpacity
style={styles.send_button}
onPress={this.sendMessage} >
<Text style={[styles.label_send]}>SEND</Text>
</TouchableOpacity>
</View>
</View>
</View>
</View>
);
}
handleInputTextContent(text){
if(text.length > 160){
text = text.substring(0,159)
this.setState({ message_text : text });
} else {
this.setState({ message_text : text });
this.setState({ message_text_length : text.length });
}
}
sendMessage(){
console.log(this.state.message_text);
if(this.state.message_text && this.state.message_text.length > 0) {
console.log("Send message now");
}
}
_renderItem(item, index){
// console.log(item.item);
item = item.item;
let view = (
<Text style = { [styles.msg_common] }> { item.message_content } </Text>
)
return view ;
}
processPaymentMessages(dataArr) {
return dataArr;
}
_fetchConversation() {
new WebApi().fetchThreadConversation().then(result => {
console.log("resutlresult", result);
if (result && result.data && result.data.LastEvaluatedKey) {
this.last_evaluated_key.message_id = result.data.LastEvaluatedKey.message_id;
this.last_evaluated_key.timestamp = result.data.LastEvaluatedKey.timestamp;
} else {
this.setState({
last_message_loaded: true
});
this.last_evaluated_key = null;
}
if (!this.conversation) {
this.conversation = [];
}
for (let i = 0; i < result.data.Items.length; i++) {
item = result.data.Items[i];
this.conversation.push(item);
}
// console.log(this.conversation);
this.setState({ conversation_arr : this.conversation });
this.setState({ show_activty_indicator : false });
console.log(this.state.conversation_arr.length);
}, error => {
console.log("web api fetch data error", error);
})
}
}
const styles = StyleSheet.create({
activity_indicator_container: {
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff'
},
container: {
flex: 1,
paddingTop: 8,
backgroundColor:"#fff"
},
list : {
paddingLeft: 8,
paddingRight:8,
marginBottom : 85,
},
gray_item: {
padding: 10,
height: 44,
backgroundColor:"#fff"
},
white_item : {
padding: 10,
height: 44,
backgroundColor:"#f5f5f5"
},
msg_common : {
flex: 1,
justifyContent: 'flex-end',
alignItems: 'flex-end',
},
colored_item_common : {
padding : 12,
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
item_insider_common : {
backgroundColor:"#fff",
fontSize : 16,
padding : 12,
borderWidth : 1,
borderRadius : 8,
width : "90%",
fontWeight : "bold",
textAlign: 'center',
},
purple_item_insider : {
color : "#7986cb",
borderColor: "#7986cb",
},
green_item_insider : {
color : "#66bb6a",
borderColor: "#66bb6a",
},
bottom_box:{
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
flex: 1,
},
message_length: {
height : 20,
textAlign: 'right', alignSelf: 'stretch'
},
message_box: {
// position: 'absolute',
// left: 0,
// right: 0,
// bottom: 0,
flex: 1,
flexDirection: "row"
},
input_text: {
width: '100%',
height: 60,
color: '#000',
backgroundColor:"#eee",
padding: 16,
},
send_button: {
alignItems: 'center',
flex: 1,
height: 60,
padding: 16,
backgroundColor : '#f1592b'
},
label_send: {
color: '#fff'
}
})
You need to give a callback to onLayout like this:
onLayout={this.scrollNow}
The updated code is: I tried it. It works.
import React, { Component } from 'react';
import { FlatList, Text } from 'react-native';
export default class App extends Component {
render() {
return (
<FlatList
ref={(ref) => { this.flatList1 = ref; }}
data={[0, 0, 0, 0, 0, 0, 0, 0]}
onContentSizeChange={(contentWidth, contentHeight) => { this.flat_list_height = contentHeight; }}
onLayout={this.scrollNow}
renderItem={this.renderItem}
keyExtractor={item => item.message_id}
/>
);
}
renderItem =() => <Text style={{marginTop: 100}}>Just Some Text</Text>
scrollNow =() => {
if (this.flatList1) {
this.flatList1.scrollToEnd();
}
}
}
Have you tried passing an empty array when "this.state.conversation_arr" is undefined or null. Checking this._renderItem can be helpful also, weather it is trying to access -1 of any argument.
There are 2 parts wrong in your code.
the ref in FlatList is a function, not a string.
If you don't use arrow function, the FlatList cannot access the "this" in scrollNow() function.
I tested with similar code. The code below should work.
import * as React from 'react';
import { StyleSheet, View, Text, FlatList } from 'react-native';
export default class Conversation extends React.Component {
flatList1;
_interval;
state = { conversation_arr: [] };
componentDidMount() {
let buffer = [];
for (let i = 1; i < 40; i++) {
buffer.push({ message_id: i, message_content: `I'm the message ${i}` });
}
this._interval = setInterval(() => {
this.setState(() => {
return { conversation_arr: buffer };
});
this.flatList1.scrollToIndex({
index: buffer.length - 1,
viewPosition: 1,
viewOffset: 0,
});
}, 1000);
}
componentWillUnmount() {
clearInterval(this._interval);
}
render() {
return (
<View style={styles.container}>
<FlatList
ref={ref => {
this.flatList1 = ref;
}}
data={this.state.conversation_arr}
renderItem={this._renderItem}
keyExtractor={item => item.message_id}
getItemLayout={(data, index) => ({
length: 40,
offset: 40 * index,
index,
})}
/>
</View>
);
}
_renderItem = ({ item }) => {
return (
<View>
<Text style={styles.msg_common}>{item.message_content}</Text>
</View>
);
};
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
msg_common: {
height: 40,
fontSize: 18,
paddingHorizontal: 10,
},
});
PS: If you have a long list, let's say more than 100. Using onLayout to scroll down might take some time for initial rendering, which provides a really bad user experience. The much better approach may be
to reverse the list before rendering
provide a sort button and set onRefresh to true during sorting
provide a scroll to bottom button list's footer
Update:
I noticed the onContentSizeChange property is NOT in the documentation.
https://facebook.github.io/react-native/docs/flatlist.html#scrolltoindex
Which version of React-Native are you using?
Update2:
The complete code in TypeScript based on yours. I use setInterval to simulate the delay from API call.
Any async function should be in componentDidMount, because constructor doesn't wait.
getItemLayout is used to help FlatList to figure out height. Notice that this is set before the data arrived.

Categories

Resources