2017년 3월 3일 금요일

Using App Inventor extensions to implement multitouch: ScaleDetector


DRAFT (September 13):  Building extensions requires the App Inventor Extensions capability, which is not yet incorporated into the App Inventor release.  But you can try some of the steps described below, using our extension  test server:

The demo packaged app, ScaleGestureDemo.apk can be loaded and run just like any apk file.
You can build the demonstration source app by following Part 1 below by loading the provided source file ScaleGestureDemo.aia.   To build the app, you’ll  need to use the App Inventor test server at http://extension-test.appinventor.mit.edu.  You will also need to use the AI Companion corresponding to that instance.   After connecting to the server, look under Help -> Companion Information to download that Companion.   You’ll need to reinstall the ordinary companion when you switch back to the ordinary AI2 server.
You can implement the ScaleDetector.aix extension as described in part 2 below using the extension test server.
Keep in mind that the extensions mechanism is still unstable and under development.   Any aia files you build in steps (2) and (3) may need to be rebuilt as the system evolves.


Contents
App Inventor does not have multitouch capabilities built in.  Adding multitouch is a popular request, and MIT might eventually include it in the system.   In the meantime, this note illustrates how to use App Inventor extensions to implement a scale detector component that people can use to create apps that react to pinch and zoom gestures.
The note is interesting for two aspects:
  1. For App Inventor users, it provides a functioning ScaleDetector component that can be shared and incorporated into projects.
  2. For App Inventor developers, can serve as a template for creating new App Inventor components that implement other Android gesture detectors.

1. A multitouch demonstration app

ScaleGestureDemo is a simple demonstration of the scale gesture, where two fingers move closer or farther apart to indicate expansion or contraction.   You can download the packaged app from here and play with it.  There’s canvas with a ball in the center.  Pinching with two fingers shrinks the ball and spreading your fingers apart expands it.   Also, tapping the canvas with one finger moves the ball to the location of the tap.


The blocks program, as shown above, uses a ScaleDetector component, whose key feature is a when ScaleDetector.Scale event handler.   In addition to ScaleDetector1, there is Canvas1, which contains a Ball1 sprite, and Label1.
The ScaleDetector1.Scale event handler is called with a number scaleFactor.   When scaleFactor is greater than 1, it indicates that fingers are moving apart.   In this case, the program increases the radius of the ball by 3, up to at most of half the canvas width.  When scaleFactor is less than 1, the fingers are moving closer together, and the program shrinks the size of the ball by 3, down to at least 5.   The program also sets the text of a label to show the current size of the ball.
The other key part of the app is a call when the app starts to the method ScaleDetector.AddHandlerToCanvas.   This tells the scale detector to listen for scale gestures on the indicated canvas.  Observe that the input here is the Canvas1 component itself, obtained from the “component” block at the bottom of the Canvas1 drawer. (The block plugged into the myCanvas slot here must be a Canvas component block, or the app will crash.)
Finally, there’s a Canvas1.Touch event handler that moves the ball when the Canvas is touched (by one finger).   In all, the Canvas is sensitive to two gestures: touch and scale.  Touch is built into the Canvas: the event handler is a block for Canvas1.  Scale is added by the ScaleDetector, and the event handler is a block for ScaleDetector1.
You can use the ScaleDetector extension to create your own multitouch apps that respond to scale gestures.   You’ll need to import the ScaleDetector.aix extension file as described in App Inventor extensions, and then build with the ScaleDetector component, just as with any component.   The ScaleDetector.aix extension is available here:
We’ve also provided the complete aia source for the ScaleGestureDemo app to save you the effort of assembling the blocks from scratch.  If you load this aia file into App Inventor, you will not have also separately install the ScaleDetector.aix extension.  The extension is included in with the source.  In general, project source files include any extensions the project uses.

2. Implementing the ScaleDetector extension

The previous section showed how to create an app using the supplied ScaleDetector extension aix file.  You can also practice implementing the extension itself.
The ScaleDetector extension is implemented as Java code, which is compiled and processed to produce the aix file, as explained in App Inventor extensions.    The Java code file ScaleDetector.java is available here:
This  code for the extension is little more than an interface for the Android SDK’s ScaleGestureDetector and SimpleOnScaleGestureListener classes, which do all the work of actually analyzing the primitive Android motion events.
In our implementation, we create an onScale block for the ScaleDetector component, which takes scaleFactor as a callback parameter, that lets App Inventor users create handlers for the scale event, as shown above in ScaleGestureDemo:
 @SimpleEvent
  public void Scale(double scaleFactor) {
        EventDispatcher.dispatchEvent(this, "Scale", scaleFactor);
  }
We also create an appropriate subclass of SimpleOnScaleGestureListener.  This overrides the default event handling for onScale, to call the block Scale event handler:
 public class MyOnScaleGestureListener extends
                SimpleOnScaleGestureListener {

   //  We override the event handling of the ordinary SimpleOnScaleGestureListener
   // In this case, make the onScale event call the component's Scale event handler, whose
   // behavior can be defined by the When Scale block.
   @Override
   public boolean onScale(ScaleGestureDetector detector) {              
         float scaleFactor = detector.getScaleFactor();
        //  Log.i("Scale", "onScale was signaled, scale factor = " + scaleFactor);
         Scale((double) scaleFactor);
         return true;
   }
 }
Next, we create the new gesture detector class, that extends the SDK ScaleGestureDetector, for adding to the Canvas.   It’s built from a  gesture listener, together with a context where the listening should occur:
 public class ExtensionScaleDetector extends ScaleGestureDetector
             implements Canvas.ExtensionGestureDetector {
   public ExtensionScaleDetector(Context c, OnScaleGestureListener l ) {
         super(c,l);
   }
 }
A key step here is to declare the the class as implements Canvas.ExtensionDetector.   Canvas.ExtensionDetector is an interface provided by Canvas.    Each Canvas has a list of gesture processors that are called when the Canvas is touched.   Classes implementing the ExtensionDetector interface can be added to the Canvas’s list with Canvas.registerCustomGestureDetector.  The only thing implementing the interface requires is that the implementing class provide a method with signature
boolean onTouchEvent(MotionEvent event);        
In our case, this requirement is met automatically by the fact that our ExtensionScaleDetector class extends ScaleGestureDetector.
Finally, we implement the block that adds the gesture detector to the specified Canvas:
  @SimpleFunction
  public void AddHanderToCanvas(Canvas myCanvas) {
        this.myCanvas = myCanvas;
        ExtensionScaleDetector myDetector =
            new ExtensionScaleDetector(myCanvas.getContext(), new MyOnScaleGestureListener());
        myCanvas.registerCustomGestureDetector(myDetector);
  }
The arguments to the constructor for ExtensionScale are the gesture listener implemented above, and the context of the Canvas, which is the context where the listening should happen.
You can build other extensions that respond to other multitouch gestures in a similar manner, provided you can find or create appropriate gesture listeners.

댓글 없음:

댓글 쓰기