【引言】
本專案是一個簡單的隨機數生成器應用,使用者可以透過設定隨機數的範圍和個數,並選擇是否允許生成重複的隨機數,來生成所需的隨機數列表。生成的結果可以透過點選“複製”按鈕複製到剪貼簿。
【環境準備】
• 作業系統:Windows 10
• 開發工具:DevEco Studio NEXT Beta1 Build Version: 5.0.3.806
• 目標裝置:華為Mate60 Pro
• 開發語言:ArkTS
• 框架:ArkUI
• API版本:API 12
【關鍵技術點】
1. 使用者介面設計
使用者介面主要包括以下幾個部分:
• 標題欄:顯示應用名稱。
• 輸入框:使用者可以輸入隨機數的起始值、結束值和生成個數。
• 開關:使用者可以選擇生成的隨機數是否允許重複。
• 生成按鈕:點選後生成隨機數。
• 結果顯示區:顯示生成的隨機數,並提供複製功能。
2. 隨機數生成演算法
隨機數生成是本專案的重點。根據使用者是否允許生成重複的隨機數,演算法分為兩種情況:
2.1 不允許重複
當使用者選擇不允許生成重複的隨機數時,程式使用一個 Set 來儲存生成的隨機數,利用 Set 的特性自動去重。具體步驟如下:
1)計算範圍:計算使用者指定的隨機數範圍 range = endValue - startValue + 1。
2)生成隨機數:使用一個臨時陣列 tempArray 來輔助生成不重複的隨機數。每次生成一個隨機索引 randomIndex,從 tempArray 中取出或計算一個新的隨機數 randomNum,並將其新增到 Set 中。
3)更新臨時陣列:將 tempArray 中末尾的元素移動到隨機位置,以確保下次生成的隨機數仍然是唯一的。
if (!this.isUnique) { if (countValue > range) { // 顯示錯誤提示 this.getUIContext().showAlertDialog({ title: '錯誤提示', message: `請求的隨機數數量超過了範圍內的總數`, confirm: { defaultFocus: true, value: '我知道了', 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 = 0; if (tempArray[randomIndex] !== undefined) { randomNum = tempArray[randomIndex]; } else { randomNum = 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)); }
3. 剪貼簿功能
為了方便使用者使用,程式提供了將生成的隨機數複製到剪貼簿的功能。具體實現如下:
private copyToClipboard(text: string): void { const pasteboardData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, text); const systemPasteboard = pasteboard.getSystemPasteboard(); systemPasteboard.setData(pasteboardData); promptAction.showToast({ message: '已複製' }); }
【完整程式碼】
// 匯入剪貼簿服務模組,用於後續實現複製功能 import { pasteboard } from '@kit.BasicServicesKit'; // 匯入用於顯示提示資訊的服務 import { promptAction } from '@kit.ArkUI'; // 使用裝飾器定義一個入口元件,這是應用的主介面 @Entry @Component struct RandomNumberGenerator { // 定義基礎間距,用於佈局中的間距設定 @State private baseSpacing: number = 30; // 儲存生成的隨機數字符串 @State private generatedNumbers: string = ''; // 應用的主題色 @State private primaryColor: string = '#fea024'; // 文字的顏色 @State private fontColor: string = "#2e2e2e"; // 輸入框是否獲取焦點的狀態變數 @State private isFocusStart: boolean = false; @State private isFocusEnd: boolean = false; @State private isFocusCount: boolean = false; // 是否允許生成的隨機數重複 @State private isUnique: boolean = true; // 隨機數生成的起始值 @State private startValue: number = 0; // 隨機數生成的結束值 @State private endValue: number = 0; // 要生成的隨機數個數 @State private countValue: number = 0; // 生成隨機數的方法 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>(); // 使用Set來自動去重 const tempArray: number[] = []; // 臨時陣列,用於輔助生成不重複的隨機數 // 如果不允許重複,則使用去重演算法生成隨機數 if (!this.isUnique) { // 如果請求的隨機數數量超過了範圍內的總數,則顯示錯誤提示 if (countValue > range) { this.getUIContext().showAlertDialog({ title: '錯誤提示', message: `請求的隨機數數量超過了範圍內的總數`, confirm: { defaultFocus: true, value: '我知道了', 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 = 0; if (tempArray[randomIndex] !== undefined) { // 如果索引位置已有值,則使用該值 randomNum = tempArray[randomIndex]; } else { randomNum = startValue + randomIndex; // 否則計算新的隨機數 } generatedNumbers.add(randomNum); // 新增到Set中,自動去重 if (tempArray[range - 1 - i] === undefined) { // 更新末尾元素的位置 tempArray[range - 1 - i] = startValue + range - 1 - i; } tempArray[randomIndex] = tempArray[range - 1 - i]; // 將末尾元素移到隨機位置 } // 將生成的隨機數轉換成JSON格式的字串 this.generatedNumbers = JSON.stringify(Array.from(generatedNumbers)); } else { // 如果允許重複,則直接生成隨機數 for (let i = 0; i < this.countValue; i++) { let randomNumber = this.startValue + Math.floor(Math.random() * (this.endValue - this.startValue)); tempArray.push(randomNumber); } // 將生成的隨機數轉換成JSON格式的字串 this.generatedNumbers = JSON.stringify(tempArray); } } // 將生成的隨機數複製到剪貼簿的方法 private copyToClipboard(text: string): void { const pasteboardData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, text); // 建立剪貼簿資料 const systemPasteboard = pasteboard.getSystemPasteboard(); // 獲取系統剪貼簿 systemPasteboard.setData(pasteboardData); // 設定剪貼簿資料 // 顯示覆製成功的提示資訊 promptAction.showToast({ message: '已複製' }); } // 構建頁面佈局的方法 build() { Column() { // 標題欄,展示應用名 Text("隨機數生成") .width('100%') // 設定寬度為100% .height(54) // 設定高度為54 .fontSize(18) // 設定字型大小為18 .fontWeight(600) // 設定字型粗細為600 .backgroundColor(Color.White) // 設定背景顏色為白色 .textAlign(TextAlign.Center) // 設定文字居中對齊 .fontColor(this.fontColor); // 設定文字顏色 // 隨機數範圍設定區域 Column() { Row() { Text(`隨機數範圍`) .fontWeight(600) // 設定字型粗細為600 .fontSize(18) // 設定字型大小為18 .fontColor(this.fontColor); // 設定文字顏色 } .margin({ top: `${this.baseSpacing}lpx`, left: `${this.baseSpacing}lpx` }); // 設定邊距 // 輸入隨機數範圍的兩個值 Row() { TextInput({ placeholder: '開始(>=)' }) // 輸入框,顯示佔位符 .layoutWeight(1) // 設定佈局權重為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: '結束(<=)' }) // 輸入框,顯示佔位符 .layoutWeight(1) // 設定佈局權重為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`, // 上邊距 }); // 輸入生成隨機數的個數 Text('生成隨機數個數') .fontWeight(600) // 設定字型粗細為600 .fontSize(18) // 設定字型大小為18 .fontColor(this.fontColor) // 設定文字顏色 .margin({ left: `${this.baseSpacing}lpx`, top: `${this.baseSpacing}lpx` }); // 設定邊距 Row() { TextInput({ placeholder: '' }) // 輸入框,顯示佔位符 .layoutWeight(1) // 設定佈局權重為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`, // 上邊距 }); // 設定數字是否可重複的開關 Row() { Text('數字是否可重複') .fontWeight(400) // 設定字型粗細為400 .fontSize(16) // 設定字型大小為16 .fontColor(this.fontColor) // 設定文字顏色 .layoutWeight(1); // 設定佈局權重為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%') // 設定寬度為100% .padding({ left: `${this.baseSpacing}lpx`, // 左內邊距 right: `${this.baseSpacing}lpx`, // 右內邊距 top: `${this.baseSpacing / 3}lpx`, // 上內邊距 }) .hitTestBehavior(HitTestMode.Block) // 設定點選測試行為 .onClick(() => this.isUnique = !this.isUnique); // 點選時切換狀態 // 生成隨機數的按鈕 Text('開始生成') .fontColor(Color.White) // 設定文字顏色為白色 .backgroundColor(this.primaryColor) // 設定背景顏色為主題色 .height(54) // 設定高度為54 .textAlign(TextAlign.Center) // 設定文字居中對齊 .borderRadius(10) // 設定圓角半徑 .fontSize(18) // 設定字型大小為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); // 設定水平對齊方式為左對齊 // 顯示生成的隨機數 Column() { Text(`生成的隨機數為:`) .fontWeight(600) // 設定字型粗細為600 .fontSize(18) // 設定字型大小為18 .fontColor(this.fontColor) // 設定文字顏色 .margin({ top: `${this.baseSpacing}lpx`, // 上邊距 left: `${this.baseSpacing}lpx`, // 左邊距 }); Text(`${this.generatedNumbers}`) // 顯示生成的隨機數 .width('650lpx') // 設定寬度 .fontColor(this.primaryColor) // 設定文字顏色為主題色 .fontSize(18) // 設定字型大小為18 .textAlign(TextAlign.Center) // 設定文字居中對齊 .padding({ left: 5, right: 5 }) // 設定內邊距 .margin({ top: `${this.baseSpacing / 3}lpx` // 上邊距 }); // 複製生成的隨機數到剪貼簿的按鈕 Text('複製') .enabled(this.generatedNumbers ? true : false) // 按鈕是否可用 .fontColor(Color.White) // 設定文字顏色為白色 .backgroundColor(this.primaryColor) // 設定背景顏色為主題色 .height(54) // 設定高度為54 .textAlign(TextAlign.Center) // 設定文字居中對齊 .borderRadius(10) // 設定圓角半徑 .fontSize(18) // 設定字型大小為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%') // 設定高度為100% .width('100%') // 設定寬度為100% .backgroundColor("#f2f3f5"); // 設定背景顏色 } }