React native 分辨率适配(px,dp)

作者: terrantian | 来源:发表于2016-12-13 15:48 被阅读8269次

React Native中使用的尺寸单位是dp(一种基于屏幕密度的抽象单位。在每英寸160点的显示器上,1dp = 1px),而设计师使用的是px, 这两种尺寸如何换算呢?官方提供了PixelRatio:

import {PixelRatio} from 'react-native';
const dp2px = dp=>PixelRatio.getPixelSizeForLayoutSize(dp);
const px2dp = px=>PixelRatio.roundToNearestPixel(px);

设计师给你一个尺寸,比如100px*200px的View,按照下面的方式可实现设计还原:

<View style={{width:px2dp(100),height:px2dp(200),backgroundColor:"red"}}/>

这个时候,你或许会说,这也太麻烦了,每个有尺寸的地方我都得转么,能不能我直接用px写,当然可以,不过需要整体加个缩放系数:

import {PixelRatio,Dimensions}} from 'react-native';
const dp2px = dp=>PixelRatio.getPixelSizeForLayoutSize(dp);
const px2dp = px=>PixelRatio.roundToNearestPixel(px);

let pxRatio = PixelRatio.get();
let {win_width,win_height} = Dimensions.get("window");

let scale = 1/pxRatio;
let width = dp2px(win_width);
let height = dp2px(win_height);
const com = props=>(
                <View sytle={styles.container}>
                    <View style={{width:100,height:200,backgroundColor:"red"}}/>
                </View>)

const styles={
  container: {
        width:width,
        height:height,
        transform:[{translateX:-width*.5},
                    {translateY:-height*.5},
                    {scale:scale},
                    {translateX:width*.5},
                    {translateY:height*.5}]
    },
}

这样处理后,在根节点内,你再也不用考虑dp的问题了,直接使用px即可。

不过此时还有另外一个问题,设计尺寸是死的,屏幕大小是活的,得考虑分辨率适配啊,那在不同的分辨率下如何正确的实现设计师的设计呢?

我们将使用一种游戏经常会用到得方案,fixedWidth/fixedHeight.

fixedWidth

fixedWidth 模式是保持原始宽高比缩放应用程序内容,缩放后应用程序内容在水平和垂直方向都填满播放器窗口,但只保持应用程序内容的原始宽度不变,高度可能会改变,简言之宽度固定,高度自适应

fixedHeight

fixedHeight 模式是保持原始宽高比缩放应用程序内容,缩放后应用程序内容在水平和垂直方向都填满播放器窗口,但只保持应用程序内容的原始高度不变,宽度可能会改变,简言之高度固定,宽度自适应

具体如何应用呢,别急,一步步来。
先来看看如何得到屏幕的像素宽高:

import {Dimensions,PixelRatio} from 'react-native';

let {width,height} = Dimensions.get("window");
let w =dp2px(width);
let h = dp2px(height);

假定我们的设计尺寸是

let designSize = {width:750,height:1336};

按照fixedWidth、fixedHeight的定义,我们计算下新的宽高:

//fixedWidth
let scale = designSize.width/w;
let winSize = {width:designSize.width,height:h*scale};

//fixedHeight
let scale = designSize.height/h;
let winSize = {width:designSize.width*scale,height:designSize.height};

这个winsize就是最终实际用来布局的屏幕尺寸,此时我们又会多了一个分辨率适配的缩放系数,还记得我们前一个我们添加的为了使用px的缩放系数么,我们在这里做一个整合:

import {PixelRatio,Dimensions}} from 'react-native';
const dp2px = dp=>PixelRatio.getPixelSizeForLayoutSize(dp);
const px2dp = px=>PixelRatio.roundToNearestPixel(px);

let designSize = {width:750,height:1336};

let pxRatio = PixelRatio.get();
let {win_width,win_height} = Dimensions.get("window");

let width = dp2px(win_width);
let height = dp2px(win_height);

let design_scale = designSize.width/width;
height = height*design_scale

let scale = 1/pxRatio/design_scale;

const com = props=>(
                <View sytle={styles.container}>
                    <View style={{width:100,height:200,backgroundColor:"red"}}/>
                </View>)

const styles={
  container: {
        width:width,
        height:height,
        transform:[{translateX:-width*.5},
                    {translateY:-height*.5},
                    {scale:scale},
                    {translateX:width*.5},
                    {translateY:height*.5}]
    },
}

在后续的开发中将不必再关注适配的问题,只需要按照设计师给的尺寸实现布局即可。

最后再附上一个工具类 Resolution.js:

import React, {Component, PropTypes} from 'react';
import {
    Dimensions,
    PixelRatio,
    Platform,
    StatusBar,
    View
} from 'react-native';

let props = {};
export default class Resolution {
    static get(useFixWidth = true){
        return useFixWidth?{...props.fw}:{...props.fh}
    }

    static setDesignSize(dwidth=750,dheight=1336,dim="window"){
        let designSize = {width:dwidth,height:dheight};

        let navHeight = Platform.OS === 'android' ? StatusBar.currentHeight : 64;
        let pxRatio = PixelRatio.get(dim);
        let {width,height} = Dimensions.get(dim);
        if(dim != "screen")height-=navHeight;
        let w = PixelRatio.getPixelSizeForLayoutSize(width);
        let h = PixelRatio.getPixelSizeForLayoutSize(height);

        let fw_design_scale = designSize.width/w;
        fw_width = designSize.width;
        fw_height = h*fw_design_scale;
        fw_scale = 1/pxRatio/fw_design_scale;

        let fh_design_scale = designSize.height/h;
        fh_width = w*fh_design_scale;
        fh_height = designSize.height;
        fh_scale = 1/pxRatio/fh_design_scale;

        props.fw = {width:fw_width,height:fw_height,scale:fw_scale,navHeight};
        props.fh = {width:fh_width,height:fh_height,scale:fh_scale,navHeight};
    }

    static FixWidthView = (p) => {
        let {width,height,scale,navHeight} = props.fw;
        return (
            <View {...p} style={{
                                            marginTop:navHeight,
                                            width:width,
                                            height:height,
                                            backgroundColor: 'transparent',
                                            transform:[{translateX:-width*.5},
                                                        {translateY:-height*.5},
                                                        {scale:scale},
                                                        {translateX:width*.5},
                                                        {translateY:height*.5}]
                                        }}>
            </View>
        );
    };

    static FixHeightView = (p) => {
        let {width,height,scale,navHeight} = props.fh;
        return (
            <View {...p} style={{
                                            marginTop:navHeight,
                                            width:width,
                                            height:height,
                                            backgroundColor: 'transparent',
                                            transform:[{translateX:-width*.5},
                                                        {translateY:-height*.5},
                                                        {scale:scale},
                                                        {translateX:width*.5},
                                                        {translateY:height*.5}]
                                        }}>
                {p.children}
            </View>
        );
    };
};
//init
Resolution.setDesignSize();




How to use:

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  Image,
  View
} from 'react-native';

import Resolution from "./Resolution"

export default class tets extends Component {
  render() { 
    return (
      <Resolution.FixWidthView style={styles.container}>
        <Image source={require("./assets/bg_day.jpg")} style={{position:"absolute"}}/>
        <Text style={styles.welcome}>
          Welcome to React Native!
        </Text>
        <Text style={styles.instructions}>
          To get started, edit index.ios.js
        </Text>
        <Text style={styles.instructions}>
          Press Cmd+R to reload,{'\n'}
          Cmd+D or shake for dev menu
        </Text>
      </Resolution.FixWidthView>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 0,
    justifyContent: 'center',
    alignItems: 'center',
    // backgroundColor: '#ff0000',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
    backgroundColor:"transparent"
  },
  instructions: {
    backgroundColor:"transparent",
    textAlign: 'center',
    color: 0xffff,
    marginBottom: 5,
  },
});

AppRegistry.registerComponent('rn_resolution', () => tets);

bg_day.jpg的尺寸是750*1500,上面的程序在所有的分辨率下图片都能正确显示。

这里有个demo:Github,如果解决你的问题了,记得给我加星哦~~

另外:不同分辨率下背景图片尺寸如何选择,移步另一篇博文:《分辨率适配的取值范围》

相关文章

  • React native 分辨率适配(px,dp)

    React Native中使用的尺寸单位是dp(一种基于屏幕密度的抽象单位。在每英寸160点的显示器上,1dp =...

  • react-native 布局篇

    react-native 布局篇之单位换算(px转dp) react-native 布局篇之flexbox rea...

  • React Native 适配工具类

    在React Native开发中,尺寸的默认单位为dp(android设备下160dpi,dp与px为1:1),加...

  • Android适配问题总结

    Android 适配问题:点击这里 (很详细) 总结: px:手机的分辨率,即像素的个数 dp/dip:密度无关像...

  • 分辨率适配的取值范围

    前面有篇文章《React native 分辨率适配》中提到了FixWidth,FixHeight两种适配策略,如果...

  • android UI适配简单记录一

    有关UI适配的屏幕相关概念很多,如分辨率、density、dpi、dip、dp、sp和px。孤立地去看这些概念有点...

  • React Native 布局单位

    React Native 布局方案 默认单位是 DP(android中 160 像素密度前提下: 1px = 1d...

  • Android 屏幕适配

    传统dp适配方式的缺点 android中的dp在渲染前会将dp转为px,计算公式: px = density * ...

  • Android UI适配方案

    大纲 使用dp而不是px 尽量使用自动适配布局,而不要指定分辨率 使用宽高限定符values-1080x1920,...

  • 2018-08-29

    今日头条适配方案 一、屏幕适配原理 1、Android中的dp、px、dpi、desity关系 px = dens...

网友评论

  • 4f9f8b21fc30:你的那个js在所有分辨率下都会适配么???如果两个手机分辨率的宽高比例不一样,背景图会不会短一块或者长一块
  • f3f54b12e867:@terrantian
    在整个rn应用中采用了自适应方案后,有些元素不需要自适应,如何避免这个问题呢?请教下
  • 0135cdbfcc16:楼主,请问能修改全局的字体大小吗?
  • 608924568ff8:只有一套2倍的图片资源怎么破?
    terrantian:@我家果果 处理图片或设计尺寸*2
  • 骑着蜗牛去遛狗:你好,使用工具类之后,字体的缩放是没有问题的,我是把Resolution.FixWidthView中嵌入了scrollView标签,工具类中设置了marginTop,我注释掉了,但是在下拉的时候会有一部分内容遮挡住,还需要麻烦帮忙看下是什么原因,图上传不了,可以给我一个QQ号码我给传过去吗
    terrantian:if(dim != "screen")height-=navHeight;
    这个地方也去掉试试
  • 炜_f0e4:scale 缩小一倍后文字变的好丑 有什么解决办法吗
  • 5330adc10b21:在项目中具体试了这个方法,用上面写的适配上还是有问题的。另外不明白方法中为什么高度height = height*design_scale,而宽度却不用。整个方法做适配的时候,宽度也乘了设计比例,发现最后还要放大两倍才能实现,但是内容却在垂直方向上被截取掉了一部分。还请赐教
    terrantian:使用这个方案后,单位就统一成px了
    60e70e0e3026:@terrantian 哥,android怎么适配?pt是ios,android是pd吧。
    terrantian:缩放是等比的,使用fixWidth的话,width * scale = designWidth,相应的height也需要乘以这个scale。

    至于你说的另一个问题,贴下你的code,我瞅瞅。
  • d085fdc7c938:同问这个工具类怎么使用呢?新手不太明白啊。另外在rn中给样式设置transform:[{translateX:-width*.5},
    {translateY:-height*.5},
    {scale:scale},
    {translateX:width*.5},
    {translateY:height*.5}]会红屏的
    terrantian:红屏有截图么,我看看具体是什么错
    terrantian:这个transform的目的是修改容器的注册中心,以中心点进行缩放。
  • 羽纱:谢谢分享,不过博主应该还要考虑android设备的status的高度,在ios中布局是与statusbar重叠的,android上布局会顶在statusbar下面:
    let statusBarHeight = Platform.OS === 'android' ? StatusBar.currentHeight : 0;
    let h = PixelRatio.getPixelSizeForLayoutSize(height - statusBarHeight)

    我在工具类中加了这两句。:blush:
  • 3262d7c36ca3:方便说一下工具类怎么使用或者有demo么

本文标题:React native 分辨率适配(px,dp)

本文链接:https://www.haomeiwen.com/subject/emxbmttx.html