自定义界面组件
App 开发中有可能使用到大量的UI组件,除了 Hippy SDK 已包括其中常用的部分,如View
、Text
、Image
等,我们仍可能需要对 UI 组件进行扩展封装。
组件扩展
我们将以MyView
为例,从头介绍如何扩展组件。
扩展组件包括:
- 扩展
HippyViewController
。 - 实现
createViewImpl方法
、 - 实现
Props
设置方法。 - 手势事件处理。
- 注册
HippyViewController
。
HippyViewController
是一个视图管理的基类(如果是ViewGroup
的组件,基类为 HippyGroupController
)。 在这个例子中我们需要创建一个 MyViewController
类,它继承 HippyViewController<MyView>
。MyView
是被管理的UI组件类型,它应该是一个 Android View
或者 ViewGroup
。 @HippyController
注解用来定义导出给JS使用时的组件信息。
@HippyController(name = "MyView")
public class MyViewController extends HippyViewController<MyView>
{
...
}
实现 createViewImpl 方法
当需要创建对视图时,引擎会调用 createViewImpl
方法。
@Override
protected View createViewImpl(Context context)
{
// context实际类型为HippyInstanceContext
return new MyView(context);
}
源码
UIManagerModule
hippy创建终端View入口
@HippyMethod(name = "createNode")
public void createNode(int rootID, HippyArray hippyArray) {
HippyRootView hippyRootView = mContext.getInstance(rootID);
DomManager domManager = this.mContext.getDomManager();
if (hippyArray != null && hippyRootView != null && domManager != null) {
int len = hippyArray.size();
for (int i = 0; i < len; i++) {
...
String className = (String) nodeArray.get(NAME);
String tagName = (String) nodeArray.get(TAG_NAME);
HippyMap props = (HippyMap) nodeArray.get(PROPS);
/* 分析1 */
domManager.createNode(hippyRootView, rootID, tag, pTag, index, className, tagName, props);
}
}
}
- / 分析1 /
DomManager
创建Dom节点,如果不是懒加载立即创建View
public void createNode(final HippyRootView hippyRootView, int rootId, final int id, int pid, int index, final String className, String tagName, HippyMap map) {
...
addDispatchTask(new IDomExecutor() {
@Override
public void exec() {
/* 分析2 */
mRenderManager.createPreView(hippyRootView, id,
nativeParentNode.getId(), childIndex.mIndex,className, newProps);
}
});
addUITask(new IDomExecutor() {
@Override
public void exec() {
mRenderManager.createNode(hippyRootView, id, nativeParentNode.getId(),
childIndex.mIndex, className, newProps);
}
});
...
}
- / 分析2 /
ControllerManager
如果不是懒加载立即创建View
public void createPreView(HippyRootView hippyRootView, int id, int pid, int mIndex,
String className, HippyMap newProps) {
...
if (!isLazy) {
/* 分析3 */
mControllerManager.createPreView(hippyRootView, id, className, newProps);
}
}
- / 分析3 /
ControllerManager
public void createPreView(HippyRootView rootView, int id, String className,
HippyMap initialProps) {
/* 分析3 a */
View view = mControllerRegistry.getView(id);
if (view == null) {
/* 分析3 b */
// 若无缓存,则获取Controller重新创建并缓存view
HippyViewController controller = mControllerRegistry.getViewController(className);
/* 分析4 */
view = controller.createView(rootView, id, mContext, className, initialProps);
...
}
}
/* 分析3 a */
// 若无缓存,则认为是根节点
public View getView(int id) {
View view = mViews.get(id);
if (view == null) {
view = mRoots.get(id);
}
return view;
}
/* 分析3 b */
// ControllerManager 被创建时会调用 processControllers 方法,其中会调用 addControllers 方法。
// 此方法会将 将Hippy包中的HippyViewController注册到ControllerRegistry中
// getViewController 实际返回的就是 HippyViewController
public void addControllers(List<HippyAPIProvider> hippyPackages) {
...
// 循环处理所有注册表
for (HippyAPIProvider hippyPackage : hippyPackages) {
List<Class<? extends HippyViewController>> components = hippyPackage.getControllers();
...
for (Class hippyComponent : components) {
...
ControllerHolder holder = new ControllerHolder(
(HippyViewController) hippyComponent.newInstance(), lazy);
// 维护 name - ViewController 的 Map 以注册 Controller
mControllerRegistry.addControllerHolder(name, holder);
// 允许注册多个别名
if (names.length > 0) {
for (String s : names) {
mControllerRegistry.addControllerHolder(s, holder);
}
}
}
}
}
- / 分析4 /
class HippyViewController<T extends View & HippyViewBase>
优先使用带参数的重载方法。
public View createView(HippyRootView rootView, int id, HippyEngineContext hippyEngineContext,
String className,
HippyMap initialProps) {
...
if (rootView != null) {
Context rootViewContext = rootView.getContext();
// CustomViewCreator" <==> 宿主自定义的一个HippyCustomViewCreator
// (这个creator还得通过ModuleParams.Builder.setCustomViewCreator来指定才行)
if (rootViewContext instanceof HippyInstanceContext) {
@SuppressWarnings("rawtypes") Map nativeParam = ((HippyInstanceContext) rootViewContext)
.getNativeParams();
if (nativeParam != null) {
Object object = nativeParam.get(HippyCustomViewCreator.HIPPY_CUSTOM_VIEW_CREATOR);
if (object instanceof HippyCustomViewCreator) {
view = ((HippyCustomViewCreator) object)
.createCustomView(className, rootView.getContext(), initialProps);
}
}
}
if (view == null) {
view = createViewImpl(rootView.getContext(), initialProps);
if (view == null) {
view = createViewImpl(rootView.getContext());
}
}
...
}
return view;
}
protected abstract View createViewImpl(Context context);
protected View createViewImpl(Context context, HippyMap iniProps) {
return null;
}