question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Svg with TouchableOpacity

See original GitHub issue

Hi,

I would like to create my image buttons with SVG using TouchableOpacity element. But my problem is I don’t have the opacity event triggered on press button.

This is my render : render() { return ( <TouchableOpacity onPress={this.props.onPress}> <Svg width={100} height={100} viewBox="0 0 104 104" > .... </Svg> </TouchableOpacity> ); }

I would like to know how to create a button with SVG image (if it is possible).

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:9

github_iconTop GitHub Comments

6reactions
msandcommented, Jan 11, 2019

Simplified into plain component:

import React, { Component } from 'react';
import { Animated, Easing } from 'react-native';
import { G } from 'react-native-svg';

const AnimatedG = Animated.createAnimatedComponent(G);

function flattenStyle(style) {
    if (style === null || typeof style !== 'object') {
        return undefined;
    }

    if (!Array.isArray(style)) {
        return style;
    }

    const result = {};
    for (let i = 0, styleLength = style.length; i < styleLength; ++i) {
        const computedStyle = flattenStyle(style[i]);
        if (computedStyle) {
            for (const key in computedStyle) {
                result[key] = computedStyle[key];
            }
        }
    }
    return result;
}

/**
 * A wrapper for making svg elements respond properly to touches.
 * On press down, the opacity of the wrapped element is decreased, dimming it.
 *
 * Opacity is controlled by wrapping the children in an Animated.G, which is
 * added to the view hierarchy.
 *
 * Example:
 *
 * ```
 * renderRect: function() {
 *   return (
 *     <TouchableOpacityG
 *       onPress={e => {
 *         console.log('press', e);
 *       }}>
 *       <Rect x="0" y="50" width="100" height="50" fill="blue" />
 *     </TouchableOpacityG>
 *   );
 * },
 * ```
 * ### Example
 *
 * ```ReactNativeWebPlayer
 * import React from "react";
 * import {
 *   AppRegistry,
 * } from 'react-native'
 * import Svg, {
 *     Rect,
 * } from "react-native-svg";
 *
 * import TouchableOpacityG from './TouchableOpacityG';
 *
 * const App = () => (
 *     <Svg width="200" height="200" viewBox="0 0 100 100">
 *         <Rect
 *             x="0"
 *             y="0"
 *             width="100"
 *             height="50"
 *             fill="red"
 *             onPress={e => {
 *                 console.log('press1', e);
 *             }}
 *         />
 *         <TouchableOpacityG
 *             onPress={e => {
 *                 console.log('press2', e);
 *             }}>
 *             <Rect x="0" y="50" width="100" height="50" fill="blue" />
 *         </TouchableOpacityG>
 *     </Svg>
 * );
 *
 * AppRegistry.registerComponent('App', () => App)
 * ```
 *
 */
export default class TouchableOpacityG extends Component {
    static defaultProps = {
        activeOpacity: 0.2,
    };

    componentDidUpdate = (prevProps, prevState) => {
        if (this.props.disabled !== prevProps.disabled) {
            this._opacityInactive(250);
        }
    };

    /**
     * Animate the touchable to a new opacity.
     */
    setOpacityTo = (value, duration) => {
        Animated.timing(this.state.anim, {
            toValue: value,
            duration: duration,
            easing: Easing.inOut(Easing.quad),
            useNativeDriver: true,
        }).start();
    };

    touchableHandleActivePressIn = e => {
        if (e.dispatchConfig.registrationName === 'onResponderGrant') {
            this._opacityActive(0);
        } else {
            this._opacityActive(150);
        }
        this.props.onPressIn && this.props.onPressIn(e);
    };

    touchableHandleActivePressOut = e => {
        this._opacityInactive(250);
        this.props.onPressOut && this.props.onPressOut(e);
    };

    touchableHandlePress = e => {
        this.props.onPress && this.props.onPress(e);
    };

    touchableHandleLongPress = e => {
        this.props.onLongPress && this.props.onLongPress(e);
    };

    _opacityActive = duration => {
        this.setOpacityTo(this.props.activeOpacity, duration);
    };

    _opacityInactive = duration => {
        this.setOpacityTo(this._getChildStyleOpacityWithDefault(), duration);
    };

    _getChildStyleOpacityWithDefault = () => {
        const childStyle = flattenStyle(this.props.style) || {};
        return childStyle.opacity == null ? 1 : childStyle.opacity;
    };

    state = {
        anim: new Animated.Value(this._getChildStyleOpacityWithDefault()),
    };

    render() {
        return (
            <AnimatedG
                opacity={this.state.anim}
                onPress={this.touchableHandlePress}
                onLongPress={this.touchableHandleLongPress}
                onPressIn={this.touchableHandleActivePressIn}
                onPressOut={this.touchableHandleActivePressOut}
            >
                {this.props.children}
            </AnimatedG>
        );
    }
}

0reactions
Symyoncommented, Dec 29, 2021

The solution above doesn’t work on all Android devices. e.g. Works on Essential PH-1 and it doesn’t on LG G5 or Samsung S21 - the ripple effect of touching works, onPress is not called though.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Svg with TouchableOpacity · Issue #645 - GitHub
Hi,. I would like to create my image buttons with SVG using TouchableOpacity element. But my problem is I don't have the opacity...
Read more >
Touchable opacity on press not working inside SVG tags
The reason for that is that SVG is at the top as parent element, disabling the accessibility to TouchableOpacity . This means the...
Read more >
ReactNative: using SVG as a button - Krasimir Tsonev
Just recently I started using ReactNative. I've been using React for years but this thing is a whole new world.
Read more >
Test svg touchable - Expo Snack
Try this project on your phone! Use Expo's online editor to make changes and save your own copy.
Read more >
Touchable opacity on press not working inside SVG tags ...
The reason for that is that SVG is at the top as parent element, disabling the accessibility to TouchableOpacity . This means the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found