曾经构建过您不想自己使用的应用程序吗?
当我还是初级应用程序开发人员时,我曾经构建混乱的用户界面。
有时,当看到这些 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 组件的方法:
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 = () => { 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 = () => { 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 ({children} ); }
我使用这个新创建的 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 ({children} ); }
以下是我向自定义版式组件添加样式的速度的预览:
我没有一次又一次地导入主题,而是通过创建一个自定义的 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 ({children} ); }
然后,在我的应用程序组件内:
export default function App() { return (); }
现在我的整个应用程序都可以访问 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 中,我只需检查用户设置并切换主题,如下所示:
import {useColorScheme} from 'react-native';
export default function ThemeProvider({children}: PropsWithChildren) {
const isDarkMode = useColorScheme() === 'dark';
return ({children}
);
}
遵循这种清晰的结构化方法为我的应用程序带来了急需的清晰度、一致性和美观性,同时也将我的开发速度加快了至少 10 倍,因为我不再需要纠结于设计决策。
我鼓励您尝试这种方法,并在评论中让我知道你们的想法。或许可以稍微改进一下?
免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。
Copyright© 2022 湘ICP备2022001581号-3