DEV Community

Cover image for HarmonyOS NEXT Development Case: Blood Type Inheritance Calculator
zhongcx
zhongcx

Posted on

HarmonyOS NEXT Development Case: Blood Type Inheritance Calculator

Image description

The following code demonstrates how to implement a blood type inheritance calculator using ArkUI in HarmonyOS NEXT. This application allows users to select parental blood types and calculates possible/prohibited blood types for their offspring based on genetic principles.


Full Code with English Comments

// Import SegmentButton and related type definitions  
import { SegmentButton, SegmentButtonItemTuple, SegmentButtonOptions } from '@kit.ArkUI';  

// Mark the component as the entry point using the @Entry decorator  
@Entry  
// Define a component using the @Component decorator  
@Component  
// BloodTypeCalculator struct implements blood type inheritance calculation  
struct BloodTypeCalculator {  
  // Theme color (default: Orange)  
  @State private themeColor: string | Color = Color.Orange;  
  // Text color (default: dark gray)  
  @State private textColor: string = "#2e2e2e";  
  // Border color (default: light gray)  
  @State private lineColor: string = "#d5d5d5";  
  // Base padding size (default: 30)  
  @State private basePadding: number = 30;  
  // Possible blood type results  
  @State private possibleBloodTypesText: string = "";  
  // Impossible blood type results  
  @State private impossibleBloodTypesText: string = "";  
  // Blood type list: A, B, AB, O  
  @State private bloodTypeList: object[] = [  
    Object({ text: 'A' }),  
    Object({ text: 'B' }),  
    Object({ text: 'AB' }),  
    Object({ text: 'O' })  
  ];  
  // Capsule button configuration for single selection  
  @State singleSelectCapsuleOptions: SegmentButtonOptions | undefined = undefined;  
  // Track father's blood type selection  
  @State @Watch('capsuleSelectedIndexesChanged') fatherBloodTypeIndex: number[] = [0];  
  // Track mother's blood type selection  
  @State @Watch('capsuleSelectedIndexesChanged') motherBloodTypeIndex: number[] = [0];  

  // Get possible gene combinations for a blood type  
  getGenes(bloodType: string): string[] {  
    console.info(`bloodType:${bloodType}`);  
    switch (bloodType) {  
      case 'A': return ['A', 'O']; // Possible genes for type A  
      case 'B': return ['B', 'O']; // Possible genes for type B  
      case 'AB': return ['A', 'B']; // Possible genes for type AB  
      case 'O': return ['O']; // Possible genes for type O  
      default: throw new Error('Invalid blood type');  
    }  
  }  

  // Combine parental genes to find possible offspring combinations  
  combineGenes(fatherGenes: string[], motherGenes: string[]): string[] {  
    const possibleGenes: string[] = [];  
    for (const fatherGene of fatherGenes) {  
      for (const motherGene of motherGenes) {  
        const combinedGene = [fatherGene, motherGene].sort().join('');  
        if (!possibleGenes.includes(combinedGene)) {  
          possibleGenes.push(combinedGene);  
        }  
      }  
    }  
    return possibleGenes;  
  }  

  // Convert gene combinations to blood types  
  getBloodTypesFromGenes(genes: string[]): string[] {  
    const bloodTypes: string[] = [];  
    for (const gene of genes) {  
      if (gene === 'AA' || gene === 'AO' || gene === 'OA') {  
        bloodTypes.push('A');  
      } else if (gene === 'BB' || gene === 'BO' || gene === 'OB') {  
        bloodTypes.push('B');  
      } else if (gene === 'AB' || gene === 'BA') {  
        bloodTypes.push('AB');  
      } else if (gene === 'OO') {  
        bloodTypes.push('O');  
      }  
    }  
    return [...new Set(bloodTypes)]; // Remove duplicates  
  }  

  // Calculate possible/impossible blood types  
  calculatePossibleBloodTypes(father: string, mother: string) {  
    const fatherGenes = this.getGenes(father);  
    const motherGenes = this.getGenes(mother);  
    const possibleGenes = this.combineGenes(fatherGenes, motherGenes);  
    const possibleBloodTypes = this.getBloodTypesFromGenes(possibleGenes);  
    const impossibleBloodTypes = ['A', 'B', 'AB', 'O']  
      .filter(bt => !possibleBloodTypes.includes(bt));  
    this.possibleBloodTypesText = `Possible: ${possibleBloodTypes.join(', ')}`;  
    this.impossibleBloodTypesText = `Impossible: ${impossibleBloodTypes.join(', ')}`;  
  }  

  // Handle segment button selection changes  
  capsuleSelectedIndexesChanged() {  
    const father = this.bloodTypeList[this.fatherBloodTypeIndex[0]]['text'];  
    const mother = this.bloodTypeList[this.motherBloodTypeIndex[0]]['text'];  
    this.calculatePossibleBloodTypes(father, mother);  
  }  

  // Initialize UI when component appears  
  aboutToAppear(): void {  
    this.singleSelectCapsuleOptions = SegmentButtonOptions.capsule({  
      buttons: this.bloodTypeList as SegmentButtonItemTuple,  
      multiply: false, // Single selection mode  
      fontColor: Color.White,  
      selectedFontColor: Color.White,  
      selectedBackgroundColor: this.themeColor,  
      backgroundColor: this.lineColor,  
      backgroundBlurStyle: BlurStyle.BACKGROUND_THICK  
    });  
    this.capsuleSelectedIndexesChanged();  
  }  

  // UI Construction  
  build() {  
    Column() {  
      // Title Section  
      Text('Blood Type Calculator')  
        .fontColor(this.textColor)  
        .fontSize(18)  
        .width('100%')  
        .height(50)  
        .textAlign(TextAlign.Center)  
        .backgroundColor(Color.White)  
        .shadow({ radius: 2, color: this.lineColor, offsetX: 0, offsetY: 5 });  

      // Introduction Section  
      Column() {  
        Text('How It Works').fontSize(20).fontWeight(600).fontColor(this.textColor);  
        Text('Blood type inheritance depends on combinations of A/B/O genes. This tool predicts possible offspring blood types based on parental selections.')  
          .fontSize(18).fontColor(this.textColor).margin({ top: `${this.basePadding / 2}lpx`);  
      }  
      // ... (UI styling properties unchanged)  

      // Parent Selection Section  
      Column() {  
        Row() {  
          Text('Father\'s Blood Type').fontColor(this.textColor).fontSize(18);  
          SegmentButton({  
            options: this.singleSelectCapsuleOptions,  
            selectedIndexes: this.fatherBloodTypeIndex  
          }).width('400lpx');  
        }  
        // ... (Mother's section mirroring father's)  
      }  

      // Result Display Section  
      Column() {  
        Text(this.possibleBloodTypesText).fontColor(this.textColor).fontSize(18);  
        Text(this.impossibleBloodTypesText).fontColor(this.textColor).fontSize(18);  
      }  
    }  
    .backgroundColor("#f4f8fb");  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

Key Technical Points

  1. Genetic Algorithm Implementation

    • The getGenes() method maps blood types to possible gene combinations (e.g., A → ["A", "O"]).
    • combineGenes() generates all possible offspring gene pairs through nested iteration.
    • getBloodTypesFromGenes() converts sorted gene pairs to standardized blood types.
  2. UI Components

    • Uses SegmentButton for blood type selection with capsule-style styling.
    • Implements responsive layout with percentage-based widths and logical pixel units (lpx).
    • Applies consistent shadow effects and color schemes for visual hierarchy.
  3. State Management

    • @State variables track UI state and calculation results.
    • @Watch decorator triggers recalculation when parental selections change.
  4. Performance Optimization

    • Uses console.info for debugging while avoiding expensive operations in render cycles.
    • Memoizes blood type lists to prevent unnecessary re-renders.

This implementation demonstrates HarmonyOS NEXT's capability to build scientifically accurate tools with clean UI/UX principles.

Top comments (0)