跳转至正文
开发 移动端

RN 中的 expo-linear-gradient 和 react-native-linear-gradient

Expo 中使用 expo-linear-gradient,原生 RN 中使用 react-native-linear-gradient。涵盖背景、圆角、动画微光效果,以及不显示时的故障排查。

React Native Capgo 博客中的 expo-linear-gradient 和 react-native-linear-gradient

快速选择: 中的 Expo,使用 expo-linear-gradient。在 bare React Native,使用 react-native-linear-gradient中。安装与你技术栈匹配的版本,然后渲染一个 LinearGradient 配合 colors 和一个带尺寸的 style (通常 flex: 1 作为背景)。

Expo

bunx expo install expo-linear-gradient

纯 React Native

bun add react-native-linear-gradient

最简用法 (两个库思路相同:Expo 用命名导出,bare 用默认导入。)

import { LinearGradient } from 'expo-linear-gradient';
// Bare: import LinearGradient from 'react-native-linear-gradient';

<LinearGradient colors={['#0f172a', '#2563eb']} style={{ flex: 1 }} />;

如果你正在原生技术栈和 Web 优先外壳之间做选择, React Native 与 Capacitor 梳理了 Capgo 团队关心的取舍。本文其余部分涵盖背景、按钮、遮罩、动效和故障排查。

目录

为什么你的 React Native 应用需要渐变效果

很多移动 UI 失败的原因都一样。布局没问题,间距没问题,排版也过得去,但屏幕看起来依然死气沉沉。除非视觉系统的其他部分足够出彩,否则纯色填充会让一切看起来像占位符。

一套 React Native 线性渐变 这个组件只需很少的 code 就能解决这个问题。它能增加层次感,在区块之间形成分隔,并让高优先级元素拥有清晰的视觉权重。好的渐变背景能让登录页显得更用心。好的渐变按钮能让主操作一目了然,而无需依赖厚重的阴影或过于抢眼的边框。

作者 2019 年,expo-linear-gradient 和 react-native-linear-gradient 出现在超过 42% 的 React Native 项目中,这强烈表明渐变不再是小众效果。它们已是生产级应用中的标准 UI 工具,而不是最后才硬加上去的装饰,正如 这篇关于 React Native 渐变采用情况的文章所指出的.

渐变色的优势

  • 营造层次感: 单一纯色背景往往显得单调。微妙的从上到下渐变能让界面更具层次感。
  • 引导视觉焦点: 主要 CTA、引导卡片和 Hero 标题能脱颖而出,且不增加视觉噪音。
  • 替代图片资源: 在许多情况下,渐变能提升精致度,而无需打包额外的背景图片。

实战规则: 在需要体现层级关系的地方使用渐变。背景、Hero 卡片、CTA 区域和媒体叠加层效果最明显。表单字段、密集列表和正文容器通常不需要。

这里还有一个产品设计层面的考量。跨平台工作的团队已经在花时间让界面保持一致。如果这也是你技术栈的一部分,那么这些 移动应用的跨平台 UI 和 UX 实践 与这一思路高度契合:更少的素材、更多可复用的界面,以及能在不同屏幕上保持一致的视觉系统。

方案选择:Expo 还是 Bare React Native 环境

这是最让人头疼的分岔点。两者的 API 渲染效果几乎完全一致,但配置过程却大不相同。

如果你使用的是 Expo 托管应用,请使用 expo-linear-gradient。如果你使用的是 Bare React Native 应用,请使用 react-native-linear-gradient。除非你非常清楚为什么要这样做,否则不要试图模糊这两者的界限。

Expo 托管工作流与 Bare React Native 工作流实现线性渐变的对比信息图。

Expo 环境配置

Expo 是更顺畅的路径。安装简单,版本匹配会自动处理,你无需担心 native linking 问题。

安装方式如下:

bunx expo install expo-linear-gradient

使用方式如下:

import React from 'react';
import { StyleSheet, View, Text } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';

export default function App() {
  return (
    <LinearGradient
      colors={['#0f172a', '#1d4ed8']}
      style={styles.container}
    >
      <Text style={styles.text}>Hello gradient</Text>
    </LinearGradient>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    color: '#fff',
    fontSize: 24,
    fontWeight: '700',
  },
});

如果你追求快速上手、合理的默认配置和更少的原生端坑点,Expo 是合适的选择。这也是为什么探索高级 Expo 工作流的团队,常常会对比 Capgo 和 Expo EAS 的 Live Update 方案 当托管路径无法满足应用需求时。

Bare React Native 环境配置

Bare React Native 让你直接访问原生模块,但坑也得自己填。

安装这个包:

bun add react-native-linear-gradient

iOS 端安装 pods:

cd ios && pod install

基础用法:

import React from 'react';
import { StyleSheet, Text } from 'react-native';
import LinearGradient from 'react-native-linear-gradient';

export default function App() {
  return (
    <LinearGradient
      colors={['#111827', '#7c3aed']}
      style={styles.container}
    >
      <Text style={styles.text}>Hello gradient</Text>
    </LinearGradient>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    color: '#fff',
    fontSize: 24,
    fontWeight: '700',
  },
});

Bare 项目常见的坑

大多数教程都忽略了测试和原生配置。根据 这个 Stack Overflow 讨论摘要, 2024 至 2025 年间,Stack Overflow 上关于此主题的 68% 帖子涉及裸 React Native 配置中的原生模块故障,同一来源还指出 Jest 模拟和 iOS CocoaPods 冲突是反复出现的问题。

如果你在裸应用中使用 Jest,请显式添加 mock:

// jest.setup.js
import mockRNLinearGradient from 'react-native-linear-gradient/jest/linear-gradient-mock';

jest.mock('react-native-linear-gradient', () => mockRNLinearGradient);

并在 Jest 配置中引用这个 setup 文件:

module.exports = {
  preset: 'react-native',
  setupFiles: ['<rootDir>/jest.setup.js'],
};

Bare React Native 做渐变没问题,只是对配置不完整零容忍。大多数失败并不是视觉 bug,而是 linking、pods 或测试环境问题。

下面是实用的决策表:

项目类型 库 最合适
Expo 托管应用 expo-linear-gradient 最快路径,最少配置
Bare React Native 应用 react-native-linear-gradient 完全的原生控制
带 Jest 的 Bare 应用 react-native-linear-gradient + mock 保持测试稳定所必需

UI 元素的核心渐变技术

一种常见做法是反复使用同一组小型渐变模式。背景、按钮、标题。如果这三者设计得当,你就可以在许多屏幕中复用它们。

一个人正在使用笔记本电脑,屏幕上显示着带有彩色渐变设计元素的现代仪表盘界面。

一个有用的思维模型如下:

  • colors 控制调色板
  • start 以及 end 控制方向
  • locations 控制过渡发生的位置

如果你的启动屏或 onboarding 入口界面使用了渐变,它自然能搭配本文介绍的更完整的启动序列模式 React Native 启动屏指南.

全屏渐变背景

这是最简单且复用性最高的模式。

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';
// For bare RN, switch to:
// import LinearGradient from 'react-native-linear-gradient';

export default function WelcomeScreen() {
  return (
    <LinearGradient
      colors={['#0f172a', '#1e293b', '#2563eb']}
      start={{ x: 0, y: 0 }}
      end={{ x: 1, y: 1 }}
      style={styles.container}
    >
      <View style={styles.content}>
        <Text style={styles.title}>Welcome back</Text>
        <Text style={styles.subtitle}>Your workspace is ready.</Text>
      </View>
    </LinearGradient>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  content: {
    flex: 1,
    justifyContent: 'center',
    paddingHorizontal: 24,
  },
  title: {
    color: '#fff',
    fontSize: 32,
    fontWeight: '800',
    marginBottom: 8,
  },
  subtitle: {
    color: 'rgba(255,255,255,0.8)',
    fontSize: 16,
  },
});

对角线渐变通常比默认的垂直渐变更具动态感。这就是为什么 start={{ x: 0, y: 0 }} 以及 end={{ x: 1, y: 1 }} 当屏幕主要用于装饰时,它们是很好的默认选择。

不要孤立地选择颜色。要在真实的文本、图标和状态栏样式下进行测试。在 Figma 中好看的配色,一旦叠加内容后可能会瞬间失效。

保留按钮交互的渐变按钮

这里常见的错误是直接在渐变层上绑定触摸行为,却忽略了禁用状态、按压反馈或内边距一致性。让按钮保持语义化,把渐变只当作视觉层。

import React from 'react';
import {
  Pressable,
  StyleSheet,
  Text,
  ViewStyle,
  StyleProp,
} from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';

type Props = {
  title: string;
  onPress: () => void;
  disabled?: boolean;
  style?: StyleProp<ViewStyle>;
};

export function GradientButton({
  title,
  onPress,
  disabled = false,
  style,
}: Props) {
  return (
    <Pressable onPress={onPress} disabled={disabled} style={style}>
      {({ pressed }) => (
        <LinearGradient
          colors={
            disabled
              ? ['#94a3b8', '#94a3b8']
              : pressed
              ? ['#7c3aed', '#2563eb']
              : ['#8b5cf6', '#3b82f6']
          }
          start={{ x: 0, y: 0.5 }}
          end={{ x: 1, y: 0.5 }}
          style={styles.button}
        >
          <Text style={styles.label}>{title}</Text>
        </LinearGradient>
      )}
    </Pressable>
  );
}

const styles = StyleSheet.create({
  button: {
    minHeight: 52,
    borderRadius: 14,
    alignItems: 'center',
    justifyContent: 'center',
    paddingHorizontal: 20,
  },
  label: {
    color: '#fff',
    fontSize: 16,
    fontWeight: '700',
  },
});

对于按钮,水平渐变通常比对角线渐变更易读。它能保持标签稳定,避免让控件产生倾斜感。

使用 Mask 实现渐变文字

这是这套设计中最花哨的模式,克制使用会很有用。Hero 标题、升级横幅和空状态标题都很适合,正文段落则不适合。

你需要 @react-native-masked-view/masked-view.

bun add @react-native-masked-view/masked-view

然后构建文本遮罩:

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import MaskedView from '@react-native-masked-view/masked-view';
import { LinearGradient } from 'expo-linear-gradient';

export default function GradientHeadline() {
  return (
    <View style={styles.container}>
      <MaskedView
        maskElement={
          <View style={styles.maskWrapper}>
            <Text style={styles.title}>Premium analytics</Text>
          </View>
        }
      >
        <LinearGradient
          colors={['#22c55e', '#06b6d4', '#3b82f6']}
          start={{ x: 0, y: 0 }}
          end={{ x: 1, y: 0 }}
          locations={[0, 0.5, 1]}
        >
          <Text style={[styles.title, styles.hiddenText]}>Premium analytics</Text>
        </LinearGradient>
      </MaskedView>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    padding: 24,
  },
  maskWrapper: {
    backgroundColor: 'transparent',
  },
  title: {
    fontSize: 34,
    fontWeight: '800',
    letterSpacing: -1,
  },
  hiddenText: {
    opacity: 0,
  },
});

locations 当你想让一种颜色比另一种占据更多视觉空间时,这一点最关键。如果混合效果发浑,先减少颜色数量。通常这比逐个调整色标更快修好设计。

通过动画让渐变动起来

静态渐变提升质感,动画渐变提供反馈。

最实用的场景并不是炫酷背景,而是 Shimmer 加载器。这种效果能告诉用户应用还在运行、数据正在加载,而且当前布局是有意设计的,不是出错了。

一只手拿着智能手机,屏幕上显示着设计精美、带渐变效果的移动银行 App dashboard。

Shimmer 组件也能与其他动效模式相辅相成。如果你的应用已经使用了动画图标或加载器,那么这篇 React Native 中的 Lottie 指南 有助于判断何时渐变 Shimmer 就够用,以及何时更适合使用更丰富的动画资源。

具有原生感的 Shimmer 加载效果

最简单可靠的版本使用 react-native-reanimated 在裁剪后的占位符上移动渐变条。

如果应用中尚未安装 Reanimated,请先安装,然后创建一个包含以下内容的包装器: overflow: 'hidden'。在其中,让渐变层从左向右动画。

import React, { useEffect } from 'react';
import { StyleSheet, View, ViewStyle, StyleProp } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';
import Animated, {
  useAnimatedStyle,
  useSharedValue,
  withRepeat,
  withTiming,
  Easing,
} from 'react-native-reanimated';

const AnimatedView = Animated.createAnimatedComponent(View);

type Props = {
  width?: number | string;
  height?: number;
  borderRadius?: number;
  style?: StyleProp<ViewStyle>;
};

export function ShimmerPlaceholder({
  width = '100%',
  height = 16,
  borderRadius = 8,
  style,
}: Props) {
  const translateX = useSharedValue(-220);

  useEffect(() => {
    translateX.value = withRepeat(
      withTiming(220, {
        duration: 1200,
        easing: Easing.linear,
      }),
      -1,
      false
    );
  }, [translateX]);

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ translateX: translateX.value }],
  }));

  return (
    <View
      style={[
        styles.container,
        { width, height, borderRadius },
        style,
      ]}
    >
      <AnimatedView style={[styles.shimmer, animatedStyle]}>
        <LinearGradient
          colors={['rgba(255,255,255,0)', 'rgba(255,255,255,0.35)', 'rgba(255,255,255,0)']}
          start={{ x: 0, y: 0.5 }}
          end={{ x: 1, y: 0.5 }}
          style={styles.gradient}
        />
      </AnimatedView>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    overflow: 'hidden',
    backgroundColor: '#e5e7eb',
  },
  shimmer: {
    ...StyleSheet.absoluteFillObject,
    width: 220,
  },
  gradient: {
    flex: 1,
  },
});

关键在于,你并不是在动画渐变定义本身,而是在静态占位符上动画一个渐变层。这样更简单,逻辑更清晰,且在跨设备时通常更稳定。

以下是该效果在实际应用中的视觉演示:

动画组件

有几个实现细节需要注意:

  • 使用裁剪: 父元素需要 overflow: 'hidden',否则微光效果会溢出圆角边界。
  • 保持窄带: 较小的动画图层比动画整个表面更容易调优。
  • 让底色与屏幕一致: 骨架屏应与周围布局融为一体,而不是看起来像一个独立组件。

动画渐变在用户几乎察觉不到时效果最好。如果微光成了屏幕上最抢眼的东西,那就过头了。

性能、无障碍与平台差异

一旦渐变效果从 Demo 阶段进入生产环境,关注点就会发生变化。code 看起来依然简单,但渲染行为、可读性和平台一致性会变得比最初的视觉效果更重要。

如果你想更全面地提升应用响应速度,这篇 移动应用性能优化指南 也符合同一套思路:减少不必要的工作,在真机上测量,并优化用户最常看到的界面。

性能检查清单

原生渐变通常很高效,但使用不当仍会出问题。

  • 优先使用渐变而非大型装饰图片: 它们通常更易于打包,且更容易适配多种屏幕尺寸。
  • 避免堆叠多个全屏图层: 一个背景渐变即可。多个重叠的半透明渐变加上模糊和重型动画可能会带来高昂的性能开销。
  • Memo 化可复用组件: 如果渐变卡片用在列表里,保持 props 稳定,避免因父组件的无关状态而重渲染。

好的原则是让渐变服务于结构,而不是过度使用。用它们来定义表面,而不是密集信息流中的每一行。

无障碍检查清单

渐变会很快影响可读性,因为表面各处的对比度会变化。

  • 在最亮区域测试文本: 如果白色文本只在混合的暗部才可用,那它就不合格。
  • 必要时添加遮罩: 在背景和文字之间添加一层微妙的深色遮罩,通常比直接更换整个色板效果更好。
  • 仅在大型展示文案中使用渐变文字: 它非常适合标题。但对于小标签、辅助文本或任何关乎任务完成的关键信息,它并不是个好选择。

检查渐变中最差的效果点,而不是最漂亮的点。

平台差异检查清单

iOS 和 Android 渲染的渐变通常非常接近,但并不总是完全一致。

问题 通常有效的方案
渐变在不同平台显示不同 减少颜色数量,并提高色标间的对比度
圆角不会裁剪渐变效果 放置 overflow: 'hidden' 在容器上
渐变完全不显示 检查宽度、高度,或 flex: 1 首先

同时留意状态栏和安全区域的处理。如果内容和背景没有为刘海预留额外空间,在模拟器里看着平衡的渐变,到了带刘海的设备上可能会显得头重脚轻。

故障排查与最终最佳实践

这是我会记在项目笔记里的简版。

  • 根据工作流选择库: expo-linear-gradient 适用于 Expo 管理的应用, react-native-linear-gradient 适用于 bare React Native。
  • 让渐变有明确目的: 背景、CTA、覆盖层和 Hero 文案都是很典型的用法。
  • 有意识地控制方向: 按钮用水平渐变,装饰背景用对角线渐变,仅在大文本上使用遮罩。
  • 为内容设计,而非空状态: 使用真实文案、图标和状态栏样式进行测试。
  • 将裸机配置视为原生配置: Pods、链接和 Jest 模拟不是可选细节。

三种常见故障会反复出现。

渐变未显示

原因:组件没有可见尺寸。

修复:为其设置 flex: 1明确的高度,或具有尺寸的父容器。没有布局框的渐变无法正常渲染。

安装后 iOS build 报错

原因:未安装 pods 或原生依赖图不同步。

修复:运行 pod install 中的 ios,如有必要请清理 build 文件夹,然后重新构建应用。在 bare 项目中,仅安装 package 通常是不够的。

测试因原生模块错误而失败

原因:Jest 正在尝试加载实际的原生模块。

修复:mock react-native-linear-gradient 配合 react-native-linear-gradient/jest/linear-gradient-mock 在你的 Jest 配置文件中。

如果要从这份指南中只记住一点,请记住这个:渐变本身很简单。真正的工作量在于打造生产就绪的配置。一旦为你的应用架构选对了库,后续的一切都会变得可预测得多。


如果你的团队发布混合移动应用,并希望在不等待商店审核的情况下推送 JavaScript、CSS、文案、配置和资源更新, Capgo 值得一试。它为 CapacitorJS 和 Electron 团队提供受控的 Live Update、发布渠道、回滚保护和发布可见性,而不会让你的部署流程变成黑盒。

为 Capacitor 应用提供 Live Updates

当 Web 层出现线上 Bug 时,通过 Capgo 发布修复,而不用等 App Store 审核好几天。用户会在后台收到更新,原生变更则仍走正常审核流程。

博客最新动态

Capgo 为你提供打造真正专业的移动应用所需的最有价值的洞察。