自定义Android控件

Tabris.js控件由JavaScript API和原生平台的实现组成。本文档介绍Android平台上的自定义控件的原生实现。

为了实现自定义控件你需要本地构建

在Cordova基础上构建

为了创建Tabris.js自定义控件,我们使用Cordova的构建系统。因此,我们创建一个与Tabris.js特定的API相关联的Cordova插件。Tabris.js自定义控件不需要接触任何Cordova特定的Java API。通过Tabris.js特定的API可以实现与JavaScript部分的所有交互。

通过Cordova的插件架构,我们可以利用Cordova构建工具链,并在我们的插件中提供一个plugin.xml来自定义构建过程。一旦定义了一个插件,app就可以通过常规的cordova plugin add <plugin-id/git-url>shell命令或一个config.xml中的<plugin />来使用。

<img src=">一个本文档中概述的概念的使用示例可以在。这里找到。

从JavaScript接收消息

自定义控件需要处理JavaScript传入的消息并将消息返回给JavaScript。此通信循环的主要入口点是com.eclipsesource.tabris.android.Operator。该Operator提供从JavaScript到原生平台的所有通信的回调方法。以下代码片段展示了一个使用com.eclipsesource.tabris.android.AbstractViewOperator作为View特定操作基础的基本操作:

  1. public class CalendarOperator extends AbstractViewOperator<CalendarView> {
  2. public CalendarOperator(Activity activity, TabrisContext tabrisContext) {
  3. // ..
  4. }
  5. @Override
  6. public String getType() {
  7. return "com.example.calendar.Calendar";
  8. }
  9. }

上面的代码片段展示了Operator的两个重要方面:该类必须有一个具有两个参数的构造函数CalendarOperator(<Activity>, <TabrisContext>),以及getType()方法必须返回JavaScript端自定义控件的名字。

Registering an operator

To make an operator available to the Tabris.js Android runtime we have to register it. The simplest way is to declare our operator in a meta-data entry of the AndroidManifest.xml.

Since our custom widget is wrapped in a Cordova plug-in we can use the plug-in’s plugin.xml file to add a new meta-data entry into the AndroidManifest.xml via the Cordova config-file directive. The following snippet shows how to declare our operator in the plugin.xml so that it is part of the final AndroidManifest.xml:

  1. <plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
  2. xmlns:android="http://schemas.android.com/apk/res/android"
  3. id="com.example.tabris.calendar">
  4. <platform name="android">
  5. <config-file target="AndroidManifest.xml" parent="/manifest/application">
  6. <meta-data
  7. android:name="com.example.tabris.android.OPERATOR.com.example.tabris.calendar"
  8. android:value="com.example.tabris.calendar.CalendarOperator" />
  9. </config-file>
  10. </platform>
  11. ...
  12. </plugin>

The snippet above inserts the meta-data element with its two attributes name and value into the AndroidManifest.xml. The name attribute has to be an application wide unique ID with a prefix of com.eclipsesource.tabris.android.OPERATOR. In order to make the name unique we append the widget specific ID .com.eclipsesource.tabris.calendar to the prefix. The value attribute of the meta-data element has to contain the fully qualified class name of our Operator implementation, eg.: com.eclipsesource.tabris.calendar.CalendarOperator.

Instantiating a widget

With the Operator registered we can now instantiate the Android View object that we want to display in the UI. To handle a create operation sent from JavaScript we implement the Operator.create(<Properties>) method in the operator:

  1. @Override
  2. public CalendarView createView(Properties properties) {
  3. return new CalendarView(activity);
  4. }

The snippet instantiates the Android android.widget.CalendarView with the Activity passed into the constructor of the Operator. The properties argument could contain widget specific configuration directives but is not used in this example.

Handling properties

While we have instantiated our widget and passed it back to the system, it is not yet visible in the UI. To show an Android View it has to be added to the view hierarchy. In order to do that we have to process the parent property passed in from JavaScript. The parent provides the widget onto which we want to add our custom widget.

Since this is a very common scenario we don’t have to implement this ourselves but rather rely on the pre-existing com.eclipsesource.tabris.android.ViewPropertyHandler. The ViewPropertyHandler implements the PropertyHandler interface which provides get and set methods to support various properties.

The concrete ViewPropertyHandler provides default implementations for common widget properties like parent, layoutData, visible etc..

To activate the property handler we override AbstractOperator.getPropertyHandler() and return the corresponding handler:

  1. @Override
  2. public PropertyHandler<CalendarView> getPropertyHandler(CalendarView calendarView) {
  3. return propertyHandler;
  4. }

By returning the default ViewPropertyHandler we have covered all the common widget properties of Tabris.js but it is also possible to extend the ViewPropertyHandler to provide your own implementation for a property or to add a custom property. The following snippet shows how to add support for the custom property date:

  1. public class CalendarWidgetPropertyHandler extends ViewPropertyHandler<CalendarView> {
  2. @Override
  3. public void set(CalendarView view, Properties properties) {
  4. super.set(view, properties);
  5. if (properties.hasProperty("date")) {
  6. view.setDate(properties.getLong("date"), true, false);
  7. }
  8. }
  9. @Override
  10. public Object get(CalendarView view, String property) {
  11. if (property.equals("date")) {
  12. return String.valueOf(view.getDate());
  13. }
  14. return super.get(view, property);
  15. }
  16. }

Note how the snippet not only processes incoming properties in the set method but also provides a get implementation so that the date property can be read as well.

Sending messages to JavaScript

<img src="> This API is likely going to change.

While receiving an operation from JavaScript covers a lot of ground we also want to send messages proactively to JavaScript. A classic example is a user initiated action like a button tap.

To send a message for a particular widget we use a com.eclipsesource.tabris.android.RemoteObject. A RemoteObject can be obtained from the TabrisContext via the ObjectRegistry:

  1. RemoteObject remoteObject = tabrisContext.getObjectRegistry().getRemoteObjectForObject(view);

Continuing the example from above the following snippet sends a notify operation to JavaScript when the user changes the date on the CalendarView:

  1. private class OnDateChangeListener implements CalendarView.OnDateChangeListener {
  2. @Override
  3. public void onSelectedDayChange(@NonNull CalendarView calendarView, int year, int month, int dayOfMonth) {
  4. String date = // get date from calendarView
  5. RemoteObject remoteObject = tabrisContext.getObjectRegistry().getRemoteObjectForObject(calendarView);
  6. remoteObject.notify("change_date", "date", date);
  7. }
  8. }

Destroying a widget

When a widget is no longer being used we also need to take care of destroying it. In case of our custom Android View we receive a destroy operation in the Operator and are responsible for cleaning up any resources that are not required anymore. When an Operator inherits from the AbstractViewOperator the destroy operation will remove the view from the view hierarchy.

  1. @Override
  2. public void destroy(CalendarView calendarView) {
  3. super.destroy(calendarView);
  4. // perform any necessary cleanup
  5. }

原文:

https://youjingyu.github.io/Tabris-Documention/?folderName=custom-widgets&pageName=custom-widgets-android.html