Skip to content

实现平滑圆角

Published: at 19:58 UTC+08:00Suggest Changes

小米的新 logo 从之前的一眼圆角变为看起来胖胖的圆角,下图中左边为新 logo,右边为旧的 logo。

logo

看起来挺玄乎的,当时刚发布的时候,听到最多的声音就是这据说 200w 的设计费真好赚。后来原研哉先生在专访中提到这是一个符合品牌特性的设计,并提出了 Alive 的理念。作为一个程序员,设计小白,没法理解大师的理念,只能用最直白的话:胖乎乎的还挺好看。

那上文提到的 Tab Bar 中,添加一个类似的新增账单的按钮吧,查阅资料之后发现,这个平滑圆角不是我能用钢笔工具慢慢调整出来的,背后包含的数学概念十分复杂。幸好 figma 提供了 Corner smoothing 工具,能帮助我实现一个类似的效果。工具使用本身并不复杂,就像下图中的效果,按照自己的想法调整一下就可以了,我就简单粗暴直接拉满。

smooth corner

代码实现

既然设计出来了,该如何实现这个胖乎乎的圆角呢?

点 9 图 (Nine-Slice Scaling)

最简单的方法当然是切图了,用背景图的形式,一行代码就搞定了。不过 background-image 有局限性,按钮的宽度与图片不一致时,背景图被拉伸了,就没有设计图上的效果了。那就得借助点 9 图来实现了,将 background-image 替换为 border-image。这在 Web 里非常容易实现,问题在于需要在 React Native 中实现,点 9 图似乎就不太容易实现了。一番查阅,大致有两种解决方案:

  1. 将图片分成独立的 9 部分,依次填充到按钮组件中
  2. figma 导出定制 SVG 包含 4 个角

对于方法 1,个人觉得比较丑陋,直接就 Pass 了。至于方法 2 这个用钢笔工具在 figma 中一个点一个点绘制圆角异曲同工了,也是超出能力范围了。

那怎么办?难道自己想出来的设计,就这样因为实现难度就直接胎死腹中了吗?

倒也不尽然

react-native-svg 绘制 svg

在我坚持不懈的否定下,强大的 ChatGPT 给出了如下答案

export default function SmoothCorner({ className = '', width = 34, height = 34, radius, smoothing = 0.6 }: SmoothCornerProps) {
  const smoothRadius = radius + radius * smoothing * 0.6 // 平滑角的实际半径

  const pathData = `
    M${smoothRadius},0
    H${width - smoothRadius}
    C${width}, 0 ${width}, ${0} ${width}, ${smoothRadius}
    V${height - smoothRadius}
    C${width}, ${height} ${width}, ${height} ${width - smoothRadius}, ${height}
    H${smoothRadius}
    C0,${height} 0, ${height} 0, ${height - smoothRadius}
    V${smoothRadius}
    C0,0 0,0 ${smoothRadius},0
    Z
  `

  return (
    <View className={className}>
      <Svg width={width} height={height}>
        <Path d={pathData} fill="currentColor" />
      </Svg>
    </View>
  )
}

在项目中试用一下

res

效果是实现了,不过 radius 参数和正常的效果不一致了,同样的数值但曲率变小了,多次尝试无果,只能慢慢调整,留个 Todo 吧。

参考


Previous Post
在 neovim 中使用 styled-components
Next Post
在 figma 中创建组件