react-native 项目搭建 - 更新中...

167 阅读2分钟

1: 项目的初始化

npx react-native init MyApp --template react-native-template-typescript

使用react-native typescript的默认构建命令初始化项目

2: 依赖安装

// npm依赖的安装
npm install

// ios的cocoapods依赖的安装
cd ios 
pod install
// cocoapods的依赖安装特别久......

2.1 cocoapods安装的加速

CocoaPods 是一个 Cocoa 和 Cocoa Touch 框架的依赖管理器,具体原理和 Homebrew 有点类似,都是从 GitHub 下载索引,然后根据索引下载依赖的源代码。

对于旧版的 CocoaPods 可以使用如下方法使用 tuna 的镜像:

$ pod repo remove master
$ pod repo add master https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git
$ pod repo update
复制代码

新版的 CocoaPods 不允许用pod repo add直接添加master库了,但是依然可以:

$ cd ~/.cocoapods/repos 
$ pod repo remove master
$ git clone https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git master
复制代码

最后进入自己的工程,在自己工程的podFile第一行加上:

source 'https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git'

一些库的安装

有React-Navigation, React-Native-Elements, React-Native-Vector-Icons等,相关安装流程可参考其官方文档。

ios的启动调整为:自定义的原生视图

首先展示下RN默认创建的AppDelegate.m文件的didFinishLaunchingWithOptions方法内容:

- (**BOOL**)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  self.moduleName = @"DingApp";
  self.initialProps = @{};
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

调整后:rootViewController将作为自定义的根视图。

在AppDelegate.m的文件顶部导入,让OC识别项目中的swift代码
#import <项目名-Swift.h>
- (**BOOL**)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [UIViewController new];
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];
  return YES;
}

ios获取屏幕大小

let screenWidth = UIScreen.main.bounds.width
let screenHeight = UIScreen.main.bounds.height

react-native集成swift原生组件

这里仅将swift组件抛出去,还没有添加属性,方法,事件。

// 创建TeMetroViewManager.m文件,内容如下:
@interface RCT_EXTERN_MODULE(TeMetroViewManager, RCTViewManager)

// 导出TeMetroView内的方法: buildMapSize
RCT_EXTERN_METHOD (
  buildMapSize:(nonnull NSNumber *)node
  width:(nonnull CGFloat *)width
  height:(nonnull CGFloat *)height
)

@end
// 创建TeMetroViewManager.swift文件,内容如下:
// TeMetroView是ios内的一个swift组件
@objc(TeMetroViewManager) 
class TeMetroViewManager: RCTViewManager { 
    // 这里返回swift组件
    override func view() -> UIView {
        return TeMetroView() 
    } 
    override static func requiresMainQueueSetup() -> Bool {
        return true
    } 
    
    // 根据node获取所在的视图
    private func getTargetView(node: NSNumber) -> TeMetroView? {
        if let view = self.bridge.uiManager.view(forReactTag: node) {
            return view as? TeMetroView
        }
        return nil
    }
  
    // buildMapSize是提供给RN调用的
    @objc public func buildMapSize(_ node: NSNumber, width: CGFloat, height: CGFloat) {
      DispatchQueue.main.async {
        guard let targetView = self.getTargetView(node: node) else {
          return
        }
        targetView.buildMapSize(width: width, height: height)
      }
    }
}
// 在react-native目录下创建te-metro-native-view.ts文件,内容如下:
import {requireNativeComponent} from 'react-native';
import TeMetroNativeViewProps from './TeMetroNativeViewProps';

// requireNativeComponent 自动把'TeMetroView'解析为'TeMetroViewManager'
export default requireNativeComponent<TeMetroNativeViewProps>('TeMetroView');

// 在react-native目录下创建TeMetroView.tsx组件文件,内容如下:
import {StyleSheet} from 'react-native';
import TeMetroNativeView from './TeMetroNativeView';
import TeMetroViewProps from './TeMetroViewProps';

export default function TeMetroView(props: TeMetroViewProps) {
  return <TeMetroNativeView style={{...styles.containerView}} />;
}

// 包装的原生UI组件的flex设置为1,可以全部填充父组件。
const styles = StyleSheet.create({
  containerView: {
    flex: 1,
  },
});

// rn调用swifu组件内的方法
const manager: any = UIManager;
manager.dispatchViewManagerCommand(
  findNodeHandle(nativeRef.current),
  manager.TeMetroView.Commands.buildMapSize,
  [width, height],
);

ios像canvas一样绘制内容

// UIGraphicsGetCurrentContext必须在draw函数中使用
guard let context = UIGraphicsGetCurrentContext() else {
    return
}
// 对context的使用在canvas的使用思路是一样的。

// 将原生ios的canvas背景设置为透明
UIColor(white: 1, alpha: 0)

// 调用setNeedsDisplay会触发ios系统对canvasView进行重绘,进而执行其draw方法。
self.canvasView.setNeedsDisplay()

ios原生绘制地铁线路图展示

image.png