Skip to content

Theming

Apps customize their look by assigning the process-wide Theme color fields in Application.onCreate and by attaching GradientDrawable backgrounds to individual views. There are no XML styles or themes (style=, ?attr/…): the palette is configured in Java and applied imperatively. Individual colours can still live in res/values and be used from layouts and code — see resources.

Setting the global theme

Theme is a holder of public static int color fields. Assign them before any UI is built — typically the first thing in Application.onCreate:

import picodroid.app.Application;
import picodroid.graphics.Color;
import picodroid.graphics.Theme;
public final class MyApp extends Application {
@Override
public void onCreate() {
Theme.colorPrimary = Color.rgb(0x6b, 0x4e, 0xc5);
Theme.colorBackground = Color.rgb(0x0e, 0x0e, 0x14);
Theme.colorSurface = Color.rgb(0x1a, 0x1a, 0x24);
Theme.colorText = Color.WHITE;
Theme.colorTextSecondary = Color.rgb(0xc8, 0xb8, 0xee);
Theme.colorOutline = Color.rgb(0x44, 0x44, 0x55);
Theme.colorOnPrimary = Color.WHITE;
startActivity(new picodroid.content.Intent(MyActivity.class));
}
}

The palette is process-global — static fields, not per-Activity; one app runs at a time — and is read when a view is built, so a later assignment does not repaint what is already on screen. Views don’t cascade automatically — a view applies a theme color explicitly, e.g. view.setBackgroundColor(Theme.colorBackground) or label.setTextColor(Theme.colorPrimary). The widgets that read the palette themselves are the progress indicators: an indeterminate ProgressBar spins in colorPrimary, and a CircularProgressIndicator draws its indicator in colorPrimary over a colorOutline track, until a tint says otherwise.

Theme color fields

FieldWhat it is for
colorPrimaryPrimary accent: button fill, focused outlines, slider track.
colorBackgroundPage background.
colorSurfaceCard / surface background, slightly lighter than colorBackground.
colorTextPrimary body text.
colorTextSecondarySecondary, muted text.
colorOutlineSubtle separators and divider lines.
colorOnPrimaryText and icons on top of colorPrimary (e.g. a button label).

The fields ship with sensible dark-palette defaults; apps that don’t reassign them get those defaults.

Per-widget styling: GradientDrawable

LinearLayout, FrameLayout and RadioGroup are flat, as on Android: no background, border, corner radius or padding until you set one. So a card’s look is yours to give. For a plain fill setBackgroundColor is enough, and it honours the colour’s alpha (Color.TRANSPARENT clears a background). For anything else (rounded cards, gradients, stroked borders), build a GradientDrawable and attach it as the view’s background:

import picodroid.graphics.Color;
import picodroid.graphics.drawable.GradientDrawable;
GradientDrawable bg = new GradientDrawable();
bg.setColor(Color.rgb(0x1a, 0x1a, 0x24));
bg.setCornerRadius(12);
bg.setStroke(2, Color.rgb(0x44, 0x44, 0x55)); // 2 px outline
card.setBackground(bg);

Two-color gradients — there is no gradient constructor; start from new GradientDrawable() and call setGradient(startColor, endColor, orientation) (the setters return the drawable so they chain):

GradientDrawable g = new GradientDrawable()
.setGradient(Color.rgb(0x6b, 0x4e, 0xc5),
Color.rgb(0x2e, 0x1a, 0x4a),
GradientDrawable.Orientation.TOP_BOTTOM)
.setCornerRadius(8);
header.setBackground(g);

Orientation has just two constants: TOP_BOTTOM (1) and LEFT_RIGHT (2). Other angles and radial gradients are not supported.

Text size

TextView.setTextSize(float) (and android:textSize in a layout) picks the size of a label’s or a button’s text. The faces are bitmaps compiled into the firmware, so the size snaps to the nearest one the board has — 14, 20, 28 and 64 px on the RP2350 boards, 14 alone on testbench_rp2040 — a tie going to the larger; getLineHeight() reports the face in use. There is one typeface (Montserrat) and no bold or italic: textStyle and fontFamily are dropped from a layout with a build warning. The sizes above 14 are ASCII plus ° and •.

title.setTextSize(28);
caption.setTextColor(Theme.colorTextSecondary);

Worked example

The displaydemo widget sampler ends with a themed-widgets section that walks the full palette + gradient pipeline (top-to-bottom gradient header, left-to-right gradient bar, surface card, pill / ghost buttons). See examples/displaydemo/.

examples/picoenvmon/ is a more realistic application — it customizes the global theme in Application.onCreate and uses gradients sparingly for mood. See examples/picoenvmon/.