a PaintCode - Android

Android

PaintCode generates drawing code for that you can use in your Android app development.

PaintCode produces methods that use android.graphics API to draw 2D graphics on provided canvas (android.graphics.Canvas).

So for example for this House Icon drawing:

Drawing of House Icon in PaintCodeDrawing of House Icon in PaintCode

following code will be generated:

void drawHouseIcon(Canvas canvas) {
    // General Declarations
    Paint paint;
    
    // Local Colors
    int houseIconColor = Color.argb(255, 0, 149, 233);
    
    // Bezier
    RectF bezierRect = new RectF(2f, 1.5f, 28f, 28f);
    Path bezierPath = new Path();
    bezierPath.moveTo(18f, 18f);
    bezierPath.lineTo(12f, 18f);
    ...
    bezierPath.lineTo(21f, 8f);
    bezierPath.close();
    
    paint = new Paint();
    paint.setStyle(Paint.Style.FILL);
    paint.setColor(houseIconColor);
    canvas.drawPath(bezierPath, paint);
}

This is useful in various situations. One of them is implementing custom subclass of View class. In order to make the custom view draw the house icon, you can paste the method into the new View subclass and override onDraw like this:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    drawHouseIcon(canvas);
}

StyleKit

Copying and pasting code from PaintCode into your Android project is fine for small experiments, but actually isn't that effective. For any project, where you need fast turnaround between design and implementation another approach is recommended.

PaintCode generates special Java class, we call it StyleKit. It contains all the drawing methods (some in multiple forms) and also collection of colors, gradients, shadows and images that you may also use in your Android project.

When you switch to StyleKit tab for the first time, you need to fill in Name and Package in Inspector:

Inspector with StyleKit settingsInspector with StyleKit settings

Package name will be used in header of the class and it'll also specify the correct folder into which the class will be saved within your Android project. Let's say your StyleKit is called HouseStyleKit and your package is com.example.house_package.

Click export and set main source directory.

<Android Project>/app/src/main

PaintCode will create the folder structure for the package, so it will save your class as:

<Android Project>/app/src/main/com/example/house_package/HouseStyleKit.java

If your StyleKit uses raster images, they will also get exported into folders according to their pixel density.

<Android Project>/app/src/main/res/drawable-mdpi
<Android Project>/app/src/main/res/drawable-xhdpi
<Android Project>/app/src/main/res/drawable-xxhdpi

Note that you only need to select the correct path once. After that whenever you hit Main Menu → File → Export Again (⌘R), your class and raster images will get updated. That's also a reason why you shouldn't change the generated resources manually. The changes will be lost after every re-export.

StyleKit makes the integration turnaround a matter of seconds. After changes are made in PaintCode file, simply hit ⌘R in PaintCode, then ⌘R in Android Studio and there it is — the updated design on the testing device.

The only change to previous usage example is the location of the drawHouseIcon method.

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    HouseStyleKit.drawHouseIcon(canvas);
}

Parametric drawing

When your drawing is parametric (uses Variables, Frames, parametric colors, etc) the method signature contains more attributes, the method signature contains more parameters.

public void drawHouseIcon(Canvas canvas, int iconColor) {
   ...
}

Custom view with attributes

The custom view can improved so that its attributes can be changed in your layout. If the custom view is called HouseView, following file has to be edited:

<Android Project>/app/src/main/res/values/attrs_house_view.xml

to contain an attribute (let's call it fillColor):

<resources>
    <declare-styleable name="HouseView">
        <attr name="fillColor" format="color" />
    </declare-styleable>
</resources>

Lastly implementation of the custom view has to be updated so that the attribute gets loaded during initialization:

public class HouseView extends View {
    private int mFillColor = Color.RED;

    public HouseView(Context context) {
        super(context);
        init(null, 0);
    }

    public HouseView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs, 0);
    }

    public HouseView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(attrs, defStyle);
    }

    private void init(AttributeSet attrs, int defStyle) {
        // Load attributes
        final TypedArray a = getContext().obtainStyledAttributes(
                attrs, R.styleable.HouseView, defStyle, 0);

        mFillColor = a.getColor(
                R.styleable.HouseView_fillColor,
                mFillColor);

        a.recycle();
    }
    
    ...
}

From now on the custom view has new attribute fillColor that can be used in layout like this:

    <view
        class="com.pixelcut.houseproject.HouseView"
        android:id="@+id/view"
        app:fillColor="@color/colorPrimary"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

Also available in the Design tab

Custom attribute in Layout in Android StudioCustom attribute in Layout in Android Studio

Type of Layer

Views are rendered using hardware layer type by default. This type may be faster in some instances, but it doesn't support blur (used in shadows) and scaling. So in order to make the rendering accurate you need to change the layerType property to software.

Layer Type setting in Android StudioLayer Type setting in Android Studio

Context

If you use custom fonts or raster images, StyleKit needs a to refer to the files. In both cases it needs an instance of Context class. In order to provide it, you need to set static property called context. For example during initialization of your activity.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    HouseStyleKit.context = getApplicationContext();
}

Scale

There are two approaches to scaling. You can use resizing drawing methods. Resizing variant of drawing method is the same drawing method, but it has two more arguments: target rectangle (of type RectF) and resizing behavior. ResizingBehavior is an enum type defined in StyleKit. The values are:

This is an example of usage of such method on parametric drawHouseIcon method:

HouseStyleKit.drawHouseIcon(canvas,
    targetRectangle,
    HouseStyleKit.ResizingBehavior.AspectFit,
    Color.BLUE);

If you just want to take display pixel density of the device into account, you can scale the canvas before calling the drawing method:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    float displayDensity = getResources().getDisplayMetrics().density;
    canvas.scale(displayDensity, displayDensity);

    HouseStyleKit.drawHouseIcon(canvas);
}

Vector drawables

Vector drawables are considered to be images similarly to SVGs. Please check Image Export section.