做过weex开发的同学应该都知道weex的原生扩展可以分为module扩展和component扩展,component扩展也可以被称为UI组件扩展,我们把原生中的UI组件封装之后就能在vue文件中以标签的方式使用了,这里我们主要讲一下component的扩展。
常规的component扩展知识在weex官网中都有教程,我在这里就不再赘述了,如果还不熟悉的话请移步weex官网中的教程。
那么我们接下来就着重介绍一下官网中没有提到的部分,分为容器类组件和独立组件两个部分探讨,我们以map组件为例进行。
initComponentHostView
这个方法我们可以看出是初始化组件宿主view的方法,我们通常会重写这个方法返回我们要显示的原生view,并进行组件一些相关数据的初始化。
@Override
protected WeexMapView initComponentHostView(@NonNull Context context) {
this.mapView = new WeexMapView(context);
if (context instanceof Activity) {
mActivity = (Activity) context;
}
requestPermissions();
return this.mapView;
}
setProperty
这个方法是设置组件属性的方法,我们可以在合适的时候调用来设置组件的属性。一般在开发独立组件的时候不会使用这个方法,因为我们通过在各个属性的set方法上添加@component注解就可以动态设置其属性了。但是有时候我们的所设置的属性不是直接作用在原生view上,而是在一些adapter或者option上配置,设置完成才会设置到原生view上,这个时候为了确保属性在option上已经配置完成,需要在initComponentHostView方法中遍历属性调用此方法设置,简单示例如下:
@Override
protected View initComponentHostView(@NonNull Context context) {
view= new View();
options=new Options();
for (String key:getAttrs().keySet()){
setProperty(key,getAttrs().get(key));
}
return view;
}
onHostViewInitialized
这个方法是组件的原生view初始化完成时候会回调的方法,我们在这里可以做一些需要的处理。比如在option参数设置完成后再此方法中我们可以将option设置到view上。
/*初始化完成回调,在setProperty设置完所有属性后在这里进行设置*/
@Override
protected void onHostViewInitialized(View host) {
super.onHostViewInitialized(host);
view.setOption(option);
}
@JSMethod(uiThread = true)
我们如果需要在vue的js代码中调用原生组件的方法我们需要在方法上添加@JSMethod注解将方法暴露给js,
@JSMethod(uiThread = true)
/*地图缩放到指定比例大小*/
public void setZoomTo(int zoom){
mapView.aMap.moveCamera(CameraUpdateFactory.zoomTo(zoom));
}
在js中调用方法如下
this.$refs.map.setZoomTo(10);
initComponentHostView(@NonNull Context context)
与独立组件中用法相同。
createChildViewAt(int index)
通常在需要区分子组件类型时使用,最终会调用addSubView方法。我们需要注意的是在重写此方法是不能将其父类中的child.createView()这行代码,否则就不会再调用子组件的构造方法之外的其他方法了。
//WXComponet源码
public void createChildViewAt(int index) {
Pair ret = rearrangeIndexAndGetChild(index);
if (ret.first != null) {
WXComponent child = ret.first;
//这行代码不要覆写
child.createView();
//下面的代码可以按照自己的需求进行修改
if (!child.isVirtualComponent()) {
addSubView(child.getHostView(), ret.second);
}
}
}
addSubView(View child, int index)
子组件添加或者设置到到父组件中,比如要自定义ListView子组件,我们就可以在这里讲view添加到数据集合中,并调用Adapter的notifyDataSetChanged刷新ListView。
//添加子元素时回调
@Override
public void addSubView(View child, int index) {
weexPages.add(child);
adapter.notifyDataSetChanged();
if(index==getChildCount()-1){
hostView.setCurrentItem(position);
}
}
remove(WXComponent child, boolean destroy)
子组件被移除时做一些必要的处理
//移除子元素时回调
@Override
public void remove(WXComponent child, boolean destroy) {
weexPages.remove(child.getHostView());
adapter.notifyDataSetChanged();
}
initComponentHostView(@NonNull Context context)
通过实践发现在自定义容器类组件中使用自定义的子组件时其属性无法仅仅通过@component注解动态更新;并且子组件如果不需要返回真实的view,而是作为组件(vue标签)的形式调用父组件的方法最后返回父类的initComponentHostView即可。
@Override
protected View initComponentHostView(@NonNull Context context) {
mapView = (WeexMapView) getParent().getRealView();
addMarkerListener();
options=new MarkerOptions();
//自定义容器类组件的子组件需要在初始化是遍历属性进行属性设置
for (String key:getAttrs().keySet()){
setProperty(key,getAttrs().get(key));
}
//这里如果此组件最终目的是调用父组件方法则返回父类的初始化方法
return super.initComponentHostView(context);
}
updateAttrs(Map attrs)
通过实践发现在自定义容器类组件中使用自定义的子组件时其属性无法仅仅通过@component注解动态更新,因此我们需要在此方法中监听属性的变化进行属性的设置。此回调方法中的Map参数返回的就是发生变化的属性的集合。
@Override
public void updateAttrs(Map attrs) {
super.updateAttrs(attrs);
for (Object key:attrs.keySet()){
setProperty(key.toString(),attrs.get(key));
}
//在这里重新设置组件参数
addMarker();
}
onHostViewInitialized(WeexMapView host)
在这里讲虚拟组件设置到父组件上
以上就是我对weex开发Android组件在实践中的理解和总结,如果有不对的地方还望不吝告知。另外我的开源的weex快速开发的开源项目https://liuxinyea.github.io/IWeex/,有一些自己扩展的component和module,各位同学如果感兴趣可以看一下。