如何使用 React Native SVG 管理动态填充

Posted

技术标签:

【中文标题】如何使用 React Native SVG 管理动态填充【英文标题】:How to manage dynamic fill with React Native SVG 【发布时间】:2022-01-20 02:41:58 【问题描述】:

我的 React 本机 .66.1 应用程序中有一些 SVG,我已经设置了 react-native-svgreact-native-svg-transformer 并且设置正确。我可以将我的 SVG 作为组件导入,一切都按预期工作。

但是,我不知道如何根据我的应用程序中的表达式动态设置填充。例如,我可以在我的 SVG 中设置渐变,但我不能在状态更改时覆盖颜色。

你如何设置它来跟踪一个值,或者如何覆盖它?

我的 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>

我的抽屉屏幕:

<Drawer.Screen name="Home" options= drawerIcon: (color, size, focused) => <HomeIcon style=maxWidth: 28 fill=focused ? colors.primary.purpleMain : darkMode ? 'white' : 'black' /> component=Home />

我想要什么:

我希望图标是焦点上的渐变,并且是黑色或白色,具体取决于darkMode。有任何想法吗?我尝试在 App.tsx 中设置填充,但它不跟踪。这是我尝试过的:'url(#gradient)'(渐变是我的 svg 中的线性渐变的 id)。

我的理想情况是不必在每个 SVG 中嵌入 linearGradient,而是将其“设置”到每个实体 SVG(仅 135 度紫色渐变)。

值得注意的是,如果我只使用常规颜色并在我的 SVG 中省略 fill 属性,我的动态颜色就可以工作。另外 - 如果我在我的 SVG 中使用“currentColor”,颜色会保持蓝色,但我什至看不到任何调用蓝色的地方。

【问题讨论】:

【参考方案1】:

我建议您使用https://icomoon.io/ 为您的图标创建字体(即:.ttf)格式,然后分别替换来自 GradientIcon 和主页的图标,

这里我使用 react-native-vector-icons 作为图标

工作示例: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;

创建仅在大小和焦点道具更改时更新的主页图标容器

图标容器

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
  );

然后在导航选项中使用此图标

DraerNAvigator

<Drawer.Screen
    name="Home"
    options=
      drawerIcon: ( size, focused ) => (
        <HomeIconContainer ... size, focused  />
      ),
    
  component=Home
/>

#结果

专注

注意力不集中

【讨论】:

字体性能不佳,我很难让它们在 iOS 和 android 上看起来一致。另外 - got 是一种动态设置渐变填充的方法。我知道你可以定期做出反应,而且我确定必须有一种方法可以让 svgs 与本机反应。我什至不知道要具体要求什么才能得到我需要的东西。 ://

以上是关于如何使用 React Native SVG 管理动态填充的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 React-Native 和 Reanimated 2 为 svg 设置动画道具变换

React Native - 如何使用本地 SVG 文件(并为其着色)

如何在react-native中显示动画svg?

React Native 和 Expo - SVG 不会在 iOS 设备上呈现

无法使用 react-native-svg 或 Svg/expo 让 Svg 显示在 react-native 中

如何在React Native中为SVG坐标设置动画?