Making of Pomodoro: Native Components
Last time we took a look at different methods which could be used for drawing vector graphics on Android with React Native. In our case, the best solution turned out to be using the native Android Canvas. This post will cover the details of building a custom native component.
In this blogpost, we will write a simple Java class whose sole purpose will be to draw two arcs of a selected size, width and colour. We will then show how such native code can be integrated into React Native.
For the sake of clarity, import and package declarations have been omitted from all the code snippets.
#1 Create Java class
Let’s start with the most essential thing — the actual implementation of the arc drawing class.
The component consists of a FrameLayout wrapped around an ImageView element, which in turn displays a bitmap with a circle made of two arcs. The rendering of the vector paths is done using Android Canvas. We need to adjust the bitmap resolution for device screen density to give it a nice look.
The CanvasView class could already be used in Java applications, but we still need a few steps to expose it as a component in React Native. These involve creating a manager class, registering it as a package and loading it in the application’s main activity.
#2 Create a Manager
The new “manager” class is meant to behave as a bridge between React and CanvasView class — its main use is to create the view component and provide appropriately annotated setter functions for all the props (marked using @ReactProp annotation).
While most of this code is pretty straightforward, we needed to cover one extra aspect here: calling the drawArc() method. To ensure that the arc represents the actual state of the timer, this function needs the values of all the props that can be passed to the component, so we can’t just toss it in the CanvasView constructor.
While RN Guides don’t really cover this topic, we figured out that there is a method called onAfterUpdateTransaction(), which is called after all the props have been set. It thus seems to be a good place for calling our drawing function.
#3 Build a Package
We now need to wrap this whole thing into a package, which, if necessary, could include up a couple of managers for different components. Again, the original documentation turns out to be a bit sparse and pays no respect to the return values of a few abstract functions that must be implemented before we can get our component up and running. Fortunately, some StackOverflow + Github issues search reveals that returning empty lists of proper type basically does the trick :).
Now let’s ask the main activity to load our package:
#4 Add React Native Integration
Our component is up and loaded, but we still need to tell the Javascript layer how it’s meant to be used. We do this by calling requireNativeComponent() and creating a React Native interface which specifies the component’s name, as well as required props and their types.
Time to include the new component in our application!
<CanvasView
angle={360.0 * this.props.percent}
frontColor={'#D20022'}
doneColor={'#FF0032'}
strokeWidth={20}
height={320}
width={32}
/>
That’s it! We now have a working custom component, which we can use in our React Native applications :)
Liked the post? Follow me or Brains&Beards on Medium :).