
运行demo、调试
来自:前端调试。
npm run build客户端demo运行
iOS(/examples/ios-demo/)
直接可以根据文档运行Xcode
Android(/examples/android-demo/)
Android Studio安装SDK
选择安装制定版本的SDK Tools:
参考:Hippy/issues/39。
配置环境变量
 export ANDROID_HOME=/Users/「用户名」/Library/Android/sdk
 export PATH=${PATH}:${ANDROID_HOME}/tools
 export PATH=${PATH}:${ANDROID_HOME}/platform-tools
Task 'wrapper' not found in project、Task 'prepareKotlinBuildScriptModel' not found in project:
 // `build.gradle`文件最后添加:
 task wrapper(type: Wrapper) {
   gradleVersion = '8.0.0'
 }
 task prepareKotlinBuildScriptModel {
 }
运行Hippy demo项目(/examples/hippy-react-demo/、/examples/hippy-vue-demo/)
npm run hippy:dev、npm run hippy:debug
Android调试(按步骤):
adb reverse tcp:38989 tcp:38989chrome://inspect/#devices打开Hippy debug tools for V8
根据https://hippyjs.org/#/guide/debug?id=android的要求,关闭
Discover USB devices可以减少断连手机。
iOS调试(按步骤):
打开Safari,勾选:开发 -> 模拟器 xxx -> ️自动显示JSContext的网页检查器
调试H5页面时要关闭「️自动显示JSContext的网页检查器」,无效且影响页面切换性能。
App点击:本地调试 -> 点击调试
若Safari没有调试信息,则重启App
前端使用:
构建工具
webpack
网络请求
fetchWebSocketcookie(NetworkModule)定时器
setTimeout/clearTimeout、setInterval/clearInterval
日志
console.log/warn/error
console日志会输出到iOS和Android系统日志中(Hippy 2.10.0之前)。
注意:若客户端系统打印多次日志,则可能是前端调用多次,也可能是客户端打印bug导致打印多次。
自定义字体
fontFamily
二分法定位问题
因为依赖客户端渲染的本质,所以最终需要在iOS和Android都真机测试才可以。
iOS和Android的渲染结果可能不同,样式(截断、遮挡)、事件冒泡情况、等,容易产生区别。

组件
<Image>、<ListView>、<Modal>、<Navigator>、<RefreshWrapper>、<ScrollView>、<TextInput>、<Text>、<View>、<ViewPager>
组件功能需要完全按照文档描述来使用,不像前端标签那么灵活。如:
<View>和<ScrollView>不能混用,<ScrollView>文档只有contentContainerStyle而没有,style<View>内部不能直接放字符串而需要放组件。
前端组件最终是传递给客户端,由客户端组件来实现呈现
因此用客户端工具查看客户端组件时,可以根据组件名字前缀有Hippy的,判断其来自于前端。
客户端都是单屏视口(可以理解为外层包裹着一个宽高等于视口的flex父级容器),借助某些组件的内部滚动来实现多屏效果。
所有滚动都是:组件内部滚动。
<ScrollView>
支持:横向 或 竖向滚动(horizontal只能选择其一,不能同时横向、竖向滚动)。没有复用节点优化。
<ScrollView>内可嵌套所有组件(包括:<ScrollView>、<ListView>、<ViewPager>)。<ListView>
支持:竖向滚动。复用节点优化:自动删除不在可视区的节点,对进入可视区的节点进行按类型复用。
<RefreshWrapper>
包裹一个<ListView>后支持:下滑刷新。
<ListView>支持下拉、上拉刷新功能(renderPullHeader/onHeaderPulling/onHeaderReleased、renderPullFooter/onFooterPulling/onFooterReleased),可以不需要<RefreshWrapper>配合下拉刷新。<ViewPager>
支持:横向切换(类似Swiper)。
overflow只有hidden/visible2个属性值)。Tips(bug?)
<Image>
需要显式设置width和height,才能显示。
若是资源图且不知道高宽比例,可以用Image.getSize获取图片的宽高。
部分机型onError无法正常触发。
可能是客户端对不同类型的图片地址采取的加载错误处理方案不同,如:http、base64、普通字符串、等。
padding无法像CSS那样扩展图片的外部,因此若想要图片的点击范围大于图片内容,则需要在外部嵌套父级,父级设置padding并把点击事件放在父级。
<Text>
Android:
ellipsizeMode仅支持tail。低版本Android机可能不支持opacity效果,可能导致整个文本渲染消失
用字体颜色color: rgba(x,y,z, 透明度)来代替。
渲染变化的节点,如果没有加style,会被渲染为空。
强制加上style设置一些样式内容。
某些渲染情况下,不设置color时会变成透明文字
需要显式设置color才能展示文字。
<Text>有不同截断效果(ellipsizeMode),其他组件需要自己实现(计算字符数,结尾自己添加...或图片覆盖)。<Text>内的文字内容,无法渲染新值,只能展示首次渲染值。文本若不设置lineHeight(或height),可能导致渲染出的行高影响整体渲染,甚至影响祖父元素的高度或间距,无法达到确定的”稳定状态”。
若出现文字上下被截断的情况,则也试着设置大一些的lineHeight去解决。
<View>用flex-start/flex-end处理。fontStyle只有'normal/italic'值,若要制作下划线或删除线等,则需要用额外节点处理(包裹一层
 <View>
   <Text numberOfLines={1}>文案</Text>
   <View style=/>
 </View>
numberOfLines设置会影响最大高度,文字排版几行才有几行的高度。lineHeight最好大于fontSize某个值(如:某些默认字体下lineHeight大于等于1.2倍fontSize),否则可能会导致行高不够裁切文字。
与CSS类似:
- 字体内容(content-area)高度 与
font-size和font-family相关,与无关。line-height
字体内容(content area) + 行间距(vertical spacing) = 行高(line-height)。其中行间距分上下部分,间距对半分。
若行高(line-height) 小于 字体内容(content area),则行间距是负数,此时文字被裁切,上下行间部分重合。
<ViewPager>
height和flexBasis类似。
height,否则会导致内容高度为0。height(会导致切换到一半卡住),可以设置延迟时间等待切换结束之后再改变height(>300ms)。onPageSelected
iOS初始化时不会 触发;Android初始化时会触发onPageSelectedonPageSelected。
大部分(但不是所有)组件都有onLayout
当元素挂载或者布局改变时被调用。返回节点实时的:宽高(width、height)、距离父级顶部(0,0)距离(x、y)。
onLayout,则可以滚动到指定组件位置和判断组件是否”曝光”。onLayout是异步的,并且可能触发时间比较慢,在组件渲染完毕之后上百毫秒(250ms?)才触发,也不一定按照排列顺序触发(如前面的组件比较复杂等原因)。<View>并利用它的onLayout。<ListView>
改变渲染内容后(除了onEndReached触发之外)有时无法再触发onEndReached
(除了onEndReached触发之外)改变渲染内容时,改变<ListView>的key属性。
getRowType返回类型根据版本会有不同,旧版SDK(@hippy/react)需要字符串类型,新版SDK需要数字类型。
会在客户端层面报错(非前端层面,因此safari不报错),类似:
Error setting property 'type' of ListViewItem with tag #153: JSON value '0' of type NSNumber cannot be converted to NSString。
renderRow不支持横向排列、不足换行的方案(flexDirection: 'row'flexWrap: wrap或wrap-reverserenderRowrenderRow。<ScrollView>、<ListView>的滚动事件,需要onMomentumScrollEnd(非用户触发的滚动结束)和onScrollEndDrag(用户触发的滚动结束)配合使用<ScrollView>
配合使用contentContainerStyle(在内层的内容容器生效)和style(在外层容器生效)
<ScrollView>会渲染里外2个容器:
flex相关样式可能要同时设置到style和contentContainerStyle上(尤其是在降级为H5页面时)
style是<ScrollView>自身外层的的样式,设置flex: 1占满其父级剩余空间。
Android的borderRadius有问题。
contentContainerStyle是<ScrollView>内部包裹一层的样式,设置flexGrow: 1可以使子项占满父级剩余空间并且正常滚动。
e.g.
实现:内容不够时子项拉伸,内容足够时滚动 ```jsx <View style={styles.container}> <View style= /> <ScrollView style={styles.scrollviewStyle} contentContainerStyle={styles.scrollviewContentContainerStyle}> <View style={styles.viewStyle}>1个或多个,满足效果</View> <View style= /> </View> const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#a2a2a2", alignItems: "center", }, scrollviewStyle: { flex: 1, backgroundColor: "yellow", width: 300, }, scrollviewContentContainerStyle: { alignItems: "center", background: "white", padding: 10, // 关键设置 flexGrow: 1, // 注意,不可以用:`flex: 1`。省去则仅正常滚动,不会内容不够时还占满父级 }, viewStyle: { height: 200, backgroundColor: "pink", width: 200, marginVertical: 50, // 关键设置 flex: 1, // 或:`flexGrow: 1` }, }); ```
horizontal={true}横向滚动的左右间距问题,用 stylecontentContainerStyle<ScrollView>转换为<View>时注意是否有contentContainerStyle,若有,则可能需要嵌套<View>
e.g.
```jsx <ScrollView style={样式1} contentContainerStyle={样式2}>内容</ScrollView> 转换 => <View style={样式1}> <View style={样式2}> 内容``` </details> 
获取:滚动距离、内容总高度(视口高度+最大滚动距离 === 子级的总高度)、布局总高度(视口高度)
<ListView>可能类似。
 // 下面3个值能够实时获取
 contentOffsetY = 0;          // 滚动距离
 contentSizeY = 0;            // 内容总高度(视口高度+最大滚动距离 === 子级的总高度)
 layoutMeasurementHeight = 0; // 布局总高度(视口高度)
 render () {
   return (
     <ScrollView
       onLayout={(data) => {
         this.layoutMeasurementHeight = data.layout.height
       }}
       onMomentumScrollEnd={(data) => {  // 滚动停止(非用户拖拽导致)
         this.contentOffsetY = data.contentOffset.y;
         this.contentSizeY = data.contentSize.height
         this.layoutMeasurementHeight = data.layoutMeasurement.height
       }}
       onScrollEndDrag={(data) => {  // 滚动停止(用户拖拽导致)
         this.contentOffsetY = data.contentOffset.y;
         this.contentSizeY = data.contentSize.height
         this.layoutMeasurementHeight = data.layoutMeasurement.height
       }}
     >
       <View
         onLayout={(data)=>{
           this.contentSizeY = data.layout.height
         }}
       >
         真正布局内容。。。
       </View>
     </ScrollView>
   )
 }
<ScrollView>默认设置flex: 1效果,可在外部加一个<View>节点限制来规避(或设置flex: 0,但未成功)实现随着内容高度变化而自适应滚动或不滚动
 // 内容不够则收缩至实际高度;内容超过外层flex: 1拥有的最高高度则内容滚动
 <View style=>
   <ScrollView>
     ...内容
   </ScrollView>
 </View>
 // 内容不够则收缩至实际高度,内容超过外层最大高度则内容滚动
 <View style=>
   <ScrollView>
     ...内容
   </ScrollView>
 </View>
key的diff有bug
key的组件可能挂载2次(触发2次componentDidMount)key="index"规避padding或margin翻倍问题render返回多个节点会有渲染问题(React已支持)
<TextInput>
keyboardType="phone-pad"。multiline={false},否则多行。onEndEditing事件、onBlur事件、点击其他区域。onEndEditing事件、onBlur事件、onChangeText事件Android:
editable为false。调用节点.blur()(作用:触发节点onBlur事件)无效。
需要设置editable先为false再为ture才会触发节点onBlur事件(可能是需要触发页面渲染)。
onBlur事件触发还会隐藏软键盘。
iOS:
软键盘被唤起时,页面不会向上顶起,因此可能会挡住要输入的区域。
利用onKeyboardWillShow事件获得软键盘弹起时高度,把输入框区域垫高;输入完毕之后再恢复高度。
书写方式:
 <TextInput
   multiline={false}
   style=
   onChangeText={text => {
     // text -> data
   }}
   value={data}
 />
「变量名」 && 「组件或嵌套组件」,当「变量名」为false时,会用一个新的空<Text>替换「组件或嵌套组件」
false && 「组件或嵌套组件」因为一直都是false,所以不会有额外的空<Text>出现,直接忽略本句渲染。
用三元运算符替换:「变量名」 ? 「组件或嵌套组件」 : null(「变量名」的true/false切换时,仅新增/删除「组件或嵌套组件」,不会有额外的空<Text>出现替换)
new Hippy的entryPage)每个组件(包括<Text>)都是块状的,不能像H5那样内联展示。但可以用如下方式制作类似inline-block的文字,支持不同颜色、换行、事件。
import { Text } from "react-native";
<Text>      {/* 必须是 Text 包裹 Text */}
  <Text>    {/* 可以加样式、点击事件等所有属性 */}
    inline-block文字1
  </Text>
  <Text
    style=
    onClick={() => {
      console.log('点到我了')
    }}
  >
    inline-block文字2
  </Text>
  <Text>    {/* 可以加样式、点击事件等所有属性 */}
    inline-block文字3
  </Text>
</Text>
列表项目曝光
<ListView>,则用onAppear或onWillAppear判断某子节点是否曝光。<ScrollView>(<ListView>也同理),则用onLayout按顺序记录每个子节点的宽高,然后 父级onScroll的滚动距离 与 父级宽高、各子节点宽高 的关系。制作swiper
最基本的滑块
<ScrollView>配置pagingEnabled={true}<ViewPager>有异化效果的滑块
(必须宽度满屏)<ScrollView>
监控滚动事件,滚动结束后补偿滚动从而使子项居中,还可以利用滚动距离设置每一项的异化。
e.g.
```tsx import { View, ScrollView, ScrollEvent } from "react-native"; import { useRef } from "react"; export default () => { const ScrollViewRef = useRef<ScrollView | null>(null); return ( <View style=> <ScrollView horizontal={true} scrollEventThrottle={16} showScrollIndicator={!!__DEV__} contentContainerStyle={样式} ref={ScrollViewRef} onScroll={(obj: ScrollEvent) => { // 异化子项:为每个子项计算与视图正中的距离 }} onScrollBeginDrag={() => { // 停止自动轮播 }} onScrollEndDrag={(obj: ScrollEvent) => { // 补偿滚动到合适位置(ScrollViewRef.current.scrollTo) // 开始自动轮播 }} onMomentumScrollEnd={(obj: ScrollEvent) => { // (可选)补偿滚动到合适位置(ScrollViewRef.current.scrollTo) }} > {子项} </ScrollView> </View> ); } ```
模块
动画组件
提供给前端React/Vue渲染使用的按时间变化的style中某样式属性值。
Animation、AnimationSet
Animation针对一个属性的一个配置后的变化;AnimationSet针对一个属性的多个配置后的变化。若需要多个属性同时变化,则多个属性每个设置一个Animation或AnimationSet,同时触发。
e.g.
```tsx import { View, Text, AnimationOption, Animation } from "react-native"; import { useEffect, useState } from "react"; const DEFAULT = 1; const NEXT_VALUE = 0; // 从0->1动画 const animationConfig1: AnimationOption = { mode: "timing", timingFunction: "ease-in-out", startValue: NEXT_VALUE, toValue: DEFAULT, duration: 3000 }; // 从1->0动画 const animationConfig2: AnimationOption = { mode: "timing", timingFunction: "ease-in-out", startValue: DEFAULT, toValue: NEXT_VALUE, duration: 3000 }; export default function Demo2() { const [opacity, setOpacity] = useState<Animation | typeof DEFAULT>(DEFAULT); useEffect(() => { if (opacity !== DEFAULT) { opacity.start(); opacity.onAnimationEnd(() => { opacity.destroy(); }); } }, [opacity]); return ( <> <View style= /> <Text onClick={() => { setOpacity(new Animation(animationConfig1)); }} > opacity: 0=》1 </Text> <Text onClick={() => { setOpacity(new Animation(animationConfig2)); }} > opacity: 1 =》 0 </Text> </> ); } ```
Tips(bug?)
动画未完成不能中途updateAnimation(或者参数startValue必须是动画当前值)。
直接操作最终的客户端UI组件样式(跳过前端执行后再传递给客户端渲染),性能更佳。
e.g.
```tsx import { View, UIManagerModule } from "react-native"; import { useRef } from "react"; export default () => { const ViewRef = useRef<View | null>(null); return ( <View style={原样式} ref={ViewRef} onClick={() => { ViewRef.current && UIManagerModule.getElementFromFiberRef?.(ViewRef.current)?.setNativeProps?.({ style: {新样式(会合并到原样式中)}, }); }} /> ) } ```
AsyncStorage
异步、持久化的键-值存储系统
hippy
返回Promise实例。
h5
返回与window.localStorage一致。
BackAndroid
监听Android实体键的back,在退出前做操作或拦截
BackAndroid.addListener(方法名)BackAndroid.removeListener(方法名)Clipboard
读取或写入剪贴板
ConsoleModule
提供了将前端日志输出到iOS终端日志和Android logcat的能力。(Hippy 2.10.0之后,console不再能输出至终端日志)
Dimensions.get('window或screen')
获取设备的Hippy Root View或者屏幕尺寸的宽高
按照设计稿等比例宽高:
自由放大缩小
width: 设计稿此物体宽 / 设计稿总宽 * Dimensions.get("window").widthheight: (设计稿此物体高 / 设计稿此物体宽) * 前面的width间距固定、单个物体占满:
width: Dimensions.get("window").width - 固定宽度height: (设计稿此物体高 / 设计稿此物体宽) * 前面的width间距固定、多个物品平均占满:
width: (Dimensions.get("window").width - 固定宽度) / 几个物品height: (设计稿此物体高 / 设计稿此物体宽) * 前面的width若是
position: "absolute"要占满全屏且父级已占满全屏(高满屏或宽满屏),则可以用top: 0; bottom: 0;代替Dimensions.get("window").height,left: 0; right: 0;代替Dimensions.get("window").width。
Tips(bug?)
(Android全面屏手机)Dimensions.get('window').height或横屏的Dimensions.get('window').width有可能会自动减少StatusBar的高度。
(React Native问题)市场上大多数的Android全面屏手机,一般都是以 刘海屏、水滴屏、挖孔屏 等异形屏的形式存在。屏幕在显示UI界面时,顶上的挖孔部分一般都是作为 状态栏 的形式存在。这其中的一些机型,在计算
Dimensions.get('window').height时不将状态栏计算进去,但在实际渲染界面时又把状态栏作为可视区域。
(网上较多是根据Dimensions.get('window').height/Dimensions.get('window').width比值判断出需要处理的Android全面屏,再一刀切加上StatusBar的高度。我感觉不妥,)需要更多地利用flex布局而不是确定尺寸的布局,或在最外层满屏的<View>上用onLayout异步获得渲染出的满屏高宽。
ImageLoaderModule
对远程图片进行相应操作:获取图片大小、预加载图片。
NetInfo
获取网络状态
NetworkModule
网络相关的模块,目前主要是操作Cookie。
PixelRatio
获取设备的像素密度(pixel density)
Platform
判断平台
Stylesheet(.hairlineWidth、.create())
CSS样式表
UIManagerModule
提供了操作UI相关的能力。
引入base64
默认情况下,webpack配置了针对小于某KB的图标进行转base64,所以一般情况不需要显式使用这个。
!!url-loader?modules!路径,如:import defaultSource from '!!url-loader?modules!./defaultSource.jpg';
自定义组件、自定义模块
自定义组件
在需要渲染的地方通过nativeName属性指定到终端组件名称。
e.g.
<div nativeName="LinearGradientView">
自定义模块
callNative或callNativeWithPromise与Native通信方式(桥协议、JSI):import { callNative, callNativeWithPromise } from "@hippy/react"
通用的,H5与Native通信方式:
桥协议或自定义URL Scheme+ WebView提供给Native调用的全局回调函数(或匿名函数)。
手势系统(点击事件、触屏事件)
所有组件(或自定义组件)均支持监听手势系统(点击事件、触屏事件)。
点击事件
onClick:点击onPressIn:开始触屏onPressOut:结束触屏onLongClick:长按回调参数:
  {
    name: 「事件名」,
    id: 「控件的id」,
    target: 「控件的id」
  }
触屏事件
onTouchDown:开始触屏onTouchMove:移动手指(持续触发回调)onTouchEnd:结束触屏onTouchCancel:被中断触屏
若触发onTouchCancel则不触发onTouchEnd。
回调参数:
  {
    name: 「事件名」,
    id: 「控件的id」,
    target: 「控件的id」,
    page_x: 「触屏点相对于根元素的横坐标」,
    page_y: 「触屏点相对于根元素的轴坐标」
  }
事件
事件冒泡
点击事件、触屏事件均支持事件冒泡,由最上层组件往根元素冒泡触发事件回调。
false,则冒泡。不返回值、或返回任何除了 false注意使用UI库时,某些组件是否进行事件冒泡拦截。e.g. 大部分
<Button>的实现,点击事件不会继续向上冒泡。
事件捕获
在目标元素事件名添加Capture后缀,e.g. onClickCapture、onTouchDownCapture。
事件拦截
父级组件拦截或中断子级组件的事件触发。所有触发在子级组件的事件都仅触发在父级组件。
onInterceptTouchEvent:
true:
onInterceptTouchEvent为true之前,子级组件已经在处理触屏事件,则子级组件将收到一次onTouchCancel回调(如果子控件有注册该函数)。false(默认):不拦截
onInterceptPullUpEvent(貌似还未实现?)
事件穿透
客户端双端原生特性如此。
pointer-events: none;)。对于结构复杂的情况,可能违背这个逻辑,导致有覆盖的节点就不穿透。
终端事件
 import { HippyEventEmitter } from '@hippy/react';
 const hippyEventEmitter = new HippyEventEmitter();
 # 发送rotate事件并监听回调
 this.call = hippyEventEmitter.addListener('rotate', evt => console.log(evt.result));
 # 事件卸载
 this.call.remove();
样式
- Hippy的还原设计稿方案,与客户端的方案基本一致:适配布局(与设计师协作思路)。
- React Native样式的子级。
- 注意属性值要求是
Number还是String,要严格遵守,不能互换。- 部分属性仅支持部分组件。如:
backgroundImage仅支持<View>、不支持。<Text>
长度单位
无单位、数值型(Number)。含义是dp或pt。不支持:百分比、任何单位(。(部分机型)支持小数点、不取整。px/em/rem/vw/vh)
1px或小数点长度:
(部分)客户端支持小数点数值(并非所有样式都支持,比如:有些机型不支持width,但支持border。以不同样式在具体机型的具体效果为准)。
  import { View, PixelRatio, StyleSheet } from "react-native";
  <View style=/>
  <View style=/>
  <View style=/>
  {/* StyleSheet.hairlineWidth 注意要存在,返回0.33... */}
属性名的方向:
left === start、right === end。但貌似未实现或start。end
盒模型
类型CSS的
box-sizing: border-box;(布局所占宽度 = width = content + padding左右 + border左右。高度同理)。
widthheightmax/min+Width/Height
Tips(bug?)
minWidth/minHeight可能是box-sizing: content-box 或 border-box效果。maxWidth/maxHeight可能完全不生效。minWidth的父节点内部若有子级,则父级布局所占最小宽度 = minWidth = content(不包括:border
宽度(Number)
borderWidth
仅能设置为相同数值。
borderTopWidthborderRightWidthborderBottomWidthborderLeftWidth颜色
属性值为颜色字符串。
borderColorborderTopColorborderRightColorborderBottomColorborderLeftColorborderStyle
'solid'(默认)'dotted''dashed'padding(Number)
padding
仅能设置为相同数值。优先级最低。
paddingVertical
仅能设置为相同数值。
paddingHorizontal
仅能设置为相同数值。
paddingToppaddingRightpaddingBottompaddingLeftmargin(Number)
margin
仅能设置为相同数值。
marginVertical
仅能设置为相同数值。
marginHorizontal
仅能设置为相同数值。
marginTopmarginRightmarginBottommarginLeft布局(flex)
仅支持flex(,所以省略 display: flexflex)。
与CSS的flex略有不同。
Flex容器
flexDirection:决定主轴的方向。
'row':水平方向,起点在左端(CSS的flex-direction默认:'row')。'column'(默认):垂直方向,起点在上沿。flexWrap:一条主轴排不下的情况,如何换行。
项的排布顺序。
与CSS的表现不同,也没有
配合。还是只能配合alignContentjustifyContent、alignItems使用。
justifyContent:子项在主轴上的对齐方式(与轴的方向有关)。
与CSS的
justify-Content表现一致。
alignItems:子项在侧轴上的对齐方式(与轴的方向有关)。
默认:'stretch'(CSS的align-content默认:'normal')。
与CSS的
align-Items表现一致。 无效属性:
:多根主轴(一条主轴排不下,有换行)的对齐方式(不换行则该属性不起作用)。alignContent默认:
'flex-start'(CSS的align-content默认:'stretch')。
Flex子项
都在主轴方向上。
flex:占用容器中剩余空间的大小。
0(默认):元素没有弹性,不管父级容器空间,仅使用自身原本宽度/高度占据空间。
也可能因为内容太多溢出父级,建议用
-1代替。
「正整数」:元素有弹性,每个元素占用的剩余空间 = 自己的 flex 数值 / 所有同一级子容器的 flex 数字之和。
此时
flex: 「正整数」等价于flexGrow: 「正整数」, flexShrink: 1, flexBasis: 0。
-1:若空间不足则缩小到minWidth/minHeight。若空间没有不足,则使用自身原本宽度/高度占据空间。
适合可变元素后面紧跟着内容的情况。
CSS的
flex-grow: 0和flex-shrink: 1的默认表现。 子项铺满父级的主轴剩余空间:flex: 1;子项扩充满父级的侧轴:alignSelf: 'stretch'。
多个项:若都设置
flex: 1(无论各项内容不一),则所有项占用空间大小均一致。若都设置flexGrow: 1,则各项先按照自己内容大小占据不同大小空间,再对剩余空间进行拉伸(各项所占空间不一致)。
flexGrow:伸缩项目扩展的能力。
默认:0。
与CSS的
flex-grow表现一致。
flexShrink:伸缩项目收缩的能力。
默认:0(CSS的flex-shrink默认:1)。
与CSS的
flex-shrink表现一致。
父级flexShrink: 1 + 子级flex: 1,可以实现:内容不够则收缩至实际高度/宽度;内容最大高度/宽度不超过外层flex: 1拥有的最大高度/宽度
  <View>
    <View style=>
      <Text style=>  // 也可以是<ScrollView>等 会变化的内容
        自适应的内容
      </Text>
    </View>
    <View>固定内容</View>
  </View>
flexBasis:伸缩基准值。
与CSS的
flex-basis表现一致。
alignSelf:单个子项覆盖父元素的alignItems。
与CSS的
align-self表现一致。 无效属性:order
颜色
包括所有颜色,如:border、字体、background、阴影。
rgb
e.g. '#f0f'、'#ff00ff'、'rgb(255, 0, 255)'
rgba
e.g. '#f0ff'、'#ff00ff40'、'rgba(255, 0, 255, 0.5)'
hsl
e.g. 'hsl(0, 33%, 69%)'
hsla
e.g. 'hsla(0, 33%, 69%, 0.5)'
'transparent'
没有
'none',只能用'transparent'覆盖回无背景色。
颜色名字
字体
fontSizelineHeightcolorfontWeighttransform: [{ 属性1: 值1 }, {属性2: 值2}]
属性值是
object[]。
backfaceVisibility
元素背面朝向观察者时是否可见。
'visible'(默认)'hidden'定位
position
'relative'(默认)'absolute'
起点:从父级border内开始计算(父级的margin、padding不影响子级absolute位置相对父级位置);从本身的margin开始计算。
与CSS表现一致。
不支持 fixedfixed效果,则:
有兄弟节点的情况
 <View>      // 此处父级必须是全屏才可以:占满上下左右全屏。因为"absolute"仅能针对父级
   <ScrollView></ScrollView> // 兄弟节点
   <View style=>类似fixed的效果</View>
   <View style=>类似fixed的效果(不够优雅)</View>
   <ScrollView></ScrollView> // 兄弟节点
 </View>
没有兄弟节点的情况
 <View style=>  // 此处父级必须是全屏才可以:占满上下左右全屏。因为"absolute"仅能针对父级、才能让子级默认居中
   <View>水平、垂直居中</View>
   <View style=>类似fixed的效果</View>
   <View style=>类似fixed的效果(不够优雅)</View>
 </View>
若要制作全局定位(如:全屏居中、贴底部、贴顶部、等)的组件,因为'absolute'仅针对父级 且 Android子级不能超出父级(强制'hidden')的限制,则其父级必须是占满上下左右全屏(视情况而定),但不要求是最外层元素。
toprightbottomleftzIndex
position: relative/absolute的节点,均按代码书写顺序进行堆叠,zIndex等效改变任何一个节点。
0(默认)
(与CSS的层叠上下文略有不同)可以理解为:Hippy中任何一个组件,都形成层叠上下文且默认层叠顺序为
0。因此层叠顺序仅在兄弟节点就确定了,不是兄弟节点无法改变堆叠顺序。
「整数」
overflow
overflow只有2个属性值,没有CSS的,除了拥有滚动效果的组件(scroll<ScrollView>、<ListView>、<RefreshWrapper>、<ViewPager>)之外,其他组件都不支持组件内滚动。
子元素超过父容器的宽度/高度后的显示情况。
'visible'(默认)'hidden'
Android机型,大部分子级元素一定会被父级元素截断(就像:父级元素固定overflow: 'hidden'不可改变),但是部分客户端组件还是需要父级设置overflow: 'hidden'才截断。因此若需要做超过父级的节点,则必须往上不断提升该节点。但对于border等,父级还是需要overflow: hidden才能不被子级盖住。
背景
不能直接
,无效果。background
backgroundImage
- URL不能缩写。不能用
https://placeholder.com/?- 仅针对
<View>等。
e.g. backgroundImage: import变量/require变量/"http资源"
backgroundPositionXbackgroundPositionYbackgroundColor实现背景图某些效果
本地资源制作背景图方式:
 <View>
   <Image source= style= />
   内部节点
 </View>
或
 <Image source= style=>
   内部节点
 </Image>
或
父级节点的style添加:backgroundImage
实现图片repeat效果
<Image>的resizeMode(cover、contain、stretch、repeat、center)类似CSS的object-fit+background-repeat属性,但没有CSS那么多效果组合。
 <Image
   style=
   source=
   resizeMode="repeat"
 />
外边框圆角(Number)
borderRadius
仅能设置为相同数值。
Tips(bug?)
<Text>borderTopLeftRadius、borderTopRightRadius、borderBottomRightRadius、borderBottomLeftRadius
Tips(bug?)
overflow: 'hidden'有问题。<LinearGradientView>(nativeName=”LinearGradientView”)对这种单独设置的属性支持不好(无效)。iOS若最终设置的4个角值不同,则导致backgroundColor渲染问题。应避免使用这些单独设置的属性:
用一个子节点设置borderRadius模拟
 <View style=>...</View>
 <View style=>
   <View
     style=
   />
   <View style=>...</View>
 </View>
e.g. 好像又能正常设置
```javascript tag: { position:'absolute', top: -pt(1.5), left: -pt(1.5), height: pt(16), paddingHorizontal: pt(6), backgroundColor:'#EA392C', borderTopLeftRadius: pt(8), borderBottomRightRadius: pt(8), } ```
opacity阴影
boxShadow+后缀
直接
boxShadow: '属性'无效。
 boxShadowOpacity: 0.6,
 boxShadowRadius: 5,
 boxShadowOffsetX: 10,
 boxShadowOffsetY: 10,
 // spread attr is only supported on iOS
 // spread 属性仅适用于iOS
 boxShadowSpread: 1,
 boxShadowColor: '#4c9afa',
textShadow+后缀
直接
textShadow: '属性'无效。
 textShadowColor
 textShadowOffsetX   // 大于0才有效
 textShadowOffsetY   // 大于0才有效
 textShadowRadius
e.g.
```javascript textShadowColor: "#fff", textShadowOffsetX: 0.1, textShadowOffsetY: 0.1, textShadowRadius: 5 ```
样式写法
内联样式
e.g. <View style=/>。
外部样式
无障碍
组件属性accessible、accessibilityLabel。
Tips(bug?)
Android:
组件均需要accessible、accessibilityLabel + 事件(如:onClick={()=>false})才能支持无障碍选中。
注意加了事件之后,不要影响到原来的事件逻辑(如:阻止了原有冒泡逻辑)。
accessible={true},还会再选中子级的accessible。iOS:
<Text>不需要加accessible、accessibilityLabel(可以设置accessible={false}关闭);其他组件需要加accessible、accessibilityLabel。accessible={true},就不会再选中子级的accessible(但是可以阅读出所有子级的accessibilityLabel内容)。