Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RN布局 & 适配 #283

Open
yaofly2012 opened this issue Jul 3, 2023 · 2 comments
Open

RN布局 & 适配 #283

yaofly2012 opened this issue Jul 3, 2023 · 2 comments

Comments

@yaofly2012
Copy link
Owner

yaofly2012 commented Jul 3, 2023

布局

React Native有两种布局方式:

  1. 控制子元素展示的布局:flex布局方式;
  2. 控制自身相对应父元素展示的布局:relative/absolute布局方式。

relative/absolute布局

相对于WEB CSS的position属性,React Native里position属性只有像个值:

  1. relative默认值
  2. absolute

并且含义跟WEB CSS的position属性一样的。由于其默认值是relative,这导致absolute元素永远相对于其父元素位置

Flex布局

子元素的布局有且只有一种布局方式,即flex布局。所以WEB CSS不一样的是父组件不用指定是否开启flex布局。

父组件相关属性

flexDirection

justifyContent

alignItems

alignContent

flexWrap

子组件相关属性

flex

根WEB CSS flex不一样的是React Nativeflex只能是单个数字值。
三种取值逻辑

  1. 正数,当取值是正数时flex相当于是flexGrow: XXX, flexShrink: 1, flexBasis: 0的简写形式;
    如果flex: 1 相当于flexGrow: 1, flexShrink: 1, flexBasis: 0
    最常用的场景就是flex: 1使得容器占满整个空间。

  2. When flex is 0, the component is sized according to width and height, and it is inflexible.

但是实际看此时flexBasis要设置为auto,更像是flexGrow: 0, flexShink: 1, flexBasis: 0。即flex: 0flex: 正数的效果是一样的。

  1. When flex is -1, the component is normally sized according to width and height. However, if there's not enough space, the component will shrink to its minWidth and minHeight

即先取值width/height如果没有足够空间再取值 minWidth/minHeight
只要是负数都一样,一般给-1

Issues/Concern:

  1. flex默认值是什么?【没有值,即此时看flexShrinkflexBasisflexGrow的值了】
  2. itemscontent区别:
  • items特指子组件
  • content表示父组件包含的内容,除了包含子组件外,还可能会有空白区域。

alignSelf

和CSS Flex语法差异

  1. flex属性取值差异;
  2. 默认值差异(RN针对移动端)
  • flexDirection默认值column;
  • alignContent默认值flex-start;
  • flexShrink默认值0(flexBasisflexGrow默认值跟CSS Flex一致).

Row Gap, Column Gap and Gap

gap, rowGap, columnGap用于设置子组件之间的缝隙。子组件和父组件边缘之间的缝隙并不受影响。

注意这是ReactNative 0.71才引入的新Style属性。之前的版本可以采用这种方式模拟gap

参考

  1. ReactNative Flexbox
  2. Yoga
@yaofly2012 yaofly2012 changed the title RN布局 RN布局 & 适配 Jul 3, 2023
@yaofly2012
Copy link
Owner Author

yaofly2012 commented Jul 3, 2023

适配

指定元素宽高

ReactNative有3种方式指定宽高尺寸:

  1. 绝对尺寸
  2. Flex方式
  3. 百分比方式

绝对尺寸

All dimensions in React Native are unitless, and represent density-independent pixels.

  1. 无单位
  2. 密度无关的像素,即逻辑像素(设备独立像素)

逻辑像素(dp)

简单回顾下逻辑像素概念:同样的尺寸在不同的设备(低分辨率和高分辨率)上看起来是“一样的”。

无单位

iOSAndroid平台里逻辑像素单位是不同的,ReactNative是作为夸平台技术直接采用无单位方式表示逻辑像素。

App适配

参考

  1. 像素密度
  2. Size Matters: How I used React Native to make my App look great on every device
  3. 聊聊React Native屏幕适配那些事儿
  4. Different UI/UX on Android and iOS when develop React Native app
  5. To Make Apps Accessible, Make Them Compatible with Different Devices

@yaofly2012
Copy link
Owner Author

yaofly2012 commented Jul 16, 2023

定义样式

  1. RN中利用JS声明样式;
  2. RN核心组件都有个style属性,用于定义组件样式;并且可以传个对象数组用于实现样式层叠。
  3. 使用StyleSheet模块将组件的样式统一放在一个地方,可简化组件render函数,提高组件的可读性。

StyleSheet API

StyleSheet API模块除了包含常用的Util函数(比如StyleSheet.create)外,还有一些常用属性:

  1. hairlineWidth
  2. absoluteFill
  3. absoluteFillObject

StyleSheet.create函数

大部分情况我们都是在组件外部使用StyleSheet.create函数创建styles变量,并在组件内部引用样式。但是⚠️为啥使用StyleSheet.create函数呢,不使用StyleSheet.create函数行不行呢?

不使用StyleSheet.create函数创建样式行不行 ?

,直接使用纯JS对象也可以声明样式。

const styles = {
  bigblue: {
    color: 'blue',
    fontWeight: 'bold',
    fontSize: 30,
  },
  red: {
    color: 'red',
  },
};

但是不要这样做,RN既然提供了StyleSheet.create函数,肯定有充分的理由,后面我们深入了解下StyleSheet.create函数。

为啥使用StyleSheet.create函数

StyleSheet.create函数的返回值就是传入的实参:

const stylesObj = {
  bigblue: {
    color: 'blue',
    fontWeight: 'bold',
    fontSize: 30,
  },
  red: {
    color: 'red',
  },
};

const styles = StyleSheet.create(stylesObj);

console.log(stylesObj === styles); // true

那为啥还要使用StyleSheet.create函数呢?从v0.72的代码注释里可以看出主要基于两个目的:

  1. 代码质量
  • By moving styles away from the render function, you're making the code easier to understand
  • Naming the styles is a good way to add meaning to the low level components in the render function
  1. 性能
  • Making a stylesheet from a style object makes it possible to refer to it by ID instead of creating a new style object every time.
  • It also allows to send the style only once through the bridge. All subsequent uses are going to refer an id (not implemented yet).

但是从目前实现看只有代码质量这个动机了:

  1. StyleSheet.create会校验实参是否是合法的Style属性(但是从v0.66开始不会再校验了,而是利用TS声明方式提示);
  2. 借助TS类型声明,在coding时编译器会有智能提示。

StyleSheet.create函数源码解析

StyleSheet.create函数实现一直在变更,并且到目前(2023-07-16)还未完全实现(见上面注释)。我们看下v0.64~0.65和0.66~0.72两个阶段的版本:

create<+S: ____Styles_Internal>(
    obj: S,
  ): $ObjMap<S, (Object) => StyleSheetInternalStyleIdentifier> {
    const result = {};
    for (const key in obj) {
      StyleSheetValidation.validateStyle(key, obj);
      result[key] = obj[key] && ReactNativePropRegistry.register(obj[key]);
    }
    return result;
  }
create<+S: ____Styles_Internal>(obj: S): $ReadOnly<S> {
    // TODO: This should return S as the return type. But first,
    // we need to codemod all the callsites that are typing this
    // return value as a number (even though it was opaque).
    if (__DEV__) {
      for (const key in obj) {
        StyleSheetValidation.validateStyle(key, obj);
        if (obj[key]) {
          Object.freeze(obj[key]);
        }
      }
    }
    return obj;
  }
create<+S: ____Styles_Internal>(obj: S): $ReadOnly<S> {
    // TODO: This should return S as the return type. But first,
    // we need to codemod all the callsites that are typing this
    // return value as a number (even though it was opaque).
    if (__DEV__) {
      for (const key in obj) {
        if (obj[key]) {
          Object.freeze(obj[key]);
        }
      }
    }
    return obj;
  }

可以看出随着版本的升级StyleSheet.create函数功能反而更简化了,从v0.65开始(目前v0.72)只是原封不动的返回实参。

总结

综上所述:

  1. 从render函数中移除具体的样式内容,可以使代码更清晰易懂;
  2. 样式命名也可以对render函数中的组件增加语义化的描述
// 不推荐 ❌
<View style={{ backgroundColor: '#fff‘ }} />

// 推荐 ✅
const styles = StyleSheet.create({
  wrapper: {
    backgroundColor: '#fff‘ 
  }
});

// 说明View作为wrapper
<View style={styles.wrapper} />
  1. style对象作为只读对象对待
    开发阶段StyleSheet.create函数会Object.freezestyle对象的属性,不要直接修改StyleSheet.create返回值的属性。

参考

  1. StyleSheet API
  2. What is the point of StyleSheet.create
  3. RN的stylesheet简介

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant