StorrBlog

How to create a canvas in NativeScript.

We’re always enthusiastic about new technologies. After all, it’s part of what we do. But, as can be expected, new technology usually presents new challenges in the development stage.

Not too long ago, we started working on a large-scale real-time management project: a B2B system that runs on an Android platforms. We decided to use the vast array of knowledge we’ve acquired in Angular to develop this system using NativeScript.

In order to make sure that NativeScript is the best choice for this project, we created a POC for the main screen. This screen needed to contain different 2D elements that can be dragged, dropped and relocated in a virtual “room”. In other words, we were looking for a canvas. The other screens fit NativeScript pretty well, so we wanted to stick with it.

A quick Google search about canvas in NativeScript revealed that Telerik didn’t implement it (as of this post). Well, someone must have written a plugin that does, right? As it turned out, someone had, but this plugin wasn’t fully implemented yet and didn’t suit our needs.

We had two options: either create a WebView in the app and use the HTML canvas, or find a way to create it ourselves.

The first option felt a bit like cheating, and wasn’t quite, well, native. So that left us with option two. But how could we create our own canvas in NativeScript?

Creating the Canvas

Luckily, Android has a native canvas (as does iOS), and NativeScript allows you to create native Android views using the placeholder tag. Normally, NativeScript creates your native Android views for you, but with the placeholder, we can specify what native Android view we want to create.

<Placeholder (creatingView) = ”createMyView($event)”>

</Placeholder>


Notice the event binding of “creatingView”, which is triggered when NativeScript tries to create the view of placeholder. In the function, we need to create a native Android view and attach it to the view that we get in the event data, like this:

createMyView (args: CreateViewEventData) {

let nativeView = new android.widget.TextView( args.context );


//NativeView now has all of the Android methods and properties so we can do something like this:

nativeView.setText( “Some Text” );

//Now we can attach it to the NativeScript view

args.view = nativeView;

}


Applying the same method, we can create our canvas:

<Placeholder (creatingView) = ”createCanvasView($event)”>

</Placeholder>


createCanvasView( args: CreateViewEventData ) {

//We’re drawing our canvas on an imageview, so that’s going to be our nativeView

let nativeView = new android.widget.ImageView( utils.ad.getApplicationContext() );

//We want the canvas to scale exactly on the imageview. In Android we do this by setting the //scaleType to fitXY. Since NativeScript allows you to use all the native view methods and //properties, it’s easy:

nativeView.setScaleType( android.widget.ImageView.ScaleType.FIT_XY );

//Now, time to create the canvas.

let bitmap = android.graphics.Bitmap.createBitmap( 1000,1000, android.graphics.Bitmap.Config.ARGB_8888 );

let canvas = new android.graphics.Canvas(bitmap);


//At this point we can draw what we need on our canvas. For example, we’ll draw a blue circle with r = 20.

// To do this we also need an Android Paint class instance:

let blueColor = new android.graphics.Paint();

blueColor.setARGB( 255, 0, 0, 255 );

blueColor.setAntiAlias(true);

canvas.drawCircle( 100, 100, 20, blueColor );


//Now we’ll set the canvas to our image.

nativeView.setImageBitmap( bitmap );

//And finally, we’ll attach our native view to the NativeScript view so it shows up in our app.

args.view = this.nativeView;

}


Redrawing is simple. You can do it just like in a native Android app: clear the canvas, call invalidate on the canvas and draw whatever you want. Now our canvas is up and running and feels just like a native canvas.

What about all the NativeScript functionality?

Everything’s still there.

For instance, you can still bind events on the placeholder just like any other NativeScript view, by placing it in the placeholder tag. That way your canvas can be easily interactable, without binding native Android events to it (though sometimes you need to do that — more on that in our next blog post).

For example:

<Placeholder (creatingView) = ”createCanvasView($event)” (touch) = ”onTouch($event)”>

</Placeholder>


onTouch(args: TouchGestureEventData) {

}


Our Conclusion

So, even without a fully implemented plugin, we created a high-performing canvas and didn’t have to sacrifice the advantages of NativeScript, TypeScript and Angular. The process was quick and pretty simple, taking just a bit more work than it would have with an HTML canvas.

In the end, we feel that using NativeScript for this project was a great decision. We quickly created a large-scale system with a custom-made, high-performance and user-friendly canvas. Now, the system is live and about to finish a pilot with real clients.

If you find yourself in a similar situation, creating your own canvas using Android’s own canvas functionality would be a good way to go. Sure, it may look like more work for you, but you will be much happier with the overall result. That extra work may even pay itself off in the long run. But there’s always something new on the horizon, and newer, maybe even quicker solutions to discover!