如何在Android中实现React Native UI组件方法

时间:2017-11-22 17:25:26

标签: react-native react-native-android react-native-native-ui-component react-native-native-module

我很清楚,对于本机反应原生模块,我们可以使用@ReactMethod导出一个方法并从JSX调用它,但我们如何在react-native native中做同样的事情UI组件?

在文档中,我只看到@ReactProp被提及。 如果@ReactMethod不起作用,那么如何从JSX访问我的本机UI组件的属性呢? (在iOS上,这可以使用RCT_EXPORT_METHOD在原生ui组件上完成,但在Android上可能类似吗?)

谢谢。

3 个答案:

答案 0 :(得分:5)

好的,我最终创建了一个模块,并在其上传递了UI组件参考的构造函数:

这是 UI组件

import cartopy
import cartopy.crs as ccrs
from matplotlib.colors import BoundaryNorm
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import cartopy.io.shapereader as shpreader

from metpy.calc import get_wind_components
from metpy.cbook import get_test_data
from metpy.gridding.gridding_functions import interpolate,      remove_nan_observation 
from metpy.plots import add_metpy_logo
from metpy.units import units

to_proj = ccrs.PlateCarree()


data=pd.read_csv('/home/borisvladimir/Documentos/Datos/EMAs/EstacionesZMG/RedZMG.csv',usecols=(1,2,3),names=['Lat','Lon','tmax'],na_values=-99999,header=0)


fname='/home/borisvladimir/Dropbox/Diversos/Shapes/LimiteAMG.shp'
adm1_shapes = list(shpreader.Reader(fname).geometries())


 lon = data['Lon'].values
 lat = data['Lat'].values
 xp, yp, _ = to_proj.transform_points(ccrs.Geodetic(), lon, lat).T


 x_masked, y_masked, t = remove_nan_observations(xp, yp, data['tmax'].values)

 #Interpola temp usando Cressman
tempx, tempy, temp = interpolate(x_masked, y_masked, t, interp_type='cressman', minimum_neighbors=3, search_radius=400000, hres=35000)
temp = np.ma.masked_where(np.isnan(temp), temp)

levels = list(range(-20, 20, 1))
cmap = plt.get_cmap('viridis')
norm = BoundaryNorm(levels, ncolors=cmap.N, clip=True)

fig = plt.figure(figsize=(15, 10))
view = fig.add_subplot(1, 1, 1, projection=to_proj)

view.add_geometries(adm1_shapes, ccrs.PlateCarree(),edgecolor='black',  facecolor='white', alpha=0.5)


view.set_extent([-103.8, -103, 20.3, 21.099 ], ccrs.PlateCarree())

ZapLon,ZapLat=-103.50,20.80
GuadLon,GuadLat=-103.33,20.68
TonaLon,TonaLat=-103.21,20.62
TlaqLon,TlaqLat=-103.34,20.59
TlajoLon,TlajoLat=-103.44,20.47

plt.text(ZapLon,ZapLat,'Zapopan',transform=ccrs.Geodetic())
plt.text(GuadLon,GuadLat,'Guadalajara',transform=ccrs.Geodetic())
plt.text(TonaLon,TonaLat,'Tonala',transform=ccrs.Geodetic())
plt.text(TlaqLon,TlaqLat,'Tlaquepaque',transform=ccrs.Geodetic())
plt.text(TlajoLon,TlajoLat,'Tlajomulco',transform=ccrs.Geodetic())

mmb = view.pcolormesh(tempx, tempy, temp,transform=ccrs.PlateCarree(),cmap=cmap, norm=norm)
plt.colorbar(mmb, shrink=.4, pad=0.02, boundaries=levels)
plt.show()

这是我为该组件创建的模块

public class RCTACCalendarManager extends ViewGroupManager <RCTACCalendar> {
    public static final String REACT_CLASS = "RCTACCalendar";
    private RCTACCalendar calendarInstance;
    public RCTACCalendarManager(ReactApplicationContext reactContext) {
            super();
        }

        @Override
        public String getName() {
            return REACT_CLASS;
        }


        @Override
        public RCTACCalendar createViewInstance(ThemedReactContext context) {
            calendarInstance = new RCTACCalendar(context);
            return calendarInstance;
    }

    public RCTACCalendar getCalendarInstance() { // <-- returns the View instance
        return calendarInstance;
    }

}

以及我在声明中将这两者结合在一起的方式:

public class RCTACCalendarModule extends ReactContextBaseJavaModule {

    private RCTACCalendar calendarInstance;

    public RCTACCalendarModule(ReactApplicationContext reactContext, RCTACCalendarManager calManager) {
        super(reactContext);
        if (calManager != null) {
            calendarInstance = calManager.getCalendarInstance();
        }

    }

    @Override
    public String getName() {
        return "ACCalendarManager";
    }

    @ReactMethod
    public void mySuperDuperFunction(Promise promise) {
        if (calendarInstance  != null) {
            calendarInstance.mySuperDuperFunction(promise); // <-- Magic
        }
    }
}

它就像一个魅力。

答案 1 :(得分:1)

如果您只需要支持Android,则现有的答案非常有用,但是当我尝试与iOS集成时,我发现它也无效。我花了很多时间试图将这种方法纠缠到iOS中,所以我推荐使用我想出的方法:使用react-native随附的UIManager

反应本机组件

...
import { UIManager, findNodeHandle } from 'react-native';

class ComponentWithNativeFunctionality extends React.Component {
   const myRef = React.createRef();

   functionToCall = () => {
      UIManager.dispatchViewManagerCommand(
         findNodeHandle(this.myRef.current),
         "nameOfFunctionToCallInNativeLand",
         [/* additional arguments */]
      );
   }

   render() {
     return <NativeComponentView ref={this.myRef} />
   }

}

Android

public class YourViewManager extends SimpleViewManager<YourView> {

  ...

  @Override
  public void receiveCommand(YourView view, String commandId, @Nullable ReadableArray args) {
    super.receiveCommand(view, commandId, args);
    switch (commandId) {
      case "nameOfFunctionToCallInNativeLand":
        view.nameOfFunctionToCallInNativeLand();
        break;
    }
  }

}

iOS(使用Swift)

  1. #import "React/RCTUIManager.h"添加到您的Bridging-Header.h
// YourViewManager.m
@interface RCT_EXTERN_MODULE(YourViewManagerClass, RCTViewManager)
...
RCT_EXTERN_METHOD(
    nameOfFunctionToCallInNativeLand: (nonnull NSNumber *)node
)

@end
// YourViewManagerClass.swift

@objc(YourViewManagerClass)
class YourViewManagerClass: RCTViewManager {

    @objc func nameOfFunctionToCallInNativeLand(_ node: NSNumber) -> Void {
        DispatchQueue.main.async {
            let component = self.bridge.uiManager.view(
              forReactTag: node
            ) as! MisnapCameraView
            component.nameOfFunctionToCallInNativeLand()
        }
    }

}

另一个注意事项:您不能像使用模块那样传递Promise。您将必须传入JS中生成的唯一ID,然后完成操作后,触发一个事件以将结果冒泡回JS,并将ID附加到事件上。

答案 2 :(得分:0)

对于本机反应原理的Android UI组件,您必须使您的视图类扩展为SimpleViewManager

见文件here