HarmonyOS NEXT Development Case: Relative Relationship Calculator
This article demonstrates how to build a Relative Relationship Calculator using HarmonyOS NEXT's ArkUI framework. The application allows users to input kinship descriptions (e.g., "father's cousin") and calculates corresponding relational titles based on gender and direction selection. Below is the implementation analysis and code walkthrough. Core Features Kinship Calculation: Utilizes the @nutpi/relationship library for kinship logic. Gender Selection: Toggle between male/female to adjust calculation results. Direction Control: Supports bidirectional relationships ("I call them" ↔ "They call me"). Example/Clear Functions: Predefined examples and input reset capabilities. Key Code Implementation 1. Component Structure & Imports // Import relationship calculation module import relationship from "@nutpi/relationship"; // Import segmented button component and configuration types import { SegmentButton, SegmentButtonItemTuple, SegmentButtonOptions } from '@kit.ArkUI'; @Entry @Component struct RelationshipCalculator { // User-input relationship description (default: "father's cousin") @State private userInputRelation: string = "爸爸的堂弟"; // Theme color (orange) @State private themeColor: string | Color = Color.Orange; // Text/border colors @State private textColor: string = "#2e2e2e"; @State private lineColor: string = "#d5d5d5"; // Base padding size @State private paddingBase: number = 30; // Gender/call method options @State private genderOptions: object[] = [{ text: 'Male' }, { text: 'Female' }]; @State private callMethodOptions: object[] = [{ text: 'I call them' }, { text: 'They call me' }]; // Segmented button configurations @State private genderButtonOptions: SegmentButtonOptions | undefined; @State private callMethodButtonOptions: SegmentButtonOptions | undefined; // Selection indices with watchers @State @Watch('updateSelections') selectedGenderIndex: number[] = [0]; @State @Watch('updateSelections') selectedCallMethodIndex: number[] = [0]; // Input & results @State @Watch('updateSelections') userInput: string = ""; @State calculationResult: string = ""; @State isInputFocused: boolean = false; 2. Calculation Logic // Update results when selections change updateSelections() { const gender = this.selectedGenderIndex[0] === 0 ? 1 : 0; // 1=Male, 0=Female const reverse = this.selectedCallMethodIndex[0] !== 0; // Reverse direction const result: string[] = relationship({ text: this.userInput, reverse: reverse, sex: gender }); this.calculationResult = result?.length > 0 ? `${reverse ? 'Their term for me' : 'My term for them'}: ${result[0]}` : this.userInput ? 'No matching relationship found' : ''; } 3. UI Components build() { Column() { // Title bar Text('Relative Relationship Calculator') .fontColor(this.textColor) .fontSize(18) .width('100%') .height(50) .textAlign(TextAlign.Center) .backgroundColor(Color.White) .shadow({ radius: 2, color: this.lineColor, offsetY: 5 }); // Settings panel Column() { // Gender selection Row() { Text('My Gender').fontColor(this.textColor).fontSize(18); SegmentButton({ options: this.genderButtonOptions, selectedIndexes: this.selectedGenderIndex }).width('400lpx'); }.justifyContent(FlexAlign.SpaceBetween); // Call direction selection Row() { Text('Direction').fontColor(this.textColor).fontSize(18); SegmentButton({ options: this.callMethodButtonOptions, selectedIndexes: this.selectedCallMethodIndex }).width('400lpx'); }.justifyContent(FlexAlign.SpaceBetween); // Example/Clear buttons Row() { Text('Example') .style({ color: "#5871ce", backgroundColor: "#f2f1fd" }) .onClick(() => this.userInput = this.userInputRelation); Blank(); Text('Clear') .style({ color: "#e48742", backgroundColor: "#ffefe6" }) .onClick(() => this.userInput = ""); }.height(45); // Input field TextInput({ text: $$this.userInput, placeholder: !this.isInputFocused ? `Input term (e.g., ${this.userInputRelation})` : '' }) .style({ borderColor: this.isInputFocused ? this.themeColor : Color.Gray, caretColor: this.themeColor }) .onFocusChange((focused) => this.isInputFocused = focused); } .cardStyle(this.paddingBase); // Custom card styling // Result display Column() { Text(this.calculationResult).fontSize(18); }.visibility(this.calculationResult ? Visibility.Visible : Visibility.None) .cardStyle(this.paddingBase); } .fullScreenStyle("#f4f8fb"); // Full-screen background } Technical Highlights Reactive State Management: @State and @Watch decorator

This article demonstrates how to build a Relative Relationship Calculator using HarmonyOS NEXT's ArkUI framework. The application allows users to input kinship descriptions (e.g., "father's cousin") and calculates corresponding relational titles based on gender and direction selection. Below is the implementation analysis and code walkthrough.
Core Features
-
Kinship Calculation: Utilizes the
@nutpi/relationship
library for kinship logic. - Gender Selection: Toggle between male/female to adjust calculation results.
- Direction Control: Supports bidirectional relationships ("I call them" ↔ "They call me").
- Example/Clear Functions: Predefined examples and input reset capabilities.
Key Code Implementation
1. Component Structure & Imports
// Import relationship calculation module
import relationship from "@nutpi/relationship";
// Import segmented button component and configuration types
import { SegmentButton, SegmentButtonItemTuple, SegmentButtonOptions } from '@kit.ArkUI';
@Entry
@Component
struct RelationshipCalculator {
// User-input relationship description (default: "father's cousin")
@State private userInputRelation: string = "爸爸的堂弟";
// Theme color (orange)
@State private themeColor: string | Color = Color.Orange;
// Text/border colors
@State private textColor: string = "#2e2e2e";
@State private lineColor: string = "#d5d5d5";
// Base padding size
@State private paddingBase: number = 30;
// Gender/call method options
@State private genderOptions: object[] = [{ text: 'Male' }, { text: 'Female' }];
@State private callMethodOptions: object[] = [{ text: 'I call them' }, { text: 'They call me' }];
// Segmented button configurations
@State private genderButtonOptions: SegmentButtonOptions | undefined;
@State private callMethodButtonOptions: SegmentButtonOptions | undefined;
// Selection indices with watchers
@State @Watch('updateSelections') selectedGenderIndex: number[] = [0];
@State @Watch('updateSelections') selectedCallMethodIndex: number[] = [0];
// Input & results
@State @Watch('updateSelections') userInput: string = "";
@State calculationResult: string = "";
@State isInputFocused: boolean = false;
2. Calculation Logic
// Update results when selections change
updateSelections() {
const gender = this.selectedGenderIndex[0] === 0 ? 1 : 0; // 1=Male, 0=Female
const reverse = this.selectedCallMethodIndex[0] !== 0; // Reverse direction
const result: string[] = relationship({
text: this.userInput,
reverse: reverse,
sex: gender
});
this.calculationResult = result?.length > 0
? `${reverse ? 'Their term for me' : 'My term for them'}: ${result[0]}`
: this.userInput ? 'No matching relationship found' : '';
}
3. UI Components
build() {
Column() {
// Title bar
Text('Relative Relationship Calculator')
.fontColor(this.textColor)
.fontSize(18)
.width('100%')
.height(50)
.textAlign(TextAlign.Center)
.backgroundColor(Color.White)
.shadow({ radius: 2, color: this.lineColor, offsetY: 5 });
// Settings panel
Column() {
// Gender selection
Row() {
Text('My Gender').fontColor(this.textColor).fontSize(18);
SegmentButton({
options: this.genderButtonOptions,
selectedIndexes: this.selectedGenderIndex
}).width('400lpx');
}.justifyContent(FlexAlign.SpaceBetween);
// Call direction selection
Row() {
Text('Direction').fontColor(this.textColor).fontSize(18);
SegmentButton({
options: this.callMethodButtonOptions,
selectedIndexes: this.selectedCallMethodIndex
}).width('400lpx');
}.justifyContent(FlexAlign.SpaceBetween);
// Example/Clear buttons
Row() {
Text('Example')
.style({ color: "#5871ce", backgroundColor: "#f2f1fd" })
.onClick(() => this.userInput = this.userInputRelation);
Blank();
Text('Clear')
.style({ color: "#e48742", backgroundColor: "#ffefe6" })
.onClick(() => this.userInput = "");
}.height(45);
// Input field
TextInput({
text: $$this.userInput,
placeholder: !this.isInputFocused ? `Input term (e.g., ${this.userInputRelation})` : ''
})
.style({
borderColor: this.isInputFocused ? this.themeColor : Color.Gray,
caretColor: this.themeColor
})
.onFocusChange((focused) => this.isInputFocused = focused);
}
.cardStyle(this.paddingBase); // Custom card styling
// Result display
Column() {
Text(this.calculationResult).fontSize(18);
}.visibility(this.calculationResult ? Visibility.Visible : Visibility.None)
.cardStyle(this.paddingBase);
}
.fullScreenStyle("#f4f8fb"); // Full-screen background
}
Technical Highlights
-
Reactive State Management:
-
@State
and@Watch
decorators enable automatic UI updates. - Bidirectional data binding via
$$this.userInput
.
-
-
Customizable UI Components:
-
SegmentButton
with capsule styling for option selection. - Shadow effects and rounded corners for modern aesthetics.
-
-
Cross-Device Adaptation:
- Uses responsive units (
lpx
) for layout scaling. - Focus state management for input fields.
- Uses responsive units (
Conclusion
This implementation showcases HarmonyOS NEXT's capabilities in building responsive, data-driven applications. Key strengths include clean state management and modular component design. Future enhancements could integrate voice input or expanded kinship databases.
Complete code available on [GitHub Repository Link].
Note: Requires @nutpi/relationship
v1.2.0+ and HarmonyOS SDK 4.0+.