React Native - Keyboard avoiding not working if ScrollView is not at the top of the screen - react-native

<View>
<View style = {{height : X}}></View>
<ScrollView>
<KeyboardAvoidingView>
<View style = {{height : 350}}></View>
<TextInput/>
<View style = {{height : 500}}></View>
</KeyboardAvoidingView>
</ScrollView>
</View>
When I tap on the TextInput, it is scrolled upward but stop at the position of below where it is supposed to be as much as X, which means it is still hidden under the keyboard.
Actually the problem is not about KeyboardAvoidingView because it also happens without the use of it

This is what I did it to resolve this issue
<KeyboardAvoiding behavior={'padding'} keyboardVerticalOffset={64} style={styles.container}>
<View style={styles.container}>
<ScrollView keyboardShouldPersistTaps="always">
<View style = {{height : 350}}></View>
<TextInput/>
<View style = {{height : 500}}></View>
</ScrollView>
</View>
</KeyboardAvoiding>
container: {
flex: 1,
alignItems: 'center',
}
and this is the KeyboardAvoiding class
import React from 'react'
import { Platform, KeyboardAvoidingView as ReactNativeKeyboardAvoidingView } from 'react-native'
class KeyboardAvoidingView extends React.Component {
render() {
if (Platform.OS === 'ios') {
return (
<ReactNativeKeyboardAvoidingView behavior={'padding'} {...this.props}>
{this.props.children}
</ReactNativeKeyboardAvoidingView>
)
}
return this.props.children
}
}
KeyboardAvoidingView.propTypes = {
children: React.PropTypes.element,
}
module.exports = KeyboardAvoidingView
Hope this helps.

render() {
var a = [];
for(var i =1; i< 100; i++) a.push(i);
return (
<View>
<Button title = 'Scroll' onPress = {() => this.refs.scroll.scrollTo({x: 0, y: 0, animated: true})}/>
<ScrollView ref = 'scroll'>{a.map((item, index) => (<TextInput style = {{height : 10 + (Math.floor(Math.random() * 10) * 5)}}
placeholder = {item + ''}
onFocus = {() => {
this.refs.scroll.scrollTo({x : 0, y : this.y[index], animated : true});
}}
onLayout = {event => {
this.y[index] = event.nativeEvent.layout.y;
}}
/>))}</ScrollView>
</View>
);
}
Using this solution, there are 2 drawbacks exist which raise other problems require solutions
Not applicable in case the TextInput is inside a FlatList or perhaps certain components which contain TextInput indirectly. In this case, event.nativeEvent.layout.y will always return 0. No problem for multilevel ScrollView. Temporarily the solution is to avoid placing the TextInput inside a prop component
The TextInput's offset is relative to wrapper component if it's not the ScrollView. Scroll distance must be the summation of TextInput's offset and wrapper's offset if the wrapper is not at the top of ScrollView. Since a parent's post-layout data cannot be passed to a child directly via prop before it is rendered, the TextInput must get the wrapper's offset in it's onFocus handler
Default buggy keyboard avoiding sometimes take action after onFocus, cancelling onFocus's effect. The temporary solution is to use setTimeout to delay onFocus action for at least 200 milliseconds

Related

Increase height of a View on swipe up in react native expo

I have a container that contains multiple views like this :
export default function MyComponent() {
<View *** container *** >
<View> // some stuff </View>
<View> // some stuff </View>
<ScrollView> // some stuff </ScrollView>
</View
}
The ScrollView is about 40% of the container's height, in absolute position.
What I need to do is to be able to extend it over the whole screen with a swipe up.
I tried to use some modals npm package but I can't make it work.
A few things:
From my experience, ScrollViews and FlatLists work best when they have a flex of one and are wrapped in a parent container that limits their size.
I couldnt determine if you wanted to wrap the entire screen in a GestureDector and listen to swipes or if you only wanted the ScrollView to listen for scroll events. Because you want the ScrollView to take up the entire screen, I assume you wanted to listen to onScroll events
So here's a demo I put together:
import * as React from 'react';
import {
Text,
View,
Animated,
StyleSheet,
ScrollView,
useWindowDimensions
} from 'react-native';
import Constants from 'expo-constants';
import Box from './components/Box';
import randomColors from './components/colors'
const throttleTime = 200;
// min time between scroll events (in milliseconds)
const scrollEventThrottle = 100;
// min up/down scroll distance to trigger animatino
const scrollYThrottle = 2;
export default function App() {
const scrollViewAnim = React.useRef(new Animated.Value(0)).current;
let lastY = React.useRef(0).current;
// used to throttle scroll events
let lastScrollEvent = React.useRef(Date.now()).current;
const [{ width, height }, setViewDimensions] = React.useState({});
const [isScrollingDown, setIsScrollingDown] = React.useState(false);
const [scrollViewTop, setScrollViewTop] = React.useState(400);
// scroll view is 40% of view height
const defaultHeight = height * .4;
// call onLayout on View before scrollView
const onLastViewLayout = ({nativeEvent})=>{
// combine the y position with the layout height to
// determine where to place scroll view
setScrollViewTop(nativeEvent.layout.y + nativeEvent.layout.height)
}
const onContainerLayout = ({nativeEvent})=>{
// get width and height of parent container
// using this instead of useWindowDimensions allow
// makes the scrollView scale with parentContainer size
setViewDimensions({
width:nativeEvent.layout.width,
height:nativeEvent.layout.height
})
}
//animation style
let animatedStyle = [styles.scrollView,{
height:scrollViewAnim.interpolate({
inputRange:[0,1],
outputRange:[defaultHeight,height]
}),
width:width,
top:scrollViewAnim.interpolate({
inputRange:[0,1],
outputRange:[scrollViewTop,-10]
}),
bottom:60,
left:0,
right:0
}]
const expandScrollView = ()=>{
Animated.timing(scrollViewAnim,{
toValue:1,
duration:200,
useNativeDriver:false
}).start()
}
const shrinkScrollView = ()=>{
Animated.timing(scrollViewAnim,{
toValue:0,
duration:200,
useNativeDriver:false
}).start()
}
const onScroll=(e)=>{
// throttling by time between scroll activations
if(Date.now() - lastScrollEvent <scrollEventThrottle ){
console.log('throttling!')
return
}
lastScrollEvent = Date.now()
// destructure event object
const {nativeEvent:{contentOffset:{x,y}}} = e;
const isAtTop = y <= 0
const isPullingTop = lastY <= 0 && y <= 0
let yDiff = y - lastY
let hasMajorDiff = Math.abs(yDiff) > scrollYThrottle
// throttle if isnt pulling top and scroll dist is small
if(!hasMajorDiff && !isPullingTop ){
return
}
const hasScrolledDown = yDiff > 0
const hasScrolledUp = yDiff < 0
if(hasScrolledDown){
setIsScrollingDown(true);
expandScrollView()
}
if(isAtTop || isPullingTop){
setIsScrollingDown(false)
shrinkScrollView();
}
lastY = y
}
return (
<View style={styles.container} onLayout={onContainerLayout}>
<Box color={randomColors[0]} text="Some text"/>
<Box color={ randomColors[1]} text="Some other text "/>
<View style={styles.lastView}
onLayout={onLastViewLayout}>
<Text>ScrollView Below </Text>
</View>
<Animated.View style={animatedStyle}>
<ScrollView
onScroll={onScroll}
style={{flex:1}}
>
{randomColors.map((color,i)=>
<Box color={color} height={60} text={"Item Number "+(i+1)}/>
)}
</ScrollView>
</Animated.View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
// justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
padding: 8,
},
scrollView:{
// position:'absolute',
position:'absolute',
marginVertical:10,
height:'40%',
backgroundColor:'lightgray'
},
lastView:{
alignItems:'center',
paddingVertical:5,
borderBottomWidth:1,
borderTopWidth:1
}
});
The result is that on downward scrolling, the scrollview expands and takes up the entire screen, and shrinks when the user scrolls to the top.
Edit : I found that simply grabbing the y position and the height of the view directly before the scroll view made it easy to calculate where the position the ScrollView, allowing for the ScrollView to be positioned absolute all the time.
Here is a very basic example of how to use FlatList (similar to ScrollView) and allow for the scrolling behavior you are wanting:
import React from "react";
import {Text,View} from "react-native";
const App = () => {
const myData = {//everything you want rendered in flatlist}
const renderSomeStuff = () => {
return (
<View>
<Text> Some Stuff </Text>
</View>
)
};
const renderOtherStuff = () => {
return (
<View>
<Text> Other Stuff </Text>
</View>
);
};
return (
<View>
<FlatList
data={myData}
keyExtractor={(item) => `${item.id}`}
showsVerticalScrollIndicator
ListHeaderComponent={
<View>
{renderSomeStuff()}
{renderOtherStuff()}
</View>
}
renderItem={({ item }) => (
<View>
<Text>{item}</Text>
</View>
)}
ListFooterComponent={
<View></View>
}
/>
</View>
);
};
export default App;

FlatList ref scrollToIndex is not a function

I am facing what seems to be a long-lasting issue in react native.
I am using Expo SDK35 with RN version 0.59. I have not updated to Expo SDK36 / RN 0.60 yet, due to large code base, but I could update if that makes up for a solution to my issue.
I have an Animated.View component that has a FlatList child, and I am unable to use the static methods (scrollToIndex() in particular) that should be available on the FlatList reference. See the next example code:
class Example extends React.Component{
constructor(props){
super(props);
this.myRef = null;
}
componentDidUpdate = () => {
/*
somewhere in code outside this class, a re-render triggers
and passes new props to this class.
I do have props change detection, and some more other code,
but I have removed it in order to minimize the code example here
*/
// This call throws:
// TypeError: undefined is not a function (near '...this._scrollRef.scrollTo...')
this.myRef.scrollToIndex({
animated: true,
index: 1,
viewOffset: 0,
viewPosition: 0.5
});
// Other suggested solution from SO
// This also throws:
// TypeError: _this.myRef.getNode is not a function. (In '_this.myRef.getNode()', '_this.myRef.getNode' is undefined)
this.myRef.getNode().scrollToIndex({
animated: true,
index: 1,
viewOffset: 0,
viewPosition: 0.5
});
}
render = () => <Animated.View style={{ /* ... some animated props */ }}>
<FlatList ref={(flatListRef) => { this.myRef = flatListRef; }}
// more FlatList related props
/>
</Animated.View>
}
I have tried to use Animated.FlatList instead, still throws the same errors as in the code example above.
I have also tried to use react native's findNodeHandle() utility function on the received flatListRef parameter, but it returns null.
I have found the same issue posted multiple times in the past here on Stack Overflow, most with no answer, or which do not work for me. These posts are also a bit old (a year or so), which is why I am posting again for the same issue.
Did anyone manage to find a solution/workaround for this issue?
EDIT: Possible workaround
As I was playing with code, I tried to use a ScrollView component instead of FlatList - and the scrollTo method works!
The changes were only on the FlatList - ScrollView specific props (so, for a ScrolLView it would be childs instead of data={[...]} and renderItem={()=>{ ... }}, ect.), and the scrollToIndex method in componentDidMount which was replaced by scrollTo.
The render method of the class, with a ScrollView, now looks like this:
render = () => <Animated.View style={{ /* ... some animated props */ }}>
<ScrollView ref={(flatListRef) => { this.myRef = flatListRef; }}>
{/*
this.renderItem is almost the same as the
renderItem method used on the FlatList
*/}
{ this.state.dataArray.map(this.renderItem) }
</ScrollView>
</Animated.View>
Please note that ScrollView does not have a scrollToIndex() method, so you'll have to cope with manually keeping track of child positions, and maybe, implement a scrollToIndex method of your own.
I am not making this the answer to my question, because the underlying issue remains. But as a workaround, maybe you can go with it and call it a day...
TL;DR;
this.myRef = React.createRef();
this.myRef.current.doSomething(); // note the use of 'current'
Long version:
While the idea behind what I was trying was correct, the error in my original post seems to be quite stupid. In my defense, the docs were not clear (probably...). Anyway...
React.createRef returns an object with a few fields on it, all of them useless for the developer (used by React in the back) - except one: current.
This prop holds the current reference to the underlying component that the ref is attached to. The main ref object is not usable for the purpose I meant to in my original question above.
Instead, this is how I should've used the ref correctly:
this.myRef.current.scrollToIndex(...)
Hold up, don't crash
Both the main myRef object, and the current field will be null if the component has not yet mounted, has unmounted at any point later, or if the ref cannot be attached to it for some reason. As you may know (or found out later), null.something will throw an error. So, to avoid it:
if ((this.myRef !== null) && (this.myRef.current !== null)){
this.myRef.current.scrollToIndex(...);
}
Extra insurance
If you try to call an undefined value as a function on a field on the ref, your code will crash. This can happend if you mistakenly reuse the same ref on multiple components, or if the component you attached it to does not have that method (i.e. View does not have a scrollTo method). To fix this you have two solutions:
// I find this to be the most elegant solution
if ((this.myRef !== null) && (this.myRef.current !== null)) {
if (typeof this.myRef.current.scrollToIndex === "function") {
this.myRef.current.scrollToIndex(...);
}
}
or
if ((this.myRef !== null) && (this.myRef.current !== null)) {
if (typeof this.myRef.current.scrollToIndex === "function") {
try {
this.myRef.current.scrollToIndex(...);
} catch (error) {
console.warn("Something went wrong", error);
}
}
}
I hope this to be useful for anyone else learning to use refs in React. Cheers :)
With Animated.ScrollView:
Create a ref to your FlatList (the old way only works):
<ScrollView ref={ (ref) => (this.MyRef=ref) } />
Access scrollToIndex using this.myRef.getNode().scrollToIndex
Animated.FlatList is currently not working unfortunately...
With FlatList:
Create a ref to your FlatList by:
<FlatList ref={ this.flatListRef } />
constructor(props) {
super(props);
this.flatListRef = React.createRef();
}
Access scrollToIndex using this.flatListRef.current.scrollToIndex
Also make sure to wrap your code inside an if statement like:
if (this.myRef.getNode()) { this.flatListRef.getNode().scrollToIndex(); }
o do not know if this will help you... it scroll to a especific item in the list:
/*Example to Scroll to a specific position in scrollview*/
import React, { Component } from 'react';
//import react in our project
import {
View,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
Image,
TextInput,
} from 'react-native';
//import all the components we needed
export default class App extends Component {
constructor() {
super();
//Array of Item to add in Scrollview
this.items = [
'zero',
'one',
'two',
'three',
'four',
'five',
'six',
'seven',
'eight',
'nine',
'ten ',
'eleven',
'twelve',
'thirteen',
'fourteen',
'fifteen',
'sixteen',
'seventeen',
'eighteen',
'nineteen',
'twenty ',
'twenty-one',
'twenty-two',
'twenty-three',
'twenty-four',
'twenty-five',
'twenty-six',
'twenty-seven',
'twenty-eight',
'twenty-nine',
'thirty',
'thirty-one',
'thirty-two',
'thirty-three',
'thirty-four',
'thirty-five',
'thirty-six',
'thirty-seven',
'thirty-eight',
'thirty-nine',
'forty',
];
//Blank array to store the location of each item
this.arr = [];
this.state = { dynamicIndex: 0 };
}
downButtonHandler = () => {
if (this.arr.length >= this.state.dynamicIndex) {
// To Scroll to the index 5 element
this.scrollview_ref.scrollTo({
x: 0,
y: this.arr[this.state.dynamicIndex],
animated: true,
});
} else {
alert('Out of Max Index');
}
};
render() {
return (
<View style={styles.container}>
<View
style={{
flexDirection: 'row',
backgroundColor: '#1e73be',
padding: 5,
}}>
<TextInput
value={String(this.state.dynamicIndex)}
numericvalue
keyboardType={'numeric'}
onChangeText={dynamicIndex => this.setState({ dynamicIndex })}
placeholder={'Enter the index to scroll'}
style={{ flex: 1, backgroundColor: 'white', padding: 10 }}
/>
<TouchableOpacity
activeOpacity={0.5}
onPress={this.downButtonHandler}
style={{ padding: 15, backgroundColor: '#f4801e' }}>
<Text style={{ color: '#fff' }}>Go to Index</Text>
</TouchableOpacity>
</View>
<ScrollView
ref={ref => {
this.scrollview_ref = ref;
}}>
{/*Loop of JS which is like foreach loop*/}
{this.items.map((item, key) => (
//key is the index of the array
//item is the single item of the array
<View
key={key}
style={styles.item}
onLayout={event => {
const layout = event.nativeEvent.layout;
this.arr[key] = layout.y;
console.log('height:', layout.height);
console.log('width:', layout.width);
console.log('x:', layout.x);
console.log('y:', layout.y);
}}>
<Text style={styles.text}>
{key}. {item}
</Text>
<View style={styles.separator} />
</View>
))}
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 30,
},
separator: {
height: 1,
backgroundColor: '#707080',
width: '100%',
},
text: {
fontSize: 16,
color: '#606070',
padding: 10,
},
});
if i completly wrong, tell me...
Because ScrollView has no scrollToOffset function and It has only scrollTo function.
So let use function scrollTo with ScrollView or scrollToOffset with FlatList and it works normal.
If you are working with 'KeyboardAwareFlatList' this worked nicely:
https://github.com/APSL/react-native-keyboard-aware-scroll-view/issues/372
In short, use useRef and use the innerRef property of the KeyboardAwareFlatList rather than the ref property.

Create a reusable React Native Modal Component

I'm going back to basics with React Native, as I feel overwhelmed. I have been looking for an implementation of a reusable modal component. I'm looking for examples of a reusable Modal component in RN? Thanks in advance
You can find many examples of this on StackOverflow. Still, if you need example I can help you with one example. You have mentioned modal component in your question, right?
Your component will look like this with props. let the name be ModalComponent for this file.
render() {
const { isVisible, message, textValue } = this.props;
return (
<Modal
animationType="slide"
transparent={false}
isVisible={isVisible}
backdropColor={"white"}
style={{ margin: 0 }}
onModalHide={() => {}}>
<View>
<Text>textValue</Text>
<Text>message</Text>
</View>
</Modal>
);
}
so now in your js file you need to import this modalComponent and after that, you need to write as
<ModalComponent
isVisible={true}
textValue={'hi there'}
message={'trying to make a basic component modal'}/>
Hope this will help for you
EDIT:
Create seperate components that you want to render inside modal. for Ex: component1.js, component2.js, component3.js with props
component1.js:
render(){
const { textVal, message } = this.props
return (
<View>
<Text>{textVal}</Text>
<Text>{message}</Text>
</View>
)
}
now in ModalComponent
render() {
const { first, second, third, isVisible, component1Text, component1Message } = this.props;
<Modal
animationType="slide"
transparent={false}
isVisible={isVisible}
backdropColor={"white"}
style={{ margin: 0 }}
onModalHide={() => {}}>
<View>
{first && <component1
textValue= component1Text
message= component1Message />}
{second && <Component2 />}
{third && <Component2 />}
</View>
</Modal>
In this way, you can achieve it within the single modal.
You will make a component like this giving the parent component all the liberty to change it through props.
render() {
const { isVisible, message, textValue, animationType, backDropColor, style, onModalHide, children } = this.props;
return (
<Modal
animationType= {animationType || 'slide'}
transparent={transparent || false}
isVisible={isVisible || false}
backdropColor={backdropColor || "white"}
style={[modalStyle, style]}
onModalHide={onModalHide}>
{children}
</Modal>
);
}
Then in your parent component, you need to import this component like this:
import ModalComponent from '../ModalComponent'; //path to your component
<ModalComponent isVisible={true}>
<View>
//any view you want to be rendered in the modal
</View>
</ModalComponent>
I had a lot of troubles using react-native modal, sometimes i started the app and could not close it even when i set the isVisible prop to false, it is even worst on IOs, i did a research and these packages are not being maintained properly.
You will save a lot of time by using a top-level navigator like is recommended in the modal docs: https://facebook.github.io/react-native/docs/modal.
I tried https://github.com/react-native-community/react-native-modal but had the same problems because its an extension of the original react-native modal.
I suggest you to use the react-navigation modal as described here: https://reactnavigation.org/docs/en/modal.html#docsNav
You can refer the following code to write Modal component once and use multiple times.
Write once:
import React, { Component } from 'react';
import { View, Text, Button, Modal, ScrollView, } from 'react-native';
export class MyOwnModal extends Component {
constructor(props) {
super(props);
this.state = {
}
render() {
return(
<Modal
key={this.props.modalKey}
transparent={this.props.istransparent !== undefined ? true : false}
visible={this.props.visible}
onRequestClose={this.props.onRequestClose}>
<View style={{
//your styles for modal here. Example:
marginHorizontal: width(10), marginVertical: '30%',
height: '40%', borderColor: 'rgba(0,0,0,0.38)', padding: 5,
alignItems: 'center',
backgroundColor: '#fff', elevation: 5, shadowRadius: 20, shadowOffset: { width: 3, height: 3 }
}}>
<ScrollView contentContainerStyle={{ flex: 1 }}>
{this.props.children}
</ScrollView>
</View>
</Modal>
);
}
}
Now,
You can call your Modal like following example: (By doing this, you avoid re-writing the Modal and its outer styles everytime!)
Example
<MyOwnModal modalKey={"01"} visible={true} onRequestClose={() =>
this.anyFunction()} istransparent = {true}>
<View>
// create your own view here!
</View>
</MyOwnModal>
Note: If you are in using different files don't forget to import , and also you can pass the styles as props.
(You can create/customise props too based on your requirement)
Hope this saves your time.
Happy coding!
I am a contributor of react-native-use-modal.
This is an example of creating a reusable modal in a general way and using react-native-use-modal: https://github.com/zeallat/creating-reusable-react-native-alert-modal-examples
With react-native-use-modal, you can make reusable modal more easily.
This is a comparison article with the general method: https://zeallat94.medium.com/creating-a-reusable-reactnative-alert-modal-db5cbe7e5c2b

How to disable highlighting effect of TouchableOpacity when scrolling?

<TouchableOpacity style={{ flex: 1 }} >
<ImageBackground
source={require('../../images/home.jpg')}>
<View style={styles.item} collapsable={false}>
<H3>{contentData[i].name}</H3>
<Text>{contentData[i].description}</Text>
</View>
</ImageBackground>
</TouchableOpacity>
I have a list of TouchableOpacity inside a ScrollView. I want to disable highlighting effect of TouchableOpacity. When scrolling I want to highlight only when onPress event is triggered. Because it may confuse the user that it is pressed.
Simply pass activeOpactity prop with value 1.
<TouchableOpacity activeOpacity={1}>....</TouchableOpacity>
Make sure you import TouchableOpacity from "react-native" not from "react-native-gesture-handler".
Try setting the activeOpacity prop on the TouchableOpacity to 1 when scrolling. Use default settings when the user stops scrolling.
https://facebook.github.io/react-native/docs/touchableopacity#activeopacity
You can try changing param delayPressIn. Look doc.
<TouchableOpacity delayPressIn={150} >
{children}
</TouchableOpacity>
You can make use of onScrollBeginDrag and onScrollEndDrag props.
state = {
scrollBegin: false
}
scrollStart = () => this.setState({scrollBegin: true})
scrollEnd = () => this.setState({scrollBegin: false})
<ScrollView onScrollBeginDrag={this.scrollStart} onScrollEndDrag={this.scrollEnd}>
... Other stuff
</ScrollView>
and set activeOpacity={1} for TouchableOpacity when this.state.scrollBegin=true
You could try replace TouchOpacity with RectButton in 'react-native-gesture-handler'. And don't forget to replace the ScrollView import from 'react-native' to 'react-native-gesture-handler'.
I found this solution in here.
It just said:
provides native and platform default interaction for buttons that are placed in a scrollable container (in which case the interaction is slightly delayed to prevent button from highlighting when you fling)
We implemeted a custom Touchable component using TouchableOpacity as click element and a wrapper View handling the opacity of the children elements.
By setting activeOpacity={1} to default and the pressed state to true when clicking, we can delay the rest of the onPress functionality by a unnoticeable 100ms to display an opacity shift when clicking. Which is shipped to the wrapper View. The View is wrapped inside the touchable instead of outside to better preserve styling.
We also added cleanup when component is unmounted in useEffect()
import React, { useEffect, useState } from "react";
import { View, TouchableOpacity } from "react-native";
const Touchable = (props) => {
const { children, onPress } = props;
const [pressed, setPressed] = useState(false);
useEffect(() => {
return setPressed(false);
}, []);
return (
<TouchableOpacity
{...props}
activeOpacity={1}
onPress={() => {
setPressed(true);
setTimeout(() => {
setPressed(false);
onPress();
}, 100);
}}
>
<View style={{opacity: pressed ? 0.8 : 1}}>
{children}
</View>
</TouchableOpacity>
);
};
export default Touchable;
I had the same issue, so I wrote this class that I use instead of <TouchableOpacity> in my code:
import React, { Component } from 'react';
import { TouchableOpacity } from 'react-native';
import TimerMixin from 'react-timer-mixin';
class TouchableOpacityScrollable extends Component {
_onPress() {
const { onPress } = this.props;
// Looking in the TouchableOpacity source code we see that
// the touch Opacity is 150, and that it comes back in 250 milliseconds.
// #see https://github.com/facebook/react-native/blob/c416b40542ece64e26fb2298485ae42eeebc352a/Libraries/Components/Touchable/TouchableOpacity.js
this.refs.touchableOpacity.setOpacityTo(0.2, 150);
TimerMixin.setTimeout(() => {
onPress();
this.refs.touchableOpacity.setOpacityTo(1, 250);
}, 150);
}
render() {
const { style, children } = this.props;
return (
<TouchableOpacity
ref="touchableOpacity"
style={style}
activeOpacity={1.0}
onPress={() => this._onPress()}
>
{children}
</TouchableOpacity>
);
}
}
export default TouchableOpacityScrollable;
You will have to install react-timer-mixin to prevent possible crashes.
Enjoy!
after upgrading RN version to 0.63.2 TouchableOpacity is working like it should, during scrolling, hover effect doesn't appears

How to get the dimensions of a react-native Child Component

I just want to pass a react View inside a component and then I want to find out the dimensions of the passed (as a prop) View in another react Component.
Is it possible to find out the dimensions without using onLayout() means before
rendering the child component.
class Child extends Component {
render() {
return(
<Parent>
<View style = {{width: 100}}>
<View style = {{height: 50,flex:1}}>
</View>
<View style = {{height: 30,flex:1}}>
</View>
<View>
</Parent>
)}
}
class Parent extends Component {
getDimensions(child) {
// Here I want to find the dimensions of child Component
// In this use case it should be like height = 80 & width = 100
// set the state height and width
}
getChildComponent(child) {
// Here I want to modify the style of Child Component
var style = [
child.props.style,
{
height: this.state.height + 50,
width : this.state.width + 50
}];
return React.cloneElement(child, {style});
}
componentWillMount() {
this.getDimensions(this.props.children);
}
render() {
return (
<View>
{ this.getChildComponent(this.props.children) }
<View>
)}
}