PHP前端开发

我如何为我的 React Native 项目设置设计系统以加快开发速度

百变鹏仔 2个月前 (10-14) #JavaScript
文章标签 为我

曾经构建过您不想自己使用的应用程序吗?

当我还是一名初级应用程序开发人员时,我曾经构建混乱的用户界面。

有时,当看到这些 ui 时,我曾经想“世界上谁会想使用这个?它看起来很糟糕”。

其他时候,只是有些“不对劲的地方”我无法指出。

虽然我曾经从设计团队那里获得过令人惊叹的精美设计,但我的应用程序看起来连 20% 都没有那么好。

我意识到了这个问题,为了解决这个问题,我深入研究了这个问题,其中我发现了一个设计系统的概念,它改变了我构建应用程序的方式。

设计系统这个神奇的东西是什么?

理解设计系统是什么至关重要,这样才能理解我们为什么需要它。

设计系统基本上是您和您的团队设计决策的集中事实来源。它告诉您要使用什么颜色以及在哪里使用?该应用程序将有多少种类型的按钮?您列表中的卡片会有阴影吗?所有的答案都来自于设计系统。

以下是拥有设计系统的一些好处:

工具和库

虽然有大量的 react native ui 库,但我使用自定义方法,因为我在其中大多数库的性能和错误方面都有过可怕的经历。

我的方法唯一依赖的库是react-native-size-matters。

现在,在您尖叫“尺寸并不重要!”之前,让我向您保证,尺寸确实重要。尤其是在移动应用程序方面。

您不希望用户打开您的应用程序,看到一个覆盖所有内容的巨大徽标,然后在删除之前思考“丑陋的是什么......”,甚至不尝试就删除,因为您的徽标隐藏了按钮。

这就是react-native-size-matters 可以发挥作用的地方。它通过缩放组件以适应设备来使您的应用程序具有响应能力。因此,无论用户使用哪种设备,您的徽标都会准确地保留在您放置的位置。

设置主题

我定义的第一件事就是我的核心设计标记。这些是我的设计系统的构建模块。其中包括调色板、版式、间距和字体大小。

我通过使用以下代码创建 theme.ts 文件来实现此目的:

import {moderatescale} from 'react-native-size-matters';// after installing custom fonts:export const fontfamily = {  bold: 'poppins-bold',  semibold: 'poppins-semibold',  medium: 'poppins-medium',  regular: 'poppins-regular',  thin: 'poppins-thin',};const colors = {  primary100: '#2e2c5f',  primary80: '#524da0',  primary60: '#736ddf',  primary40: '#a09bff',  primary20: '#dcdaff',  secondary100: '#484a22',  secondary80: '#858945',  secondary60: '#d9df6d',  secondary40: '#f8fca1',  secondary20: '#fdffd4',  neutral100: '#131218',  neutral90: '#1d1c25',  neutral80: '#272631',  neutral70: '#343341',  neutral60: '#3e3d4d',  neutral50: '#53526a',  neutral40: '#757494',  neutral30: '#9c9ac1',  neutral20: '#cbc9ef',  neutral10: '#e8e7ff',  white: '#fff',  black: '#222',  error: '#e7002a',  success: '#3ec55f',  warning: '#fecb2f',  info: '#157efb',};const theme = {  colors,  fontsizes: {    xxl: moderatescale(32),    xl: moderatescale(28),    lg: moderatescale(24),    md: moderatescale(20),    body: moderatescale(17),    sm: moderatescale(14),    xs: moderatescale(12),    xxs: moderatescale(10),    xxxs: moderatescale(8),  },  spacing: {    none: 0,    xxs: moderatescale(4),    xs: moderatescale(8),    md: moderatescale(12),    lg: moderatescale(16),    xl: moderatescale(20),    xxl: moderatescale(24),    xxxl: moderatescale(28),  },};export default theme;

创建可重用组件

一旦我的设计令牌就位,我就会定义一些可重用的组件,例如 box、typography 和 input。这些组件遵循设计令牌,确保整个应用程序的一致性。

例如,这是我创建 box 组件的方法:

import {  view,  type viewprops,  type flexaligntype,  type viewstyle,} from 'react-native';import theme from '../styles/theme/theme';export interface ibox extends viewprops {  backgroundcolor?: keyof typeof theme.colors;  p?: keyof typeof theme.spacing;  pv?: keyof typeof theme.spacing;  ph?: keyof typeof theme.spacing;  pt?: keyof typeof theme.spacing;  pb?: keyof typeof theme.spacing;  pl?: keyof typeof theme.spacing;  pr?: keyof typeof theme.spacing;  m?: keyof typeof theme.spacing;  mv?: keyof typeof theme.spacing;  mh?: keyof typeof theme.spacing;  mt?: keyof typeof theme.spacing;  mb?: keyof typeof theme.spacing;  ml?: keyof typeof theme.spacing;  mr?: keyof typeof theme.spacing;  gap?: number;  flex?: number;  flexdirection?: 'row' | 'column' | 'row-reverse' | 'column-reverse';  alignitems?: flexaligntype;  justifycontent?:    | 'center'    | 'flex-start'    | 'flex-end'    | 'space-between'    | 'space-around'    | 'space-evenly';  rounded?: boolean;}export default function box({  backgroundcolor,  p,  pv,  ph,  pt,  pb,  pr,  pl,  m,  mv,  mh,  mt,  mb,  ml,  mr,  children,  style,  flex,  alignitems,  justifycontent,  flexdirection = 'column',  rounded = false,  gap = undefined,  ...rest}: ibox) {  const getmargin = () =&gt; {    const obj: any = {};    if (m) {      obj.margin = theme.spacing[m];      return obj;    }    if (mt) obj.margintop = mt ? theme.spacing[mt] : 0;    if (mb) obj.marginbottom = mb ? theme.spacing[mb] : 0;    if (ml) obj.marginleft = ml ? theme.spacing[ml] : 0;    if (mr) obj.marginright = mr ? theme.spacing[mr] : 0;    if (mv) obj.marginvertical = theme.spacing[mv];    if (mh) obj.marginhorizontal = theme.spacing[mh];    return obj;  };  const getpadding = () =&gt; {    const obj: any = {};    if (p) {      obj.padding = theme.spacing[p];      return obj;    }    if (pt) obj.paddingtop = pt ? theme.spacing[pt] : 0;    if (pb) obj.paddingbottom = pb ? theme.spacing[pb] : 0;    if (pl) obj.paddingleft = pl ? theme.spacing[pl] : 0;    if (pr) obj.paddingright = pr ? theme.spacing[pr] : 0;    if (pv) obj.paddingvertical = theme.spacing[pv];    if (ph) obj.paddinghorizontal = theme.spacing[ph];    return obj;  };  const boxstyles: viewstyle[] = [    {      backgroundcolor: backgroundcolor        ? theme.colors[backgroundcolor]        : undefined,      flex,      justifycontent,      alignitems,      flexdirection,      borderradius: rounded ? 10 : 0,      gap,    },    getmargin(),    getpadding(),    style,  ];  return (    <view style="{boxstyles}">      {children}    </view>  );}

我使用这个新创建的 box 组件来替代 view。它允许我通过 props 快速设计它的样式(如果您使用打字稿,则提供建议),如下所示:

这是我如何创建 typography 组件的示例,我使用它来代替 react native 的 text 组件:

import react from 'react';import {text, type textprops} from 'react-native';import theme, {fontfamily} from '../styles/theme/theme';export interface itypography extends textprops {  size?: keyof typeof theme.fontsizes;  color?: keyof typeof theme.colors;  textalign?: 'center' | 'auto' | 'left' | 'right' | 'justify';  variant?: keyof typeof fontfamily;}export default function typography({  size,  color,  textalign,  children,  style,  variant,  ...rest}: itypography) {  return (    <text style="{[" color: color theme.colors : theme.colors.white textalign fontsize: size theme.fontsizes theme.fontsizes.body fontfamily: variant fontfamily fontfamily.regular>      {children}    </text>  );}

以下是我向自定义排版组件添加样式的速度的预览:

自定义使用主题挂钩

我没有一次又一次地导入主题,而是通过创建一个自定义的 usetheme 挂钩来使代码更具可读性,我在应用程序中的任何位置调用该挂钩来添加符合我的主题的样式。

为了做到这一点,我利用 react 的 context api 在应用程序中传递我的主题。

我创建了一个 themeprovider.tsx 文件,并在内部定义了 themecontext 和 themeprovider 以将我的应用程序组件包装在其中。代码如下:

import react, {type propswithchildren, createcontext} from 'react';import theme from './theme';export const themecontext = createcontext(theme);export default function themeprovider({children}: propswithchildren) {  return (    <themecontext.provider value="{theme}">{children}</themecontext.provider>  );}

然后,在我的应用程序组件内:

export default function app() {  return (    <themeprovider><appnavigation></appnavigation></themeprovider>  );}

现在我的整个应用程序都可以访问 themecontext,我创建了 usetheme 挂钩:

import {usecontext} from 'react';import {themecontext} from '../styles/theme/themeprovider';export default function usetheme() {  const theme = usecontext(themecontext);  return theme;}

现在我可以通过调用 usetheme 挂钩在任何地方访问我的主题,如下所示:

const theme = usetheme();// example usage:theme.colors.primary100;theme.spacing.md;theme.fontsizes.lg;

深色模式

为了实现深色模式,在 theme.ts 文件中,我添加了另一个包含深色模式颜色的调色板。

export const darktheme = {  // define dark mode colors here keeping the keys same as the light mode only changing the values.}

然后,在 themeprovider 中,我只需检查用户设置并切换主题,如下所示:

<p>import {useColorScheme} from 'react-native';</p><p>export default function ThemeProvider({children}: PropsWithChildren) {<br>const isDarkMode = useColorScheme() === 'dark';<br>  return (<br><themecontext.provider value="{isDarkMode" darktheme : theme>{children}</themecontext.provider><br>  );<br>}</p>




结论

遵循这种清晰的结构化方法为我的应用带来了急需的清晰度、一致性和美观性,同时也将我的开发速度加快了至少 10 倍,因为我不再需要纠结于设计决策。

我鼓励您尝试这种方法,并在评论中让我知道你们的想法。也许稍微改进一下吧?