1.0.0-rc.1 • Published 7 months ago

@hadss/react_native_adaptive_layout v1.0.0-rc.1

Weekly downloads
-
License
Apache-2.0
Repository
-
Last release
7 months ago

@hadss/react_native_adaptive_layout

介绍

这是一个旨在解决 React Native多设备适配问题的三方库,专为不同设备类型(包括折叠屏、平板、手机等)提供了便捷的支持。该库包含的接口和开箱即用的组件,使开发者能够轻松应对各种设备的布局适配需求。

工程目录

.
├─harmony
│  ├─adaptive_layout.har                                 // Turbo Modules接口har包
│  └─adaptive_layout
│     └─src
│        └─main
│           └─ets
│              ├─LayoutModule.ets               // Turbo Modules接口ArkTS实现
│              ├─LayoutModulePackage.ets        // LayoutModulesFactory
│              ├─LayoutModuleSpec.ts            // Turbo Modules接口
│              └─core
│                 └─FoldConfig.ts   
├─src
│  ├─index.ts                                 // RN模块导出
│  ├─component
│  │  └─FoldSplitContainer.tsx                // 折叠屏高阶组件
│  ├─config
│  │  └─breakpoints.ts                        // 断点配置类
│  ├─hooks
│  │  ├─BreakpointManager.ts                  // 纵向断点管理类
│  │  └─useBreakpointValue.ts                 // 横向断点hook
│  └─turbo
│     └─NativeLayoutModule.ts                   // RN Turbo Modules接口

安装与使用

进入到工程目录并输入以下命令:

npm

npm install @hadss/react_native_adaptive_layout

yarn

yarn add @hadss/react_native_adaptive_layout

下面的代码展示了这个库的基本使用场景:

横向断点&&FoldSplitContainer使用示例

const TestSample = () => {
  const [foldCreaseRegion, setFoldCreaseRegion] = useState<number[]>([]);
  const [foldStatus, setFoldStatus] = useState('');
  const [breakpoints, setBreakpointsState] = useState({});
  const [isDeviceFoldable, setIsDeviceFoldable] = useState(false);

  useEffect(() => {
    const checkFoldable = () => {
      // 判断当前设备是否可折叠
      const foldable = Fold.isFoldable();
      setIsDeviceFoldable(foldable);
      if (foldable) {
        // 获取折痕区域
        setFoldCreaseRegion(Fold.getFoldCreaseRegion());
        
        // 获取当前折叠屏状态
        setFoldStatus(Fold.getFoldStatus());
      }
    };

    checkFoldable();

    // 监听折叠屏状态变化
    Fold.addFoldListener((foldStatus) => {
      console.log('折叠屏状态发生变化', foldStatus);
    });

    return () => {
      // 销毁监听折叠屏状态变化
      Fold.removeFoldListener();
    };
  }, []);

  const handleGetBreakpoints = () => {
    setBreakpointsState(getBreakpoints());
  };

  const handleSetBreakpoints = () => {
    // 设置断点区间
    setBreakpoints({
      base: 320,
      md: 768,
      lg: 1024,
    });
  };

  const handleGetFoldStatus = () => {
    if (isDeviceFoldable) {
      // 获取当前折叠屏状态
      setFoldStatus(Fold.getFoldStatus());
    }
  };

  const color = useBreakpointValue({
    // 根据不同断点设置不同的颜色
    base: 'red',
    xs: 'blue',
    sm: 'green',
    md: 'yellow',
    lg: 'purple',
    xl: 'orange',
  });
  
  // FoldSplitContainer 主要区域
  const primaryRender = () => (
    <View style={{ flex: 1 }}>
      <Text style={{ color }}>Responsive Color Text</Text>
      <Text>Is Device Foldable: {isDeviceFoldable ? 'Yes' : 'No'}</Text>

      {isDeviceFoldable && (
        <>
          <Text>Fold Crease Region: {JSON.stringify(foldCreaseRegion)}</Text>
          <Button title="Get Fold Status" onPress={handleGetFoldStatus} />
          {foldStatus && <Text>Fold Status: {foldStatus}</Text>}
        </>
      )}

      <Button title="Get Breakpoints" onPress={handleGetBreakpoints} />
      {Object.keys(breakpoints).length > 0 && (
        <Text>Breakpoints: {JSON.stringify(breakpoints)}</Text>
      )}

      <Button title="Set Custom Breakpoints" onPress={handleSetBreakpoints} />
    </View>
  );

  // FoldSplitContainer 次要区域
  const secondRender = () => (
    <View style={{ flex: 1, backgroundColor: 'blue' }}>
      <Text style={{ fontSize: 20 }}>secondRender</Text>
    </View>
  );

  // FoldSplitContainer 扩展区域
  const extraRender = () => (
    <View style={{ flex: 1, backgroundColor: 'red' }}>
      <Text style={{ fontSize: 20 }}>extraRender</Text>
    </View>
  );

  // 折叠屏展开态配置
  const expandedLayoutOptions: ExpandedRegionLayoutOptions = {
    isExtraRegionPerpendicular: false,
    extraRegionPosition: ExtraRegionPosition.BOTTOM,
  };

  // 折叠屏悬停态配置
  const hoverModeRegionLayoutOptions: HoverModeRegionLayoutOptions = {
    showExtraRegion: true,
  };

  return (
    <View style={styles.container}>
      // 折叠屏高阶组件
      <FoldSplitContainer
        primary={primaryRender()}
        secondary={secondRender()}
        extra={extraRender()}
        expandedLayoutOptions={expandedLayoutOptions}
        hoverModeLayoutOptions={hoverModeRegionLayoutOptions}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
});

export default TestSample;

纵向断点BreakpointManager使用示例

import React, {useState, useEffect} from 'react';
import {
  View,
  Text,
  useWindowDimensions,
  StyleSheet,
  FlatList,
} from 'react-native';
//ios及android平台需切换为对应android_ios目录下的类。
import {BreakpointManager} from '@hadss/react_native_adaptive_layout/src/hooks/BreakpointManager';

const BreakpointDemo = () => {
  const {width: cwidth, height: cheight} = useWindowDimensions();
  const [itemNum, setItemNum] = useState<number>(12);
  const [itemColor, setItemColor] = useState<string>('red');

  // 获取 BreakpointManager 的实例
  const breakpointManager = BreakpointManager.getInstance();

  // 获取当前宽度和高度的断点值
  const currentWidthBp = breakpointManager.getCurrentWidthBreakpoint();
  const currentHeightBp = breakpointManager.getCurrentHeightBreakpoint();

  // 根据高度断点值计算每行的元素数量,并根据宽度断点值设置颜色
  useEffect(() => {
    // 订阅断点变化
    const unsubscribe = breakpointManager.subscribeToBreakpoint(
      (width, height) => {
        // 根据高度断点设置每行元素数量
        switch (height) {
          case 'sm':
            setItemNum(12); // 一行展示 12 个元素
            break;
          case 'md':
            setItemNum(6); // 两行展示,每行 6 个元素
            break;
          case 'lg':
            setItemNum(4); // 三行展示,每行 4 个元素
            break;
          default:
            setItemNum(12); // 默认一行展示 12 个元素
        }
        // 根据宽度断点设置颜色
        switch (width) {
          case 'sm':
            setItemColor('red'); // 红色
            break;
          case 'md':
            setItemColor('orange'); // 橙色
            break;
          case 'lg':
            setItemColor('green'); // 绿色
            break;
          case 'xl':
            setItemColor('blue'); // 蓝色
            break;
          default:
            setItemColor('red'); // 默认红色
        }
      },
    );

    // 在组件卸载时移除订阅
    return () => {
      unsubscribe();
    };
  }, [breakpointManager]);

  // 生成 12 个元素的列表数据
  const data = Array.from({length: 12}, (_, index) => ({id: index + 1}));

  // 渲染列表项
  const renderItem = ({item}) => (
    <View
      style={[
        styles.item,
        {width: cwidth / itemNum - 10, backgroundColor: itemColor},
      ]}>
      <Text style={styles.itemText}>{item.id}</Text>
    </View>
  );

  return (
    <View style={{padding: 20}}>
      <Text>Current Width Breakpoint: {currentWidthBp}</Text>
      <Text>Current Height Breakpoint: {currentHeightBp}</Text>
      <Text>Current Width : {cwidth}</Text>
      <Text>Current Height : {cheight}</Text>
      <Text>Current Height / Width : {cheight / cwidth}</Text>

      {/* 横向列表区域 */}
      <View style={styles.listContainer}>
        <FlatList
          data={data}
          renderItem={renderItem}
          keyExtractor={item => item.id.toString()}
          numColumns={itemNum} // 动态设置每行的元素数量
          scrollEnabled={false} // 禁用滚动
          contentContainerStyle={styles.listContent}
          key={itemNum} // 强制重新渲染 FlatList
        />
      </View>
    </View>
  );
};

// 样式定义
const styles = StyleSheet.create({
  listContainer: {
    marginTop: 20,
    width: '100%', // 确保容器宽度占满屏幕
  },
  listContent: {
    justifyContent: 'center', // 内容居中
  },
  item: {
    height: 50, // 固定高度
    justifyContent: 'center',
    alignItems: 'center',
    borderWidth: 1,
    borderColor: '#ccc',
  },
  itemText: {
    fontSize: 16,
  },
});

export default BreakpointDemo;

Link

本库依赖以下三方库,请查看对应文档:

@react-native-oh-tpl/react-native-orientation

目前OpenHarmony暂不支持AutoLink,所以Link步骤需要手动配置。

首先需要使用DevEco Studio打开项目里的OpenHarmony工程,在工程根目录的oh-package.json5添加overrides字段:

{
  ...
  "overrides": {
    "@rnoh/react-native-openharmony" : "./react_native_openharmony"
  }
}

引入原生端代码

目前有两种方法:

  1. 通过har包引入(在IDE完善相关功能后该方法会被遗弃,目前首选此方法)。

    说明: har包位于三方库安装路径的harmony文件夹下。

    a. 打开entry/oh-package.json5,添加以下依赖:

    "dependencies": {
        "@rnoh/react-native-openharmony": "file:../react_native_openharmony",
        "@hadss/react_native_adaptive_layout": "file:../../node_modules/@hadss/react_native_adaptive_layout/harmony/adaptive_layout.har",
      }

    b. 配置CMakeLists和引入RNOHGeneratedPackage:

    打开entry/src/main/cpp/CMakeLists.txt,添加:

    project(rnapp)
    cmake_minimum_required(VERSION 3.4.1)
    set(CMAKE_SKIP_BUILD_RPATH TRUE)
    set(OH_MODULE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
    set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
    
    set(RNOH_CPP_DIR "${OH_MODULE_DIR}/@rnoh/react-native-openharmony/src/main/cpp")
    set(RNOH_GENERATED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/generated")
    set(CMAKE_ASM_FLAGS "-Wno-error=unused-command-line-argument -Qunused-arguments")
    set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie")
    add_compile_definitions(WITH_HITRACE_SYSTRACE)
    set(WITH_HITRACE_SYSTRACE 1) # for other CMakeLists.txt files to use
    + file(GLOB GENERATED_CPP_FILES "./generated/*.cpp")
    
    add_subdirectory("${RNOH_CPP_DIR}" ./rn)
    
    add_library(rnoh_app SHARED
    +    ${GENERATED_CPP_FILES}
        "./PackageProvider.cpp"
        "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
    )
    
    target_link_libraries(rnoh_app PUBLIC rnoh)

    c. 打开entry/src/main/cpp/PackageProvider.cpp,添加:

    #include "RNOH/PackageProvider.h"
    + #include "generated/RNOHGeneratedPackage.h"
    
    using namespace rnoh;
    
    std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
        return {
    +        std::make_shared<RNOHGeneratedPackage>(ctx)
        };
    }

    d. 在ArkTs侧引入LayoutModulePackage:

    打开entry/src/main/ets/RNPackagesFactory.ts,添加:

      ...
    + import { LayoutModulePackage } from '@hadss/react_native_adaptive_layout/ts';
    
    export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
      return [
    +   new LayoutModulePackage(ctx),
      ];
    }

    e. 运行:

    点击右上角的sync按钮

    或者在终端执行:

    cd entry
    ohpm install

    然后编译、运行即可。

  2. 直接链接源码。

    如需使用直接链接源码,请参考直接链接源码说明

API

说明: "Platform"列表示支持的平台,All表示支持所有平台。

断点(横向断点 )

NameDescriptionTypePlatform
getBreakpoints获取当前用于响应式布局的断点值。functionAll
setBreakpoints设置自定义的响应式布局断点值。functionAll
useBreakpointValue允许开发者为特定断点定义不同的值,并动态返回与当前屏幕宽度相对应的值。hookAll

断点(BreakpointManager横向纵向断点)

NameDescriptionTypePlatform
getInstance获取 BreakpointManager 的单例functionAll
getCurrentWidthBreakpoint获取当前的横向断点functionAll
getCurrentHeightBreakpoint获取当前的纵向断点functionAll
subscribeToBreakpoint订阅断点变化functionAll
destroy注销监听functionAll

折叠屏适配

折叠屏接口

NameDescriptionTypePlatform
getFoldCreaseRegion获取可折叠设备屏幕的折痕区域。functionOpenHarmony
getFoldStatus获取当前可折叠设备的状态(例如:展开、半折叠或折叠)。functionOpenHarmony
isFoldable判断设备是否可折叠。如果为 true,设备是可折叠的;否则是不可折叠设备。functionOpenHarmony
addFoldListener监听折叠设备的折叠状态变化。functionOpenHarmony
removeFoldListener移除已添加的折叠状态变化监听。functionOpenHarmony

FoldSplitContainer组件

NameDescriptionTypePlatform
primary主要区域回调函数。functionOpenHarmony
secondary次要区域回调函数。functionOpenHarmony
extra扩展区域回调函数,不传入的情况,没有对应区域。functionOpenHarmony
expandedLayoutOptions展开态布局信息。ExpandedRegionLayoutOptionsOpenHarmony
hoverModeLayoutOptions悬停态布局信息。HoverModeRegionLayoutOptionsOpenHarmony
foldedLayoutOptions折叠态布局信息。FoldedRegionLayoutOptionsOpenHarmony
onHoverStatusChange折叠屏进入或退出悬停模式时触发的回调函数。onHoverStatusChangeHandlerOpenHarmony

ExpandedRegionLayoutOptions

NameDescriptionTypePlatform
isExtraRegionPerpendicular扩展区域是否从上到下贯穿整个组件,当且仅当extra有效时此字段才生效。默认值:true。booleanOpenHarmony
verticalSplitRatio主要区域与次要区域之间的高度比例。默认值:PresetSplitRatio.LAYOUT_1V1。numberOpenHarmony
horizontalSplitRatio主要区域与扩展区域之间的宽度比例,当且仅当extra有效时此字段才生效。默认值:PresetSplitRatio.LAYOUT_3V2。numberOpenHarmony
extraRegionPosition扩展区域的位置信息,当且仅当isExtraRegionPerpendicular = false有效时此字段才生效。默认值:ExtraRegionPosition.top。ExtraRegionPositionOpenHarmony

HoverModeRegionLayoutOptions

NameDescriptionTypePlatform
showExtraRegion可折叠屏幕在半折叠状态下是否显示扩展区域。默认值:false。booleanOpenHarmony
horizontalSplitRatio主要区域与扩展区域之间的宽度比例,当且仅当extra有效时此字段才生效。默认值:PresetSplitRatio.LAYOUT_3V2。numberOpenHarmony
extraRegionPosition扩展区域的位置信息,当且仅当showExtraRegion时此字段才生效。默认值:ExtraRegionPosition.top。ExtraRegionPositionOpenHarmony

FoldedRegionLayoutOptions

NameDescriptionTypePlatform
verticalSplitRatio主要区域与次要区域之间的高度比例。默认值:PresetSplitRatio.LAYOUT_1V1。numberOpenHarmony

onHoverStatusChangeHandler

NameDescriptionTypePlatform
callback折叠屏进入或退出悬停模式时触发的回调函数。(status: HoverModeStatus) => voidOpenHarmony

HoverModeStatus

NameDescriptionTypePlatform
foldStatus设备的折叠状态。FoldStatusOpenHarmony
isHoverModeapp当前是否处于悬停态。booleanOpenHarmony

ExtraRegionPosition

NameDescriptionValue
top扩展区域在组件上半区域。1
bottom扩展区域在组件下半区域。2

PresetSplitRatio

NameDescriptionValue
LAYOUT_1V11:1比例。1/1
LAYOUT_3V23:2比例。3/2
LAYOUT_2V32:3比例。2/3

约束与限制

本示例仅支持标准系统上运行,支持设备:华为手机。 DevEco Studio版本:DevEco Studio NEXT Developer Beta5及以上。 SDK版本:API13及以上。