HarmonyOS NEXT Development Case: Random Number Generator

This article demonstrates a random number generator implementation using ArkUI in HarmonyOS NEXT. The application allows users to define number ranges, specify quantity, choose uniqueness, and copy results to clipboard. // Import clipboard service module for copy functionality import { pasteboard } from '@kit.BasicServicesKit'; // Import prompt service for user feedback import { promptAction } from '@kit.ArkUI'; // Define main entry component using decorator @Entry @Component struct RandomNumberGenerator { // Base spacing for layout configuration @State private baseSpacing: number = 30; // Generated random numbers string @State private generatedNumbers: string = ''; // Primary theme color @State private primaryColor: string = '#fea024'; // Text color @State private fontColor: string = "#2e2e2e"; // Input focus states @State private isFocusStart: boolean = false; @State private isFocusEnd: boolean = false; @State private isFocusCount: boolean = false; // Allow duplicate numbers flag @State private isUnique: boolean = true; // Range boundaries and count @State private startValue: number = 0; @State private endValue: number = 0; @State private countValue: number = 0; // Generate random numbers based on parameters private generateRandomNumbers(): void { const startValue = this.startValue; const endValue = this.endValue; const countValue = this.countValue; const range: number = endValue - startValue + 1; const generatedNumbers = new Set(); const tempArray: number[] = []; if (!this.isUnique) { if (countValue > range) { this.getUIContext().showAlertDialog({ title: 'Error', message: `Requested count exceeds available numbers in range`, confirm: { defaultFocus: true, value: 'OK', fontColor: Color.White, backgroundColor: this.primaryColor, action: () => {} }, onWillDismiss: () => {}, alignment: DialogAlignment.Center, }); return; } for (let i = 0; i this.isFocusStart = false) .onFocus(() => this.isFocusStart = true) .onChange((value: string) => this.startValue = Number(value)); Line().width(10) TextInput({ placeholder: 'End(

May 11, 2025 - 04:26
 0
HarmonyOS NEXT Development Case: Random Number Generator

Image description
This article demonstrates a random number generator implementation using ArkUI in HarmonyOS NEXT. The application allows users to define number ranges, specify quantity, choose uniqueness, and copy results to clipboard.

// Import clipboard service module for copy functionality
import { pasteboard } from '@kit.BasicServicesKit';
// Import prompt service for user feedback
import { promptAction } from '@kit.ArkUI';

// Define main entry component using decorator
@Entry
@Component
struct RandomNumberGenerator {
  // Base spacing for layout configuration
  @State private baseSpacing: number = 30;
  // Generated random numbers string
  @State private generatedNumbers: string = '';
  // Primary theme color
  @State private primaryColor: string = '#fea024';
  // Text color
  @State private fontColor: string = "#2e2e2e";
  // Input focus states
  @State private isFocusStart: boolean = false;
  @State private isFocusEnd: boolean = false;
  @State private isFocusCount: boolean = false;
  // Allow duplicate numbers flag
  @State private isUnique: boolean = true;
  // Range boundaries and count
  @State private startValue: number = 0;
  @State private endValue: number = 0;
  @State private countValue: number = 0;

  // Generate random numbers based on parameters
  private generateRandomNumbers(): void {
    const startValue = this.startValue;
    const endValue = this.endValue;
    const countValue = this.countValue;
    const range: number = endValue - startValue + 1;

    const generatedNumbers = new Set<number>();
    const tempArray: number[] = [];

    if (!this.isUnique) {
      if (countValue > range) {
        this.getUIContext().showAlertDialog({
          title: 'Error',
          message: `Requested count exceeds available numbers in range`,
          confirm: {
            defaultFocus: true,
            value: 'OK',
            fontColor: Color.White,
            backgroundColor: this.primaryColor,
            action: () => {}
          },
          onWillDismiss: () => {},
          alignment: DialogAlignment.Center,
        });
        return;
      }

      for (let i = 0; i < countValue; i++) {
        let randomIndex = Math.floor(Math.random() * (range - i));
        let randomNum = tempArray[randomIndex] ?? startValue + randomIndex;
        generatedNumbers.add(randomNum);
        if (tempArray[range - 1 - i] === undefined) {
          tempArray[range - 1 - i] = startValue + range - 1 - i;
        }
        tempArray[randomIndex] = tempArray[range - 1 - i];
      }
      this.generatedNumbers = JSON.stringify(Array.from(generatedNumbers));
    } else {
      for (let i = 0; i < this.countValue; i++) {
        let randomNumber = startValue + Math.floor(Math.random() * (endValue - startValue));
        tempArray.push(randomNumber);
      }
      this.generatedNumbers = JSON.stringify(tempArray);
    }
  }

  // Copy text to system clipboard
  private copyToClipboard(text: string): void {
    const pasteboardData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, text);
    const systemPasteboard = pasteboard.getSystemPasteboard();
    systemPasteboard.setData(pasteboardData);
    promptAction.showToast({ message: 'Copied to clipboard' });
  }

  // UI layout construction
  build() {
    Column() {
      // Header section
      Text("Random Number Generator")
        .width('100%')
        .height(54)
        .fontSize(18)
        .fontWeight(600)
        .backgroundColor(Color.White)
        .textAlign(TextAlign.Center)
        .fontColor(this.fontColor);

      // Configuration panel
      Column() {
        // Range input section
        Row() {
          Text(`Number Range`)
            .fontWeight(600)
            .fontSize(18)
            .fontColor(this.fontColor);
        }
        .margin({ top: `${this.baseSpacing}lpx`, left: `${this.baseSpacing}lpx` });

        // Range input fields
        Row() {
          TextInput({ placeholder: 'Start(>=)' })
            .layoutWeight(1)
            .type(InputType.Number)
            .placeholderColor(this.isFocusStart ? this.primaryColor : Color.Gray)
            .fontColor(this.isFocusStart ? this.primaryColor : this.fontColor)
            .borderColor(this.isFocusStart ? this.primaryColor : Color.Gray)
            .borderWidth(1)
            .borderRadius(10)
            .backgroundColor(Color.White)
            .showUnderline(false)
            .onBlur(() => this.isFocusStart = false)
            .onFocus(() => this.isFocusStart = true)
            .onChange((value: string) => this.startValue = Number(value));

          Line().width(10)

          TextInput({ placeholder: 'End(<=)' })
            .layoutWeight(1)
            .type(InputType.Number)
            .placeholderColor(this.isFocusEnd ? this.primaryColor : Color.Gray)
            .fontColor(this.isFocusEnd ? this.primaryColor : this.fontColor)
            .borderColor(this.isFocusEnd ? this.primaryColor : Color.Gray)
            .borderWidth(1)
            .borderRadius(10)
            .backgroundColor(Color.White)
            .showUnderline(false)
            .onBlur(() => this.isFocusEnd = false)
            .onFocus(() => this.isFocusEnd = true)
            .onChange((value: string) => this.endValue = Number(value));
        }
        .margin({ left: `${this.baseSpacing}lpx`, right: `${this.baseSpacing}lpx`, top: `${this.baseSpacing}lpx` });

        // Count input section
        Text('Quantity')
          .fontWeight(600)
          .fontSize(18)
          .fontColor(this.fontColor)
          .margin({ left: `${this.baseSpacing}lpx`, top: `${this.baseSpacing}lpx` });

        Row() {
          TextInput({ placeholder: '' })
            .layoutWeight(1)
            .type(InputType.Number)
            .placeholderColor(this.isFocusCount ? this.primaryColor : Color.Gray)
            .fontColor(this.isFocusCount ? this.primaryColor : this.fontColor)
            .borderColor(this.isFocusCount ? this.primaryColor : Color.Gray)
            .borderWidth(1)
            .borderRadius(10)
            .backgroundColor(Color.White)
            .showUnderline(false)
            .onBlur(() => this.isFocusCount = false)
            .onFocus(() => this.isFocusCount = true)
            .onChange((value: string) => this.countValue = Number(value));
        }
        .margin({ left: `${this.baseSpacing}lpx`, right: `${this.baseSpacing}lpx`, top: `${this.baseSpacing}lpx` });

        // Uniqueness toggle
        Row() {
          Text('Allow duplicates')
            .fontWeight(400)
            .fontSize(16)
            .fontColor(this.fontColor)
            .layoutWeight(1);

          Toggle({ type: ToggleType.Checkbox, isOn: this.isUnique })
            .width('100lpx')
            .height('50lpx')
            .borderColor(Color.Gray)
            .selectedColor(this.primaryColor)
            .onChange((isOn: boolean) => this.isUnique = isOn)
            .align(Alignment.End);
        }
        .margin({ top: `${this.baseSpacing}lpx` })
        .width('100%')
        .padding({ left: `${this.baseSpacing}lpx`, right: `${this.baseSpacing}lpx`, top: `${this.baseSpacing / 3}lpx` })
        .hitTestBehavior(HitTestMode.Block)
        .onClick(() => this.isUnique = !this.isUnique);

        // Generate button
        Text('Generate')
          .fontColor(Color.White)
          .backgroundColor(this.primaryColor)
          .height(54)
          .textAlign(TextAlign.Center)
          .borderRadius(10)
          .fontSize(18)
          .width(`${650 - this.baseSpacing * 2}lpx`)
          .margin({
            top: `${this.baseSpacing}lpx`,
            left: `${this.baseSpacing}lpx`,
            right: `${this.baseSpacing}lpx`,
            bottom: `${this.baseSpacing}lpx`
          })
          .clickEffect({ level: ClickEffectLevel.HEAVY, scale: 0.8 })
          .onClick(() => this.generateRandomNumbers());
      }
      .width('650lpx')
      .margin({ top: 20 })
      .backgroundColor(Color.White)
      .borderRadius(10)
      .alignItems(HorizontalAlign.Start);

      // Results display
      Column() {
        Text(`Generated Numbers:`)
          .fontWeight(600)
          .fontSize(18)
          .fontColor(this.fontColor)
          .margin({ top: `${this.baseSpacing}lpx`, left: `${this.baseSpacing}lpx` });

        Text(`${this.generatedNumbers}`)
          .width('650lpx')
          .fontColor(this.primaryColor)
          .fontSize(18)
          .textAlign(TextAlign.Center)
          .padding({ left: 5, right: 5 })
          .margin({ top: `${this.baseSpacing / 3}lpx` });

        // Copy button
        Text('Copy')
          .enabled(!!this.generatedNumbers)
          .fontColor(Color.White)
          .backgroundColor(this.primaryColor)
          .height(54)
          .textAlign(TextAlign.Center)
          .borderRadius(10)
          .fontSize(18)
          .width(`${650 - this.baseSpacing * 2}lpx`)
          .margin({
            top: `${this.baseSpacing}lpx`,
            left: `${this.baseSpacing}lpx`,
            right: `${this.baseSpacing}lpx`,
            bottom: `${this.baseSpacing}lpx`
          })
          .clickEffect({ level: ClickEffectLevel.HEAVY, scale: 0.8 })
          .onClick(() => this.copyToClipboard(this.generatedNumbers));
      }
      .width('650lpx')
      .backgroundColor(Color.White)
      .borderRadius(10)
      .margin({ top: `${this.baseSpacing}lpx` })
      .alignItems(HorizontalAlign.Start);
    }
    .height('100%')
    .width('100%')
    .backgroundColor("#f2f3f5");
  }
}

Key Technical Points:

  1. State Management:

    • Uses @State decorators for reactive UI updates
    • Manages input focus states for better UX
  2. Random Generation Algorithm:

    • Implements Fisher-Yates shuffle for unique numbers
    • Handles range validation and error alerts
  3. UI Components:

    • Uses ArkUI's declarative syntax for layout
    • Implements responsive input fields with visual feedback
  4. System Integration:

    • Clipboard integration via pasteboard service
    • Toast notifications using promptAction

Features:

  • Configurable number range and quantity
  • Duplicate number prevention
  • One-click copy functionality
  • Responsive input validation
  • Visual feedback for user actions

This implementation demonstrates HarmonyOS NEXT's capabilities in building interactive applications with clean architecture and good user experience.