自定义界面组件
App 开发中有可能使用到大量的UI组件,Hippy SDK 已包括其中常用的部分,如View
、Text
、Image
等,但这极有可能无法满足你的需求,这就需要对 UI 组件进行扩展封装。
更多特性
处理组件方法调用
在有些场景,JS需要调用组件的一些方法,比如 MyView
的 changeColor
。这个时候需要在 HippyViewController
重载 dispatchFunction
方法来处理JS的方法调用。
public void dispatchFunction(MyView view, String functionName, HippyArray var)
{
switch (functionName)
{
case "changeColor":
String color = var.getString(0);
view.setColor(Color.parseColor(color));
break;
}
super.dispatchFunction(view, functionName, var);
}
源码
UIManagerModule
组件方法调用的入口
@HippyMethod(name = "callUIFunction")
public void callUIFunction(HippyArray hippyArray, Promise promise) {
...
int id = hippyArray.getInt(0);
String functionName = hippyArray.getString(1);
HippyArray array = hippyArray.getArray(2);
/* 分析1 */
domManager.dispatchUIFunction(id, functionName, array, promise);
}
- / 分析1 /
DomManager
添加任务,使组件方法向下分发
public void dispatchUIFunction(final int id, final String functionName, final HippyArray
array,final Promise promise) {
addNulUITask(new IDomExecutor() {
@Override
public void exec() {
/* 分析2 */
mRenderManager.dispatchUIFunction(id, functionName, array, promise);
}
});
}
- / 分析2 /
RenderManager
继续向下分发组件方法
public void dispatchUIFunction(int id, String functionName, HippyArray var, Promise promise) {
RenderNode renderNode = mNodes.get(id);
...
/* 分析3 */
renderNode.dispatchUIFunction(functionName, var, promise);
...
}
- / 分析3 /
RenderNode
在mUIFunction
中添加组件方法,等待被调用
public void dispatchUIFunction(String functionName, HippyArray parameter, Promise promise) {
if (mUIFunction == null) {
mUIFunction = new ArrayList<>();
}
mUIFunction.add(new UIFunction(functionName, parameter, promise));
}
RenderNode
节点更新时,调用已经添加的所有组件方法
public void update() {
...
if (mUIFunction != null && mUIFunction.size() > 0) {
for (int i = 0; i < mUIFunction.size(); i++) {
UIFunction uiFunction = mUIFunction.get(i);
/* 分析4 */
mComponentManager.dispatchUIFunction(mId, mClassName, uiFunction.mFunctionName,
uiFunction.mParameter,uiFunction.mPromise);
}
mUIFunction.clear();
mUIFunction = null;
}
...
}
- / 分析4 /
ControllerManager
区分有无回调,调用组件方法
public void dispatchUIFunction(int id, String className, String functionName, HippyArray var,
Promise promise) {
HippyViewController hippyViewController = mControllerRegistry.getViewController(className);
View view = mControllerRegistry.getView(id);
if (!promise.isCallback()) {
hippyViewController.dispatchFunction(view, functionName, var);
} else {
hippyViewController.dispatchFunction(view, functionName, var, promise);
}
}
HippyViewController<T extends View & HippyViewBase>
调用到重载方法
public void dispatchFunction(T view, String functionName, HippyArray var) {
}
public void dispatchFunction(T view, String functionName, HippyArray params, Promise promise) {
}
事件回调
Hippy SDK 提供了一个基类 HippyViewEvent
,其中封装了UI事件发送的逻辑,只需调用 send
方法即可发送事件到JS对应的组件上。比如我要在 MyView
的 onAttachedToWindow
的时候发送事件到前端的控件上面。 示例如下:
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
// this is show how to send message to js ui
HippyMap hippyMap = new HippyMap();
hippyMap.pushString("test", "code");
new HippyViewEvent(" onAttachedToWindow").send(this, hippyMap);
}
源码
new HippyViewEvent(" onAttachedToWindow").send(this,hippyMap);
send
方法 会将事件名,参数发送给指定id的组件
public void send(View view, Object param) {
if (view != null && view.getContext() instanceof HippyInstanceContext) {
HippyEngineContext context = ((HippyInstanceContext)
view.getContext()).getEngineContext();
send(view.getId(), context, param);
}
}
public void send(int id, HippyEngineContext context, Object param) {
if (context == null) {
return;
}
HippyModuleManager hmm = context.getModuleManager();
if (hmm != null) {
hmm.getJavaScriptModule(EventDispatcher.class).receiveUIComponentEvent(id, mEventName,
param);
}
}
HippyViewController 的回调函数
onAfterUpdateProps
:属性更新完成后回调。onBatchComplete
:一次上屏操作完成后回调(适用于 ListView 类似的组件,驱动 Adapter刷新等场景)。onViewDestroy
:视图被删除前回调(适用于类似回收视图注册的全局监听等场景)。onManageChildComplete
:在HippyGroupController
添加、删除子视图完成后回调。
源码 (以onManageChildComplete
为例)
RenderNode
更新节点时触发回调函数 沿着a -> b -> c
调用,触发重载的回调函数
public void update() {
...
if (mChildPendingList.size() > 0) {
Collections.sort(mChildPendingList, new Comparator<RenderNode>() {
@Override
public int compare(RenderNode o1, RenderNode o2) {
return o1.indexFromParent() < o2.indexFromParent() ? -1 : 0;
}
});
for (int i = 0; i < mChildPendingList.size(); i++) {
RenderNode renderNode = mChildPendingList.get(i);
mComponentManager.addChild(mId, renderNode.getId(), renderNode.indexFromParent());
}
mChildPendingList.clear();
// 更新子节点则添加标志位
mNotifyManageChildren = true;
}
...
// 存在标志位则开始出发回调函数并重置标志位
if (mNotifyManageChildren) {
/* a */
manageChildrenComplete();
mNotifyManageChildren = false;
}
...
}
/* a */
public void manageChildrenComplete() {
if (!mIsLazyLoad && !mIsDelete) {
/* b */
mComponentManager.onManageChildComplete(mClassName, mId);
}
}
/* b */
public void onManageChildComplete(String className, int id) {
HippyViewController hippyViewController = mControllerRegistry.getViewController(className);
View view = mControllerRegistry.getView(id);
if (view != null) {
/* c */
hippyViewController.onManageChildComplete(view);
}
}
/* c */
protected void onManageChildComplete(T view) {}