Using expo vector icon in react native skia? - react-native

How to use expo vector icon in react native skia.
I want to use this icon,
<Ionicons name="md-checkmark-circle" size={32} color="green" /> in skia Canvas or Box
Thanks.

You can't use vector icons directly but you can add the icon as an SVG image like this:
import {
Canvas,
ImageSVG,
useSVG
} from "#shopify/react-native-skia";
const ImageSVGDemo = () => {
// Alternatively, you can pass an SVG URL directly
// for instance: const svg = useSVG("https://upload.wikimedia.org/wikipedia/commons/f/fd/Ghostscript_Tiger.svg");
const svg = useSVG(require("../../assets/checkmark.svg"));
return (
<Canvas style={{ flex: 1 }}>
{ svg && (
<ImageSVG
svg={svg}
x={0}
y={0}
width={256}
height={256}
/>)
}
</Canvas>
);
};
and the checkmark.svg file will be:
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm-1.25 16.518l-4.5-4.319 1.396-1.435 3.078 2.937 6.105-6.218 1.421 1.409-7.5 7.626z"/></svg>

Related

make svg responsive in react native

ive got an svg im using as a header in my app, i want it to be responsive so it could fit any screen.
the thing is , there is a weird white space on the left and it still not responsive.
thanks!
svg code:
import Svg, { Path, Defs, LinearGradient, Stop } from "react-native-svg"
import { Dimensions } from 'react-native';
const { height, width } = Dimensions.get('window');
function SvgComponent(props) {
const viewBox = '0 0 '+width+' '+height*0.117;
return (
<Svg width={width} height={height*0.117} viewBox={viewBox} fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
<Path
d="M0 99V0h395v99c-19.439-4.282-85.706-7.897-195.26-7.897C85.186 91.103 19.266 94.718 0 99z"
fill="url(#paint0_linear_1134_4959)"
/>
<Defs>
<LinearGradient
id="paint0_linear_1134_4959"
x1={1.8637e-7}
y1={49.5}
x2={505.032}
y2={49.5}
gradientUnits="userSpaceOnUse"
>
<Stop stopColor="#7D55AE" />
<Stop offset={1} stopColor="#5E00D0" />
</LinearGradient>
</Defs>
</Svg>
)
}
export default SvgComponent ```

How can I change icon width-height on react native?

I've created SVG component for all svg's. I just want to change width height with props but I couldn't figure out. I'm using icons like this now <SVGCustomIcon name="InboxMenu" />. how can I also add width height props?
custom SVG component
const icons: SVGCustomIconMap = {
InboxMenu: (
<Svg width={18} height={20} viewBox="0 0 18 20" fill="none">
<Path
d="M11.25 17.5c0 .629-.262 1.3-.73 1.77-.47.468-1.141.73-1.77.73a2.5 2.5 0 01-1.77-.73 2.563 2.563 0 01-.73-1.77h5z"
fill="#949494"
/>
.....
),
ProfileMenu: (
<Svg width={20} height={22} viewBox="0 0 20 22" fill="none">
......
),
};
const SVGCustomIcon = ({ name }: SVGCustomIconProps) => {
return <>{icons[name] ? icons[name] : null}</>;
};
export default SVGCustomIcon;
type.ts
export type SVGCustomIcon = React.SVGProps<SVGSVGElement>;
export interface SVGCustomIconMap {
[key: string]: SVGCustomIcon;
}
export interface SVGCustomIconProps {
name: string;
}
you can try this,
export interface SVGCustomIconMap {
[key: string]: any;
}
export interface SVGCustomIconProps {
name: string;
width?: number;
height?: number;
}
export type TSize = {
width?: number;
height?: number;
};
const icons: SVGCustomIconMap = {
InboxMenu: ({ width, height }: TSize) => {
return (
<>
<Svg
width={width || 18}
height={height || 20}
viewBox="0 0 18 20"
fill="none">
{/* .... your rest code .... */}
</>
);
},
ProfileMenu: ({ width, height }: TSize) => {
return (
<>
<Svg
width={width || 20}
height={height || 22}
viewBox="0 0 20 22"
fill="none">
{/* ...... your rest code ....... */}
</>
);
},
};
const SVGCustomIcon = ({ name, width, height }: SVGCustomIconProps) => {
const SvgCustom = icons?.[name] ? icons[name] : null;
if (!SvgCustom) {
return null;
}
return <SvgCustom width={width} height={height} />;
};
export default SVGCustomIcon;
//how to call
<SVGCustomIcon name="InboxMenu" width={20} height={22} />;
I would try adding a `preserveAspectRatio="none" to your svg component. I don't work in React Native a lot but I vaguely remember this issue.
ProfileMenu: (
<Svg width={20} height={22} viewBox="0 0 20 22" fill="none" preserveAspectRatio="none">
)
To change the width and height of an SVG icon in a React Native application, you can use the style prop of the Svg component.
Here is an example of how you can set the width and height of an SVG icon to 50 pixels:
Copy code
import { Svg } from 'react-native-svg';
function MyIcon() {
return (
<Svg width={50} height={50}>
{/* Icon content goes here */}
</Svg>
);
}
You can also use the style prop to set the width and height using a style object:
Copy code
import { Svg } from 'react-native-svg';
function MyIcon() {
return (
<Svg style={{ width: 50, height: 50 }}>
{/* Icon content goes here */}
</Svg>
);
}
Keep in mind that the width and height of the Svg component will determine the size of the entire icon, including any elements inside it. You may need to adjust the size of the individual elements within the icon as well to achieve the desired appearance.

react-native-tvos - TouchableOpacity Causes SVG Elements to Disappear

I am using react-native-tvos to create an app.
I am trying to display SVG elements that respond to the remote.
I have tried using TouchableOpacity as well as Pressable on the elements.
Whenever I wrap the elements with those they no longer appear.
I've looked through dozens of S/O posts and have tried various things. Such as zIndex, flex on container. I also tried the react-native-gesture-handler, but that doesn't seem to work for tvos.
I've broken the code down to something very simple. Just a circle in the middle of the screen.
import Svg, {Circle} from 'react-native-svg';
import * as React from 'react';
import {TouchableOpacity, View,} from 'react-native';
const App = () => {
return (
<View>
<Svg x="0px" y="0px" viewBox="0 0 1920 1080" style="enable-background:new 0 0 1920 1080;">
<TouchableOpacity style={{
opacity: 1,
fill: "#FF0000",
stroke: "5",
zIndex: 100,
}} onPress={() => alert('PRESSED')}>
<Circle cx="960" cy="540" r="100" opacity="1" fill="#FF0000"/>
</TouchableOpacity>
</Svg>
</View>
);
};
export default App;

How to manage dynamic fill with React Native SVG

I have some SVGs in my React native .66.1 app, and I've set up react-native-svg and react-native-svg-transformer and have set it up correctly. I can import my SVGs as components, and it all works as expected.
However, I don't know how to dynamically set the fill based on an expression in my app. For instance, I can set the gradient in my SVG, but I can't override the color on the state change.
How do you set it up to track a value, or how to override it?
My SVG:
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="0 0 26 26" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient gradientUnits="userSpaceOnUse" x1="12.99" y1="0" x2="12.99" y2="25.92" id="gradient" gradientTransform="matrix(0.707053, -0.707161, 1.001161, 1.001008, -9.106794, 9.237734)">
<stop offset="0" style="stop-color: rgb(161, 70, 183);"/>
<stop offset="1" style="stop-color: rgb(0, 38, 94);"/>
</linearGradient>
</defs>
<path d="M13.91.38a1.3 1.3 0 0 0-1.84 0L.33 12.14c-.4.4-.35.73-.29.89.06.16.25.44.8.44h1.32v10.45a2 2 0 0 0 1.92 2h5.95v-7.08h5.76v7.08h6.1c1.03 0 1.9-.93 1.9-2V13.47h1.36c.54 0 .73-.28.79-.44.06-.16.1-.5-.28-.9L13.9.39Z" fill-rule="evenodd" />
</svg>
My Drawer Screen:
<Drawer.Screen name="Home" options={{ drawerIcon: ({color, size, focused}) => <HomeIcon style={{maxWidth: 28}} fill={focused ? colors.primary.purpleMain : darkMode ? 'white' : 'black'} />}} component={Home} />
What I want:
I want the icon to be the gradient on focused, and either black or white depending on darkMode. Any ideas? I've tried setting the fill in App.tsx, but it doesn't track. This is what I tried: 'url(#gradient)' (gradient is the id of the linearGradient in my svg).
My perfect situation would be not to have to embed the linearGradient in every SVG, but to 'set' it to each solid SVG (just a 135deg purple gradient).
It's worth noting my dynamic color works if I just use regular colors and I omit the fill property inside my SVG. Also - if I use 'currentColor' inside my SVG, the color just remains blue, but I don't even see anywhere that the color blue is called.
i would suggest you to create font (ie: .ttf) format for your icons using https://icomoon.io/, after that replace Icon from GradientIcon adng home page respectively,
Here i am using react-native-vector-icons for icons
working example: Snack Expo
GradientIcon.tsx
import React, { FC } from 'react';
import {
View,
StyleSheet,
StyleProp,
ViewStyle,
ViewProps,
} from 'react-native';
import IonIcon, { IconProps } from 'react-native-vector-icons/Ionicons';
// in bare react native use. react-native-linear-gradient
import { LinearGradient } from 'expo-linear-gradient';
import MaskedView, {
MaskedViewProps,
} from '#react-native-community/masked-view';
/**
* GradientIonIconProps
*/
type GradientIonIconProps = IconProps & {
colors?: string[];
containerStyle?: StyleProp<ViewStyle>;
start?: {
x: number;
y: number;
};
end?: {
x: number;
y: number;
};
};
/**
* GradientIonIcon
*/
const GradientIonIcon: FC<GradientIonIconProps> = (props) => {
const {
children,
containerStyle,
start = { x: 0, y: 0 },
end = { x: 1, y: 0 },
colors = ['#3D7BF7', '#26CCFF'],
...rest
} = props;
return (
<MaskedView
style={containerStyle}
maskElement={
<IonIcon {...rest} style={{ color: '#fff' }} color="#fff" />
}>
<LinearGradient {...{ colors, start, end }}>
<IonIcon {...rest} color="transparent" />
</LinearGradient>
</MaskedView>
);
};
export default GradientIonIcon;
create home icon container which updates only when size ans focused props changes
IconContainer
const HomeIconContainer: React.FC<{ size: number; focused: boolean }> =
React.memo(
({ size, focused }) => {
console.log(focused);
const Icon = React.useMemo(
() => (focused ? GradientIonIcon : IonIcon),
[focused]
);
return (
<Icon
containerStyle={{ width: size, height: size }}
size={size}
name="ios-home"
color="purple"
/>
);
},
(prev, next) => prev.size === next.size && prev.focused === next.focused
);
then use this icon in your navigation options
DraerNAvigator
<Drawer.Screen
name="Home"
options={{
drawerIcon: ({ size, focused }) => (
<HomeIconContainer {...{ size, focused }} />
),
}}
component={Home}
/>
#Result
focused
unfocused

Accessibility issue for custom buttons made from SVGs

I'm trying to add accessibility to my app (disclosure, using 0.59.8 version of RN). I have SVG images (each in separate TSX files, called like "IconClose") that I am using to make custom buttons. When I call these SVGs, I wrap them in a TouchableOpacity with style and an onPress to make them act as buttons. I tried adding an accessibilityLabel="close button" and setting the accessibilityRole and the accessibilityTraits to the TouchableOpacity. They work as buttons and do the navigation perfectly, however when I check the accessibility, I can tap on the button to select it, but I get nothing as far as the voice reader in iOS saying the label or the hint. I've tried wrapping it in a View, I tried adding titles and aria-label to the SVG. Is there a way to make these custom buttons voice reader accessible?
the IconClose button
import React from 'react';
import Svg, { Path } from 'svgs';
export const IconClose = (props: any) => (
<Svg viewBox="0 0 24 24" width="24" height="24" fill="#000000" {...props} >
<Path
d="M13.4 12l6.3-6.3c.4-.4.4-1 0-1.4s-1-.4-1.4 0L12 10.6 5.7 4.3c-.4-.4-1-.4-1.4 0s-.4 1 0 1.4l6.3 6.3-6.3 6.3c-.4.4-.4 1 0 1.4.2.2.4.3.7.3s.5-.1.7-.3l6.3-6.3 6.3 6.3c.2.2.5.3.7.3s.5-.1.7-.3c.4-.4.4-1 0-1.4L13.4 12z"
fill="#231f20"
/>
</Svg>
);
where I call the button
export const Page: FC<IPageProps> = ({ imageSource, location, title, info, actions, content, footer, onCloseButtonPress }) => {
const renderHeader = () => {
return (
<View style={styles.header}>
{imageSource
? <Image style={styles.image} source={imageSource} />
: <IconImage width={120} height={120} fill={COLORS.TECH_GRAY} />
}
<TouchableOpacity
style={styles.closeIcon}
onPress={onCloseButtonPress}
activeOpacity={0.8}
accessibilityComponentType="button"
accessibilityLabel="close">
<IconClose/>
</TouchableOpacity>
</View>
);
};