Henok Tesfaye
Henok Tesfaye

Reputation: 9560

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.

Upvotes: 36

Views: 39481

Answers (8)

Oskar Hertzman
Oskar Hertzman

Reputation: 321

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;

Upvotes: 4

0soltys
0soltys

Reputation: 36

after upgrading RN version to 0.63.2 TouchableOpacity is working like it should, during scrolling, hover effect doesn't appears

Upvotes: 0

wscheng
wscheng

Reputation: 51

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)

Upvotes: 5

Andrey Patseiko
Andrey Patseiko

Reputation: 4495

You can try changing param delayPressIn. Look doc.

<TouchableOpacity delayPressIn={150} > 
 {children}
</TouchableOpacity>

Upvotes: 12

Jeevan Prakash
Jeevan Prakash

Reputation: 776

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".

Upvotes: 65

Francois Nadeau
Francois Nadeau

Reputation: 7463

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!

Upvotes: 1

Pritish Vaidya
Pritish Vaidya

Reputation: 22199

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

Upvotes: 4

Sahesh
Sahesh

Reputation: 885

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

Upvotes: 16

Related Questions