自分では使いたくないアプリを作成したことがありますか?
私がジュニア アプリ開発者だった頃、混沌としたユーザー インターフェイスを構築していました。
これらの UI を見て、「一体誰がこれを使いたいと思うでしょうか? 見た目はひどいです。」と時々思っていました。
また、指摘できない「何かがおかしい」こともありました。
以前はデザイン チームから驚くほど洗練されたデザインを提供してもらいましたが、アプリの見た目は 20% も良くありませんでした。
私はこの問題を認識しており、それを解決するためにウサギの穴のような研究を進め、アプリの構築方法を変えるデザイン システムの概念に出会いました。
なぜデザイン システムが必要なのかを理解するには、デザイン システムとは何なのかを理解することが重要です。
デザイン システムは基本的に、あなたとあなたのチームのデザイン決定のための一元的な情報源です。どの色をどこで使用するかがわかります。アプリには何種類のボタンがありますか?リスト内のカードには影がありますか?すべての答えはデザイン システムから得られます。
デザイン システムを導入するメリットの一部を次に示します:
一貫した UI: インターフェイスには、理由もなくあちこちに奇妙なギャップが存在することはありません。すべてのデバイスで見た目も感触も統一されます。
迅速な意思決定: デザイン システムでは、意思決定を難しくするのではなく、より簡単にするために、特定の制約セットが強制されます。選択肢が多ければ多いほど、より多くの分析麻痺に遭遇します。
スケーラブルなアプリ: アプリが成長するにつれて、デザイン システムは、最初から構築するのではなく、コンポーネントの再利用に役立ちます。
開発に集中: ボタンを緑にするか青にするかを強調する必要はもうありません。代わりに、重要なことに集中します。
React Native UI ライブラリはたくさんありますが、そのほとんどでパフォーマンスとバグに関してひどい経験をしたため、私はカスタム アプローチを使用しています。
私のアプローチで私が依存している唯一のライブラリは、react-native-size-matters です。
「サイズなんて関係ない!」と叫ぶ前に、重要だということを保証させてください。特にモバイル アプリに関してはそうです。
ユーザーがアプリを開いて、すべてを覆う巨大なロゴを見て、ロゴがボタンを隠していたために何も試さずに削除してしまう前に、「なんて醜いんだろう…」と思ってほしくないでしょう。
そこで、react-native-size-matters が役に立ちます。デバイスに合わせてコンポーネントをスケーリングすることで、アプリの応答性が向上します。したがって、ユーザーがどのデバイスを持っていても、ロゴは配置した場所に正確に残ります。
私が最初に定義するものの 1 つは、コア デザイン トークンです。これらは私のデザイン システムの構成要素です。これらには、カラー パレット、タイポグラフィ、間隔、フォント サイズが含まれます。
これを行うには、次のコードを使用して 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 を通じてすばやくスタイルを設定できます (また、typescript を使用している場合は提案を提供します)。
これは、React Native の Text コンポーネントの代わりに使用する Typography コンポーネントを作成する方法の例です:「react」から React をインポートします。 import {Text, type TextProps} from 'react-native'; テーマ、{FontFamily} を '../styles/theme/theme' からインポートします。 エクスポート インターフェイス ITypography は TextProps を拡張します { サイズ?: テーマのタイプのキー、フォントサイズ; color?: テーマのタイプのキー。色; textAlign?: '中央' | '自動' | '左' | '右' | 「正当化する」; バリアント?: FontFamily のタイプのキー; } デフォルト関数のエクスポート タイポグラフィ({ サイズ、 色、 textAlign、 子供たち、 スタイル、 変異体、 ...休む }: Iタイポグラフィ) { 戻る ( {子供たち} テキスト> ); }
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} ); }
カスタム使用テーマフック
これを行うために、React の Context API を利用してテーマをアプリに渡します。
ThemeProvider.tsx ファイルを作成し、その中にアプリ コンポーネントをラップする ThemeContext と ThemeProvider を定義します。コードは次のとおりです:
import React、{type PropsWithChildren、createContext} from 'react'; './theme' からテーマをインポートします。 エクスポート const ThemeContext = createContext(テーマ); デフォルト関数のエクスポート ThemeProvider({children}: PropsWithChildren) { 戻る (
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} ); }
デフォルト関数 App() をエクスポート { 戻る ( テーマプロバイダ> ); }
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 (アプリ全体が ThemeContext にアクセスできるようになったので、useTheme フックを作成します。{children} ); }
'react' から {useContext} をインポートします。 {ThemeContext} を '../styles/theme/ThemeProvider' からインポートします。 デフォルト関数 useTheme() をエクスポート { const テーマ = useContext(ThemeContext); テーマを返す。 }
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 (これで、次のように useTheme フックを呼び出すことで、どこからでもテーマにアクセスできるようになります。{children} ); }
const テーマ = useTheme(); // 使用例: テーマ.カラー.プライマリー100; テーマ.spacing.md; テーマ.fontSizes.lg;
const theme = useTheme(); // example usage: theme.colors.primary100; theme.spacing.md; theme.fontSizes.lg;ダークモード
エクスポート const darkTheme = { // ここでダーク モードの色を定義します。キーはライト モードと同じに保ち、値のみを変更します。 }
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 (次に、ThemeProvider でユーザー設定を確認し、次のようにテーマを切り替えます。{children} ); }
import {useColorScheme} from 'react-native';
export default function ThemeProvider({children}: PropsWithChildren) {
const isDarkMode = useColorScheme() === 'dark';
return ({children}
);
}
このアプローチを試してみて、コメントで意見を聞かせてください。少しは改善できるかも知れませんね?
免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。
Copyright© 2022 湘ICP备2022001581号-3