Read the original article:Creating a Lucky Spin on HarmonyOS
📘 Introduction
Creating interactive and animated components in HarmonyOS can significantly improve user engagement — especially in casual games or reward-based apps. In this article, I’ll walk you through how I built a simple but smooth “Lucky Spin” wheel using HarmonyOS and ArkTS.
We’ll use PieChartModel
from @ohos/mpchart
, basic animation with @ohos.animator
, and some layout tricks to make the UI feel fun and responsive.
📊 What Is the Lucky Spin?
The Lucky Spin is a circular prize wheel divided into segments, each representing a reward like “Smartphone”, “Laptop”, or “VR Headset”. Users tap the Spin button, and the wheel rotates — eventually stopping at a random reward.
It’s often used in games, loyalty apps, or promotional events to increase excitement and give randomized feedback.
🛠️ Step 1: Import Required PieChart Components
Before building the chart, we need to import the necessary classes from the @ohos/mpchart
package.
import {
ColorTemplate,
JArrayList,
MPPointF,
PieChart,
PieChartModel,
PieData,
PieDataSet,
PieEntry
} from '@ohos/mpchart';
-
PieChartModel
: Main logic and data handler for the chart -
PieChart
: The UI component that renders the wheel -
PieEntry
: Represents a single segment of the wheel -
PieDataSet
: A collection of entries with styling -
ColorTemplate
: A set of predefined color palettes -
JArrayList
: Used to build chart entry and color lists -
MPPointF
: Used to define icon/text offsets
🛠️ Step 2: Initialize the Pie Chart
I used PieChartModel
to build the circular wheel. I disabled hole, legend, and touch interaction, so it acts like a static visual chart — only spinning on command.
🎨 Step 3: Set Up Prize Data and Colors
To represent each reward segment, I used PieEntry
objects with equal values, and then styled the chart using colorful slices from ColorTemplate
.
private async setData(range: number): Promise<void> {
let entries: JArrayList<PieEntry> = new JArrayList<PieEntry>();
for (let i = 0; i < this.count; i++) {
entries.add(new PieEntry(range, this.parties[i % this.parties.length]));
}
let dataSet: PieDataSet = new PieDataSet(entries, "Prizes");
dataSet.setSliceSpace(1); // Small gap between slices
dataSet.setIconsOffset(new MPPointF(0, 40)); // Offset for potential icons
dataSet.setSelectionShift(5); // Visual shift on selection
dataSet.setValueTextColor(Color.White); // Value text color
dataSet.setDrawValues(false); // Hide values inside slices
let colors: JArrayList<number> = new JArrayList();
for (let index = 0; index < ColorTemplate.COLORFUL_COLORS.length; index++) {
colors.add(ColorTemplate.COLORFUL_COLORS[index]);
}
colors.add(ColorTemplate.getHoloBlue()); // Add extra color
dataSet.setColorsByList(colors);
let data: PieData = new PieData(dataSet);
this.onePartAngle = 360 / this.count;
this.model.setRotationAngle(-90 - this.onePartAngle / 2); // Align pointer
this.model.setData(data);
}
📌 range
here defines the value given to each slice. Since all rewards are equal, we use the same value for all.
🌀 Step 3: Animate the Wheel Spin
To spin the wheel, I created a startGun()
function that:
- Calculates a randomized angle.
- Adds a large base value (
7200 deg
) to create a satisfying long spin. - Adjusts the final angle to align with the top (pointer).
- Determines which prize segment the pointer stops at.
Here’s the full function:
startGun() {
let currentAngle = this.model.getRotationAngle();
let randomExtraRotation = Math.random() * 360;
let end = 7200 + currentAngle + randomExtraRotation;
let options: AnimatorOptions = {
duration: 8000,
easing: "ease",
delay: 0,
fill: "forwards",
direction: "normal",
begin: currentAngle,
end: end,
iterations: 1
};
this.animatorResult = animator.create(options);
this.animatorResult.onframe = (value) => {
this.model.setRotationAngle(value);
this.model.invalidate();
};
this.animatorResult.onfinish = () => {
const finalRotation = end % 360;
let adjustedAngle = finalRotation - 90;
if (adjustedAngle < 0) adjustedAngle += 360;
let index = Math.floor(adjustedAngle / this.onePartAngle);
this.currentIndex = index;
};
this.animatorResult.play();
}
📌 Note: The -90
correction accounts for the chart’s initial rotation offset, ensuring the pointer correctly lands on the intended segment.
✅ Conclusion
Building a Lucky Spin UI in HarmonyOS is easier than it seems — with just a combination of PieChartModel
and animator
, we can simulate a complete spin wheel experience. From customizing rewards to calculating exact stop angles, the entire flow feels responsive and engaging.
This component can easily be extended with sound effects, haptics, or even backend integration for real prizes.
If you’re building a gamified app or want to boost user engagement, give it a spin! 🎯
📚 References
- https://developer.huawei.com/consumer/en/doc/harmonyos-references/js-service-widget-basic-chart Official guide for using PieChart in HarmonyOS
- https://developer.huawei.com/consumer/en/doc/harmonyos-references/js-apis-animator#animator API documentation for animation features used in spin logic.
- Screenshots and code from personal implementation
Project built and tested using DevEco Studio.
Written by Omer Basri Okcu
Top comments (0)