Skyroc Native UI

Rate

星级评分,支持半星、只读小数与自定义图标

评分(Rate)用一排星星表达分值。每颗星由三层构成:空心星打底、实心星按填充比例裁剪覆盖、命中区平铺在最上层。两种星形取自同一字体族,字形轮廓完全对齐,半星裁剪时不会错位。

import { Rate } from '@skyroc/native-ui';

基础用法

默认 5 颗星、初始 0 分。传 value + onChange 即为受控,非受控用 defaultValue

RateBasic.tsx
Loading…
import { Rate, Text } from '@skyroc/native-ui';
import { useState } from 'react';
import { View } from 'react-native';

const RateBasic = () => {
  const [value, setValue] = useState(3);

  return (
    <View className="gap-2 bg-background p-4">
      <Rate
        value={value}
        onChange={setValue}
      />
      <Text color="muted">当前分值:{value}</Text>
    </View>
  );
};

export { RateBasic };

何时使用

  • 让用户给内容打分,或展示已有的平均分(配 readonly)。
  • 只需要「赞 / 不赞」这类二元反馈时不要用评分。

半星

allowHalf 开启后,单颗星被切成左右两个命中区:点左半得 .5 分,点右半得整分。

RateHalf.tsx
Loading…
import { Rate, Text } from '@skyroc/native-ui';
import { useState } from 'react';
import { View } from 'react-native';

const RateHalf = () => {
  const [value, setValue] = useState(2.5);

  return (
    <View className="gap-2 bg-background p-4">
      <Rate
        allowHalf
        value={value}
        onChange={setValue}
      />
      <Text color="muted">当前分值:{value}</Text>
    </View>
  );
};

export { RateHalf };

可交互时分值一律量化到 0.5,保证「点出来的分值」与「看到的星」始终一致。

可清除

clearable 允许再次点中当前分值时归零。关闭时重复点击同一分值不会触发 onChange

RateClearable.tsx
Loading…
import { Rate, Text } from '@skyroc/native-ui';
import { useState } from 'react';
import { View } from 'react-native';

const RateClearable = () => {
  const [value, setValue] = useState(3);

  return (
    <View className="gap-2 bg-background p-4">
      <Rate
        clearable
        value={value}
        onChange={setValue}
      />
      <Text color="muted">当前分值:{value}</Text>
    </View>
  );
};

export { RateClearable };

数量与尺寸

属性含义默认值
count星星总数,非整数向下取整、负数按 05
size图标边长(px),同时是半星裁剪基准24
gutter星星间距(px)4
RateSize.tsx
Loading…
import { Rate } from '@skyroc/native-ui';
import { View } from 'react-native';

const RateSize = () => {
  return (
    <View className="gap-3 bg-background p-4">
      <Rate
        count={3}
        defaultValue={2}
        size={20}
      />
      <Rate defaultValue={3} />
      <Rate
        count={7}
        defaultValue={5}
        gutter={8}
        size={32}
      />
    </View>
  );
};

export { RateSize };

分值会被裁进 [0, count],越界入参不至于渲染出半截星或多余的空星。

主题色

color 决定点亮星的颜色,默认是 warning(金色星)。未点亮的星统一用 accent-muted-foreground

RateColor.tsx
Loading…
import { Rate, Text } from '@skyroc/native-ui';
import type { ThemeColor } from '@skyroc/native-ui';
import { View } from 'react-native';

const COLORS: ThemeColor[] = ['warning', 'primary', 'destructive', 'success', 'info', 'accent', 'carbon', 'secondary'];

const RateColor = () => {
  return (
    <View className="gap-3 bg-background p-4">
      {COLORS.map(color => (
        <View
          key={color}
          className="flex-row items-center gap-3"
        >
          <Rate
            color={color}
            defaultValue={4}
            size={20}
          />
          <Text color="muted">{color}</Text>
        </View>
      ))}
    </View>
  );
};

export { RateColor };

secondary 是浅底色,直接当星色几乎不可见,因此内部取前景色代替。

只读小数

readonly 时不响应点击;与 allowHalf 一起使用会放开填充精度,可以渲染 3.7 星这类统计值 —— 这是唯一允许任意小数的组合,其余情况都会量化。

RateReadonly.tsx
Loading…
import { Rate, Text } from '@skyroc/native-ui';
import { View } from 'react-native';

const READONLY_SCORES = [3.7, 4.2, 2.5];

const RateReadonly = () => {
  return (
    <View className="gap-3 bg-background p-4">
      {READONLY_SCORES.map(score => (
        <View
          key={score}
          className="flex-row items-center gap-3"
        >
          <Rate
            allowHalf
            readonly
            value={score}
          />
          <Text color="muted">{score} 分</Text>
        </View>
      ))}
    </View>
  );
};

export { RateReadonly };

禁用

disabled 阻止点击、把整体降到 50% 不透明度,并把点亮星的颜色改为灰色(与 readonly 的区别:只读保留原色)。

RateDisabled.tsx
Loading…
import { Rate } from '@skyroc/native-ui';
import { View } from 'react-native';

const RateDisabled = () => {
  return (
    <View className="gap-3 bg-background p-4">
      <Rate
        disabled
        defaultValue={3}
      />
      <Rate
        allowHalf
        disabled
        defaultValue={2.5}
      />
    </View>
  );
};

export { RateDisabled };

自定义图标

icon / voidIcon 接受一个节点,或 (index, active) => 节点 的函数(函数式写法可以按星索引给出不同图标,例如笑脸评分)。

RateIcon.tsx
Loading…
import Ionicons from '@expo/vector-icons/Ionicons';
import { Rate } from '@skyroc/native-ui';
import { View } from 'react-native';
import { withUniwind } from 'uniwind';

/** 与库内一致的取色方式:`accent-*` 工具类映射到矢量图标的 color 上 */
const HeartIcon = withUniwind(Ionicons);

const RateIcon = () => {
  return (
    <View className="gap-3 bg-background p-4">
      <Rate
        allowHalf
        color="destructive"
        defaultValue={3.5}
        icon={(_index, active) => (
          <HeartIcon
            colorClassName="accent-destructive"
            name={active ? 'heart' : 'heart-outline'}
            size={24}
          />
        )}
        voidIcon={
          <HeartIcon
            colorClassName="accent-muted-foreground"
            name="heart-outline"
            size={24}
          />
        }
      />
    </View>
  );
};

export { RateIcon };

自定义图标的实际宽度必须与 size 一致,否则半星遮罩按 size 裁剪会与图标错位。矢量图标不认 className,取色请用 withUniwindaccent-* 映射到 color,或直接在图标上写死颜色。

自定义样式

className 追加到根容器上,classNames 按 slot 细粒度覆盖:

slot作用位置
root根容器 View(横向排布,间距由 gutter 决定)
item单颗星的容器
icon点亮星的 colorClassName,只接受 accent-* 颜色类
voidIcon未点亮星的 colorClassName,只接受 accent-* 颜色类
RateStyles.tsx
Loading…
import { Rate } from '@skyroc/native-ui';
import { View } from 'react-native';

const RateStyles = () => {
  return (
    <View className="gap-3 bg-background p-4">
      <Rate
        className="self-start rounded-lg bg-secondary px-3 py-2"
        defaultValue={4}
      />
      <Rate
        classNames={{
          icon: 'accent-info',
          item: 'rounded-full bg-muted p-1'
        }}
        defaultValue={3}
      />
    </View>
  );
};

export { RateStyles };

icon / voidIcon 两个 slot 只在使用内置星星时生效;传了自定义图标后取色由你自己负责。

受控

分值完全由外部 state 决定,其它控件也可以改写它。

RateControlled.tsx
Loading…
import { Button, Rate } from '@skyroc/native-ui';
import { useState } from 'react';
import { View } from 'react-native';

const RateControlled = () => {
  const [value, setValue] = useState(4);

  return (
    <View className="gap-3 bg-background p-4">
      <Rate
        allowHalf
        value={value}
        onChange={setValue}
      />
      <View className="flex-row gap-2">
        <Button
          color="primary"
          variant="outline"
          onPress={() => setValue(Math.max(0, value - 0.5))}
        >
          -0.5
        </Button>
        <Button
          color="primary"
          variant="outline"
          onPress={() => setValue(Math.min(5, value + 0.5))}
        >
          +0.5
        </Button>
        <Button
          color="primary"
          variant="ghost"
          onPress={() => setValue(0)}
        >
          重置
        </Button>
      </View>
    </View>
  );
};

export { RateControlled };

热区

单颗星默认只有 24pt,半星模式下横向命中区更是只剩一半。横向补偿会与相邻星互抢点击,因此组件只补纵向:hitSlop={{ top: 10, bottom: 10 }},把可点高度抬到 44pt 附近。命中区不嵌套 Pressable,左右两半是平级的兄弟节点,避免内外层互抢触摸响应。

API

Rate

属性说明类型默认值
value当前分值(受控)number-
defaultValue非受控初始分值number0
onChange分值变化回调(value: number) => void-
count星星总数,非整数向下取整number5
size图标边长(px),同时是半星遮罩的裁剪基准number24
gutter星星间距(px)number4
color点亮星的主题色'primary' | 'destructive' | 'success' | 'warning' | 'info' | 'accent' | 'carbon' | 'secondary''warning'
allowHalf允许半星:左半区选半星、右半区选满星booleanfalse
clearable再次点中当前分值时清零booleanfalse
readonly只读,不响应点击;配合 allowHalf 可渲染任意小数booleanfalse
disabled禁用,不响应点击并整体置灰booleanfalse
icon点亮态图标,缺省为实心星RateIcon-
voidIcon未点亮态图标,缺省为空心星RateIcon-
className根容器类名,合并在 classNames.root 之后string-
classNames各 slot 的类名覆盖,见「自定义样式」一节SlotClassNames<RateSlots>-
ref根容器 View 的 ref,用于 measure / 滚动定位Ref<View>-

类型

import type { RateIcon, RateProps, RateSlots } from '@skyroc/native-ui';

RateIcon

星星图标:直接给节点,或按星索引与点亮态动态返回节点。自定义图标的宽度必须与 size 一致。

ReactNode | ((index: number, active: boolean) => ReactNode)

RateSlots

可通过 classNames 覆盖的 slot 名称。

'icon' | 'item' | 'root' | 'voidIcon'

SlotClassNames

classNames 的取值形态:把 slot 名映射到类名,每个 slot 都可选。本页用到的 slot 见 RateSlots。

Partial<Record<Slots, string>>

包内还导出了 rateVariants 与四个常量:DEFAULT_RATE_COUNT(5)、DEFAULT_RATE_SIZE(24)、DEFAULT_RATE_GUTTER(4)、RATE_HIT_SLOP(纵向 10)。