Skip to content
作者:  WHY
字数统计: 
阅读时长:  分钟
阅读量: 

RN 屏幕适配

  • android1dp=1px (160dpi)1dp=2px (320dpi)
  • dpr=1 的屏幕使用一倍图, dpr=2 的屏幕使用二倍图, dpr=3 的屏幕使用三倍图

Reading Materials

Basic

分辨率

分辨率即横纵两个方向上的像素点数量, 常见的分辨率:

  • 1920x10801080p (1k 屏)
  • 2560x1440 即显示器 2k
  • 3840x2160 即显示器 4k 屏 (Quad Full HD)
  • 4096x2160 即显示器 4k 屏 (UHD)
tsx
import {useWindowDimensions} from 'react-native';
const {width, height} = useWindowDimensions();
console.log('[INFO] wxh: ', `${width}x${height}`);

DPI

DPIDots Per Inch, 每英寸点数, 计算公式为对角像素数/对角英寸

tsx
console.log('[INFO] DPI: ', `${PixelRatio.get() * 160} dpi`);
  • 160dpi <-> mdpi
  • 240dpi <-> hdpi
  • 320dpi <-> xhdpi
  • 480dpi <-> xxhdpi

PPI

PPIPixels Per Inch, 每英寸像素数, 也称像素密度

图片适配

js
const image = getImage({
  width: PixelRatio.getPixelSizeForLayoutSize(200), // 等同于 200 * PixelRatio.get()
  height: PixelRatio.getPixelSizeForLayoutSize(100) // 等同于 100 * PixelRatio.get()
});

<Image source={image} />;

字体适配

屏幕适配

总的来说, RN 项目有以下几种屏幕适配方案:

  • Dimensions:

    tsx
    import {Dimensions} from 'react-native';
    
    // 可换成 useWindowDimensions
    const windowDimensions = Dimensions.get('window');
    
    /**
     * 设计稿宽度, 单位: px
     */
    export const DESIGN_WIDTH = 1025;
    /**
     * 设计稿高度, 单位: px
     */
    export const DESIGN_HEIGHT = 629;
    // const TARGET_WIDTH = 1920;
    // const TARGET_HEIGHT = 1024;
    
    export const WIDTH_SCALE = windowDimensions.width / DESIGN_WIDTH;
    export const HEIGHT_SCALE = windowDimensions.height / DESIGN_HEIGHT;
    
    // 这里无需使用 use 前缀, 使用 u 即可 (非 hook)
    export const uResponsiveWidth = (width: number, transform = true) => (transform ? width * WIDTH_SCALE : width);
    export const uResponsiveHeight = (height: number, transform = true) => (transform ? height * HEIGHT_SCALE : height);
    export const uResponsiveFontSize = (fontSize: number, transform = true) =>
      transform ? fontSize * Math.min(WIDTH_SCALE, HEIGHT_SCALE) : fontSize;

    然后在 StyleSheet.create 中调用相应方法即可实现屏幕适配

  • 基于 StyleSheet 封装 CustomStyleSheet

    js
    import {StyleSheet} from 'react-native';
    import dp2px from './dp2px';
    
    let CustomStyleSheet = {
      create(style) {
        let s = {...style};
        // 目前仅对以下的属性进行处理
        let list = [
          'width',
          'height',
          'marginTop',
          'marginBottom',
          'marginLeft',
          'marginRight',
          'paddingTop',
          'paddingRight',
          'paddingBottom',
          'paddingLeft',
          'top',
          'right',
          'bottom',
          'left',
          'fontSize',
          'lineHeight'
        ];
        for (let outKey in s) {
          for (let innerKey in s[outKey]) {
            if (list.includes(innerKey) && typeof s[outKey][innerKey] == 'number') {
              s[outKey][innerKey] = dp2px(s[outKey][innerKey]);
            }
          }
        }
        return StyleSheet.create(s);
      }
    };
    export default CustomStyleSheet;
  • babel 插件自动转换, 如以下插件

  • 一些其他插件:

flutter_screenutil

可参考 flutter_screenutil 实现 RN 版本的屏幕适配

Contributors

The avatar of contributor named as why why

Changelog

Released under the MIT License.