在这里插入图片描述

目录

  1. 概述
  2. 工具功能
  3. 核心实现
  4. Kotlin 源代码
  5. JavaScript 编译代码
  6. ArkTS 调用代码
  7. 实战案例
  8. 最佳实践

概述

本文档介绍如何在 Kotlin Multiplatform (KMP) 鸿蒙跨端开发中实现一个功能完整的速度单位转换工具系统。速度是物理学中的基本量,在日常生活、交通运输、体育竞技、气象预报等领域都有广泛应用。这个工具提供了对多种速度单位的全面转换支持,包括公制单位(米/秒、千米/小时)和英制单位(英里/小时、英尺/秒)等,以及速度转换的各种操作和分析。

在实际应用中,速度转换工具广泛应用于以下场景:导航应用、运动健身、气象预报、交通管理、航空航海、物理教育等。通过 KMP 框架的跨端能力,我们可以在不同平台上使用相同的速度转换逻辑,确保转换结果的准确性和一致性。

工具的特点

  • 完整的速度单位支持:支持公制和英制单位的相互转换
  • 精确的转换:使用标准的速度转换系数
  • 双向转换:支持任意两种速度单位之间的转换
  • 速度范围检查:检查速度值是否在合理范围内
  • 速度分析:提供速度数据的详细分析
  • 跨端兼容:一份 Kotlin 代码可同时服务多个平台

工具功能

1. 公制速度单位转换

公制速度单位是国际标准单位,基于米和秒。米/秒和千米/小时是最常见的公制速度单位。公制速度转换需要处理小数点精度和单位之间的倍数关系。

  • 米/秒到千米/小时:1 m/s = 3.6 km/h
  • 千米/小时到米/秒:1 km/h = 1/3.6 m/s
  • 米/秒到厘米/秒:1 m/s = 100 cm/s
  • 跨单位转换:支持任意两个公制单位之间的转换

2. 英制速度单位转换

英制速度单位主要在美国和英国使用。英里/小时和英尺/秒是主要的英制速度单位。英制速度转换需要处理复杂的倍数关系。

  • 英里/小时到英尺/秒:1 mph = 5280/3600 ft/s ≈ 1.46667 ft/s
  • 英尺/秒到英里/小时:1 ft/s = 3600/5280 mph ≈ 0.681818 mph
  • 节到英里/小时:1 knot = 1.15078 mph
  • 跨单位转换:支持任意两个英制单位之间的转换

3. 公制与英制转换

公制和英制之间的转换需要使用标准的转换系数。这对于国际应用很重要。

  • 米/秒到英里/小时:1 m/s = 2.23694 mph
  • 千米/小时到英里/小时:1 km/h = 0.621371 mph
  • 英里/小时到千米/小时:1 mph = 1.60934 km/h
  • 精确转换:使用标准的国际转换系数

4. 速度范围检查

速度范围检查是验证速度值是否在合理范围内。不同的应用有不同的速度范围。速度范围检查对于数据质量控制很重要。

  • 正数检查:速度必须为正数或零
  • 合理范围检查:检查速度是否在常见范围内
  • 单位验证:检查速度单位是否有效
  • 错误报告:提供详细的错误信息

5. 速度描述和分类

速度描述是用自然语言描述速度的大小。速度分类是根据速度范围进行分类。速度描述和分类对于用户界面很有用。

  • 速度等级:静止、极慢、很慢、慢、中等、快、很快、极快
  • 速度评价:根据速度生成评价
  • 应用场景:根据速度推荐应用场景
  • 参考对象:提供速度的参考对象

6. 速度统计分析

速度统计分析是对速度数据进行统计和分析。速度统计分析对于运动分析和数据处理很有用。

  • 最大速度:找出最大的速度
  • 最小速度:找出最小的速度
  • 平均速度:计算速度的平均值
  • 速度分布:分析速度的分布

7. 速度转换历史

速度转换历史是记录之前的转换操作。速度转换历史对于用户查看和重复使用很有用。

  • 转换记录:记录所有的转换操作
  • 快速重复:快速重复之前的转换
  • 历史查询:查询之前的转换结果
  • 导出数据:导出转换历史

核心实现

1. 公制速度转换

fun meterPerSecondToKilometerPerHour(mps: Double): Double = mps * 3.6
fun kilometerPerHourToMeterPerSecond(kmh: Double): Double = kmh / 3.6

fun meterPerSecondToCentimeterPerSecond(mps: Double): Double = mps * 100
fun centimeterPerSecondToMeterPerSecond(cms: Double): Double = cms / 100

fun convertMetric(value: Double, fromUnit: String, toUnit: String): Double {
    val mps = when (fromUnit.lowercase()) {
        "m/s" -> value
        "km/h" -> kilometerPerHourToMeterPerSecond(value)
        "cm/s" -> centimeterPerSecondToMeterPerSecond(value)
        else -> 0.0
    }
    
    return when (toUnit.lowercase()) {
        "m/s" -> mps
        "km/h" -> meterPerSecondToKilometerPerHour(mps)
        "cm/s" -> meterPerSecondToCentimeterPerSecond(mps)
        else -> 0.0
    }
}

代码说明: 公制速度转换通过米/秒作为标准单位。先将源单位转换为米/秒,再转换为目标单位。这种方法简洁且易于维护。

2. 英制速度转换

fun milePerHourToFootPerSecond(mph: Double): Double = mph * 5280 / 3600
fun footPerSecondToMilePerHour(fps: Double): Double = fps * 3600 / 5280

fun knotToMilePerHour(knot: Double): Double = knot * 1.15078
fun milePerHourToKnot(mph: Double): Double = mph / 1.15078

fun convertImperial(value: Double, fromUnit: String, toUnit: String): Double {
    val fps = when (fromUnit.lowercase()) {
        "mph" -> milePerHourToFootPerSecond(value)
        "ft/s" -> value
        "knot" -> knotToMilePerHour(value) * 5280 / 3600
        else -> 0.0
    }
    
    return when (toUnit.lowercase()) {
        "mph" -> footPerSecondToMilePerHour(fps)
        "ft/s" -> fps
        "knot" -> footPerSecondToMilePerHour(fps) / 1.15078
        else -> 0.0
    }
}

代码说明: 英制速度转换通过英尺/秒作为标准单位。先将源单位转换为英尺/秒,再转换为目标单位。这种方法处理了英制单位复杂的倍数关系。

3. 速度验证

fun validateSpeed(speed: Double): Pair<Boolean, String> {
    return if (speed < 0) {
        Pair(false, "速度不能为负数")
    } else if (speed > 1000) {
        Pair(false, "速度超出合理范围")
    } else {
        Pair(true, "速度有效")
    }
}

代码说明: 速度验证检查速度是否为正数且在合理范围内。这确保了数据的有效性。

4. 速度描述

fun describeSpeed(mps: Double): String {
    return when {
        mps < 0.1 -> "静止或极慢"
        mps < 1 -> "极慢,蜗牛级别"
        mps < 5 -> "很慢,步行级别"
        mps < 10 -> "慢,慢跑级别"
        mps < 20 -> "中等,骑车级别"
        mps < 30 -> "快,汽车级别"
        mps < 50 -> "很快,高速公路级别"
        else -> "极快,飞行级别"
    }
}

fun getSpeedEmoji(mps: Double): String {
    return when {
        mps < 1 -> "🐌"
        mps < 5 -> "🚶"
        mps < 10 -> "🏃"
        mps < 20 -> "🚴"
        mps < 30 -> "🚗"
        mps < 50 -> "🚙"
        else -> "✈️"
    }
}

代码说明: 速度描述根据米/秒的范围提供自然语言描述。通过使用 emoji,可以提供更加直观的速度表示。

5. 速度统计分析

fun analyzeSpeeds(speeds: List<Double>, unit: String): Map<String, Any> {
    if (speeds.isEmpty()) return mapOf("error" to "速度列表为空")
    
    val stats = mutableMapOf<String, Any>()
    stats["count"] = speeds.size
    stats["max"] = speeds.maxOrNull() ?: 0.0
    stats["min"] = speeds.minOrNull() ?: 0.0
    stats["average"] = String.format("%.2f", speeds.average())
    
    val sorted = speeds.sorted()
    stats["median"] = if (speeds.size % 2 == 0) {
        (sorted[speeds.size / 2 - 1] + sorted[speeds.size / 2]) / 2
    } else {
        sorted[speeds.size / 2]
    }
    
    stats["unit"] = unit
    
    return stats
}

代码说明: 速度统计分析计算多个统计指标,包括最大值、最小值、平均值、中位数等。这对于分析速度数据很有用。


Kotlin 源代码

// SpeedConverter.kt

class SpeedConverter {
    
    // 公制转换
    fun meterPerSecondToKilometerPerHour(mps: Double): Double = mps * 3.6
    fun kilometerPerHourToMeterPerSecond(kmh: Double): Double = kmh / 3.6
    
    fun meterPerSecondToCentimeterPerSecond(mps: Double): Double = mps * 100
    fun centimeterPerSecondToMeterPerSecond(cms: Double): Double = cms / 100
    
    // 英制转换
    fun milePerHourToFootPerSecond(mph: Double): Double = mph * 5280 / 3600
    fun footPerSecondToMilePerHour(fps: Double): Double = fps * 3600 / 5280
    
    fun knotToMilePerHour(knot: Double): Double = knot * 1.15078
    fun milePerHourToKnot(mph: Double): Double = mph / 1.15078
    
    // 公制与英制转换
    fun meterPerSecondToMilePerHour(mps: Double): Double = mps * 2.23694
    fun milePerHourToMeterPerSecond(mph: Double): Double = mph / 2.23694
    
    fun kilometerPerHourToMilePerHour(kmh: Double): Double = kmh * 0.621371
    fun milePerHourToKilometerPerHour(mph: Double): Double = mph * 1.60934
    
    fun convertMetric(value: Double, fromUnit: String, toUnit: String): Double {
        val mps = when (fromUnit.lowercase()) {
            "m/s" -> value
            "km/h" -> kilometerPerHourToMeterPerSecond(value)
            "cm/s" -> centimeterPerSecondToMeterPerSecond(value)
            else -> 0.0
        }
        
        return when (toUnit.lowercase()) {
            "m/s" -> mps
            "km/h" -> meterPerSecondToKilometerPerHour(mps)
            "cm/s" -> meterPerSecondToCentimeterPerSecond(mps)
            else -> 0.0
        }
    }
    
    fun convertImperial(value: Double, fromUnit: String, toUnit: String): Double {
        val fps = when (fromUnit.lowercase()) {
            "mph" -> milePerHourToFootPerSecond(value)
            "ft/s" -> value
            "knot" -> knotToMilePerHour(value) * 5280 / 3600
            else -> 0.0
        }
        
        return when (toUnit.lowercase()) {
            "mph" -> footPerSecondToMilePerHour(fps)
            "ft/s" -> fps
            "knot" -> footPerSecondToMilePerHour(fps) / 1.15078
            else -> 0.0
        }
    }
    
    fun convertBetweenSystems(value: Double, fromUnit: String, toUnit: String): Double {
        val mps = when (fromUnit.lowercase()) {
            "m/s", "km/h", "cm/s" -> convertMetric(value, fromUnit, "m/s")
            "mph" -> milePerHourToMeterPerSecond(value)
            "ft/s" -> value * 0.3048
            "knot" -> knotToMilePerHour(value) * 0.44704
            else -> 0.0
        }
        
        return when (toUnit.lowercase()) {
            "m/s", "km/h", "cm/s" -> convertMetric(mps, "m/s", toUnit)
            "mph" -> meterPerSecondToMilePerHour(mps)
            "ft/s" -> mps / 0.3048
            "knot" -> mps / 0.51444
            else -> 0.0
        }
    }
    
    fun validateSpeed(speed: Double): Pair<Boolean, String> {
        return if (speed < 0) {
            Pair(false, "速度不能为负数")
        } else if (speed > 1000) {
            Pair(false, "速度超出合理范围")
        } else {
            Pair(true, "速度有效")
        }
    }
    
    fun describeSpeed(mps: Double): String {
        return when {
            mps < 0.1 -> "静止或极慢"
            mps < 1 -> "极慢,蜗牛级别"
            mps < 5 -> "很慢,步行级别"
            mps < 10 -> "慢,慢跑级别"
            mps < 20 -> "中等,骑车级别"
            mps < 30 -> "快,汽车级别"
            mps < 50 -> "很快,高速公路级别"
            else -> "极快,飞行级别"
        }
    }
    
    fun getSpeedEmoji(mps: Double): String {
        return when {
            mps < 1 -> "🐌"
            mps < 5 -> "🚶"
            mps < 10 -> "🏃"
            mps < 20 -> "🚴"
            mps < 30 -> "🚗"
            mps < 50 -> "🚙"
            else -> "✈️"
        }
    }
    
    fun analyzeSpeeds(speeds: List<Double>, unit: String): Map<String, Any> {
        if (speeds.isEmpty()) return mapOf("error" to "速度列表为空")
        
        val stats = mutableMapOf<String, Any>()
        stats["count"] = speeds.size
        stats["max"] = speeds.maxOrNull() ?: 0.0
        stats["min"] = speeds.minOrNull() ?: 0.0
        stats["average"] = String.format("%.2f", speeds.average())
        
        val sorted = speeds.sorted()
        stats["median"] = if (speeds.size % 2 == 0) {
            (sorted[speeds.size / 2 - 1] + sorted[speeds.size / 2]) / 2
        } else {
            sorted[speeds.size / 2]
        }
        
        stats["unit"] = unit
        
        return stats
    }
    
    fun formatSpeed(speed: Double, unit: String, decimals: Int = 2): String {
        return String.format("%.${decimals}f $unit", speed)
    }
    
    fun getUnitInfo(unit: String): Map<String, String> {
        return when (unit.lowercase()) {
            "m/s" -> mapOf("name" to "米/秒", "system" to "公制", "symbol" to "m/s")
            "km/h" -> mapOf("name" to "千米/小时", "system" to "公制", "symbol" to "km/h")
            "cm/s" -> mapOf("name" to "厘米/秒", "system" to "公制", "symbol" to "cm/s")
            "mph" -> mapOf("name" to "英里/小时", "system" to "英制", "symbol" to "mph")
            "ft/s" -> mapOf("name" to "英尺/秒", "system" to "英制", "symbol" to "ft/s")
            "knot" -> mapOf("name" to "节", "system" to "海事", "symbol" to "knot")
            else -> mapOf("error" to "不支持的速度单位")
        }
    }
}

fun main() {
    val converter = SpeedConverter()
    
    println("=== 速度单位转换工具演示 ===\n")
    
    // 公制转换
    val mps = 10.0
    println("$mps m/s 转换:")
    println("  千米/小时: ${converter.convertMetric(mps, "m/s", "km/h")} km/h")
    println("  厘米/秒: ${converter.convertMetric(mps, "m/s", "cm/s")} cm/s\n")
    
    // 英制转换
    val mph = 60.0
    println("$mph mph 转换:")
    println("  英尺/秒: ${converter.convertImperial(mph, "mph", "ft/s")} ft/s")
    println("  节: ${converter.convertImperial(mph, "mph", "knot")} knot\n")
    
    // 公制与英制转换
    println("10 m/s 转英里/小时: ${converter.convertBetweenSystems(10.0, "m/s", "mph")} mph")
    println("60 mph 转千米/小时: ${converter.convertBetweenSystems(60.0, "mph", "km/h")} km/h\n")
    
    // 速度描述
    println("10 m/s 的描述: ${converter.describeSpeed(10.0)} ${converter.getSpeedEmoji(10.0)}")
}

Kotlin 代码说明: 这个实现提供了完整的速度转换功能。SpeedConverter 类包含了公制转换、英制转换、系统间转换、验证、描述、分析等多个方法。通过使用标准的速度转换系数,确保了转换的准确性。


JavaScript 编译代码

// SpeedConverter.js
class SpeedConverter {
    // 公制转换
    meterPerSecondToKilometerPerHour(mps) { return mps * 3.6; }
    kilometerPerHourToMeterPerSecond(kmh) { return kmh / 3.6; }
    
    meterPerSecondToCentimeterPerSecond(mps) { return mps * 100; }
    centimeterPerSecondToMeterPerSecond(cms) { return cms / 100; }
    
    // 英制转换
    milePerHourToFootPerSecond(mph) { return mph * 5280 / 3600; }
    footPerSecondToMilePerHour(fps) { return fps * 3600 / 5280; }
    
    knotToMilePerHour(knot) { return knot * 1.15078; }
    milePerHourToKnot(mph) { return mph / 1.15078; }
    
    // 公制与英制转换
    meterPerSecondToMilePerHour(mps) { return mps * 2.23694; }
    milePerHourToMeterPerSecond(mph) { return mph / 2.23694; }
    
    kilometerPerHourToMilePerHour(kmh) { return kmh * 0.621371; }
    milePerHourToKilometerPerHour(mph) { return mph * 1.60934; }
    
    convertMetric(value, fromUnit, toUnit) {
        let mps;
        switch (fromUnit.toLowerCase()) {
            case "m/s": mps = value; break;
            case "km/h": mps = this.kilometerPerHourToMeterPerSecond(value); break;
            case "cm/s": mps = this.centimeterPerSecondToMeterPerSecond(value); break;
            default: mps = 0;
        }
        
        switch (toUnit.toLowerCase()) {
            case "m/s": return mps;
            case "km/h": return this.meterPerSecondToKilometerPerHour(mps);
            case "cm/s": return this.meterPerSecondToCentimeterPerSecond(mps);
            default: return 0;
        }
    }
    
    convertImperial(value, fromUnit, toUnit) {
        let fps;
        switch (fromUnit.toLowerCase()) {
            case "mph": fps = this.milePerHourToFootPerSecond(value); break;
            case "ft/s": fps = value; break;
            case "knot": fps = this.knotToMilePerHour(value) * 5280 / 3600; break;
            default: fps = 0;
        }
        
        switch (toUnit.toLowerCase()) {
            case "mph": return this.footPerSecondToMilePerHour(fps);
            case "ft/s": return fps;
            case "knot": return this.footPerSecondToMilePerHour(fps) / 1.15078;
            default: return 0;
        }
    }
    
    convertBetweenSystems(value, fromUnit, toUnit) {
        let mps;
        switch (fromUnit.toLowerCase()) {
            case "m/s":
            case "km/h":
            case "cm/s":
                mps = this.convertMetric(value, fromUnit, "m/s");
                break;
            case "mph": mps = this.milePerHourToMeterPerSecond(value); break;
            case "ft/s": mps = value * 0.3048; break;
            case "knot": mps = this.knotToMilePerHour(value) * 0.44704; break;
            default: mps = 0;
        }
        
        switch (toUnit.toLowerCase()) {
            case "m/s":
            case "km/h":
            case "cm/s":
                return this.convertMetric(mps, "m/s", toUnit);
            case "mph": return this.meterPerSecondToMilePerHour(mps);
            case "ft/s": return mps / 0.3048;
            case "knot": return mps / 0.51444;
            default: return 0;
        }
    }
    
    validateSpeed(speed) {
        if (speed < 0) {
            return { valid: false, message: "速度不能为负数" };
        } else if (speed > 1000) {
            return { valid: false, message: "速度超出合理范围" };
        }
        return { valid: true, message: "速度有效" };
    }
    
    describeSpeed(mps) {
        if (mps < 0.1) return "静止或极慢";
        if (mps < 1) return "极慢,蜗牛级别";
        if (mps < 5) return "很慢,步行级别";
        if (mps < 10) return "慢,慢跑级别";
        if (mps < 20) return "中等,骑车级别";
        if (mps < 30) return "快,汽车级别";
        if (mps < 50) return "很快,高速公路级别";
        return "极快,飞行级别";
    }
    
    getSpeedEmoji(mps) {
        if (mps < 1) return "🐌";
        if (mps < 5) return "🚶";
        if (mps < 10) return "🏃";
        if (mps < 20) return "🚴";
        if (mps < 30) return "🚗";
        if (mps < 50) return "🚙";
        return "✈️";
    }
    
    analyzeSpeeds(speeds, unit) {
        if (speeds.length === 0) return { error: "速度列表为空" };
        
        const stats = {};
        stats.count = speeds.length;
        stats.max = Math.max(...speeds);
        stats.min = Math.min(...speeds);
        stats.average = (speeds.reduce((a, b) => a + b, 0) / speeds.length).toFixed(2);
        
        const sorted = [...speeds].sort((a, b) => a - b);
        stats.median = speeds.length % 2 === 0 ?
            (sorted[speeds.length / 2 - 1] + sorted[speeds.length / 2]) / 2 :
            sorted[Math.floor(speeds.length / 2)];
        
        stats.unit = unit;
        
        return stats;
    }
    
    formatSpeed(speed, unit, decimals = 2) {
        return speed.toFixed(decimals) + " " + unit;
    }
    
    getUnitInfo(unit) {
        switch (unit.toLowerCase()) {
            case "m/s": return { name: "米/秒", system: "公制", symbol: "m/s" };
            case "km/h": return { name: "千米/小时", system: "公制", symbol: "km/h" };
            case "cm/s": return { name: "厘米/秒", system: "公制", symbol: "cm/s" };
            case "mph": return { name: "英里/小时", system: "英制", symbol: "mph" };
            case "ft/s": return { name: "英尺/秒", system: "英制", symbol: "ft/s" };
            case "knot": return { name: "节", system: "海事", symbol: "knot" };
            default: return { error: "不支持的速度单位" };
        }
    }
}

// 使用示例
const converter = new SpeedConverter();

console.log("=== 速度单位转换工具演示 ===\n");

const mps = 10;
console.log(`${mps} m/s 转换:`);
console.log("  千米/小时:", converter.convertMetric(mps, "m/s", "km/h"), "km/h");
console.log("  厘米/秒:", converter.convertMetric(mps, "m/s", "cm/s"), "cm/s");

const mph = 60;
console.log(`\n${mph} mph 转换:`);
console.log("  英尺/秒:", converter.convertImperial(mph, "mph", "ft/s"), "ft/s");
console.log("  节:", converter.convertImperial(mph, "mph", "knot"), "knot");

console.log("\n10 m/s 转英里/小时:", converter.convertBetweenSystems(10, "m/s", "mph"), "mph");
console.log("60 mph 转千米/小时:", converter.convertBetweenSystems(60, "mph", "km/h"), "km/h");

console.log(`\n10 m/s 的描述: ${converter.describeSpeed(10)} ${converter.getSpeedEmoji(10)}`);

JavaScript 代码说明: JavaScript 版本是 Kotlin 代码的直接转译。由于 JavaScript 和 Kotlin 在语法上有差异,我们使用 switch 语句替代 when 表达式。整体逻辑和算法与 Kotlin 版本保持一致。


ArkTS 调用代码

// SpeedConverterPage.ets
import { SpeedConverter } from './SpeedConverter';

@Entry
@Component
struct SpeedConverterPage {
    @State inputValue: string = '10';
    @State fromUnit: string = 'm/s';
    @State toUnit: string = 'km/h';
    @State result: string = '';
    @State showResult: boolean = false;
    @State isLoading: boolean = false;
    @State operationType: string = 'convert';
    
    private converter: SpeedConverter = new SpeedConverter();
    
    private unitOptions = [
        { label: '米/秒 (m/s)', value: 'm/s' },
        { label: '千米/小时 (km/h)', value: 'km/h' },
        { label: '厘米/秒 (cm/s)', value: 'cm/s' },
        { label: '英里/小时 (mph)', value: 'mph' },
        { label: '英尺/秒 (ft/s)', value: 'ft/s' },
        { label: '节 (knot)', value: 'knot' }
    ];
    
    private operationOptions = [
        { label: '速度转换', value: 'convert' },
        { label: '速度验证', value: 'validate' },
        { label: '速度描述', value: 'describe' },
        { label: '单位信息', value: 'info' }
    ];
    
    performOperation() {
        this.isLoading = true;
        try {
            let resultText = '';
            const speed = parseFloat(this.inputValue);
            
            switch (this.operationType) {
                case 'convert':
                    const convertResult = this.converter.convertBetweenSystems(speed, this.fromUnit, this.toUnit);
                    resultText = `${speed} ${this.fromUnit} = ${convertResult.toFixed(4)} ${this.toUnit}`;
                    break;
                case 'validate':
                    const validation = this.converter.validateSpeed(speed);
                    resultText = validation.valid ? '✓ ' + validation.message : '✗ ' + validation.message;
                    break;
                case 'describe':
                    let mps = speed;
                    if (this.fromUnit !== 'm/s') {
                        mps = this.converter.convertBetweenSystems(speed, this.fromUnit, 'm/s');
                    }
                    const description = this.converter.describeSpeed(mps);
                    const emoji = this.converter.getSpeedEmoji(mps);
                    resultText = `${emoji} ${description}`;
                    break;
                case 'info':
                    const info = this.converter.getUnitInfo(this.fromUnit);
                    resultText = `📊 ${info.name} 信息\n`;
                    resultText += `━━━━━━━━━━━━━━━━━━━━━\n`;
                    resultText += `符号: ${info.symbol}\n`;
                    resultText += `系统: ${info.system}`;
                    break;
                default:
                    resultText = '未知操作';
            }
            
            this.result = resultText;
            this.showResult = true;
        } catch (error) {
            this.result = '操作失败: ' + (error instanceof Error ? error.message : String(error));
            this.showResult = true;
        } finally {
            this.isLoading = false;
        }
    }
    
    build() {
        Column() {
            // 标题
            Text('速度单位转换工具')
                .fontSize(28)
                .fontWeight(FontWeight.Bold)
                .margin({ top: 20, bottom: 20 })
                .textAlign(TextAlign.Center)
                .width('100%')
            
            // 操作类型选择
            Column() {
                Text('操作类型')
                    .fontSize(14)
                    .fontColor('#666666')
                    .margin({ bottom: 10 })
                
                Select(this.operationOptions)
                    .value(this.operationType)
                    .onSelect((index: number, value?: string) => {
                        this.operationType = value || 'convert';
                    })
                    .width('100%')
                    .height(40)
            }
            .width('100%')
            .padding(15)
            .backgroundColor('#ffffff')
            .borderRadius(10)
            .border({ width: 1, color: '#eeeeee' })
            .margin({ bottom: 20 })
            
            // 速度单位选择
            Row() {
                Column() {
                    Text('源单位')
                        .fontSize(12)
                        .fontColor('#666666')
                        .margin({ bottom: 8 })
                    
                    Select(this.unitOptions)
                        .value(this.fromUnit)
                        .onSelect((index: number, value?: string) => {
                            this.fromUnit = value || 'm/s';
                        })
                        .width('100%')
                        .height(40)
                }
                .width('48%')
                
                Text('→')
                    .fontSize(20)
                    .fontWeight(FontWeight.Bold)
                    .width('4%')
                    .textAlign(TextAlign.Center)
                
                Column() {
                    Text('目标单位')
                        .fontSize(12)
                        .fontColor('#666666')
                        .margin({ bottom: 8 })
                    
                    Select(this.unitOptions)
                        .value(this.toUnit)
                        .onSelect((index: number, value?: string) => {
                            this.toUnit = value || 'km/h';
                        })
                        .width('100%')
                        .height(40)
                }
                .width('48%')
            }
            .width('100%')
            .padding(15)
            .backgroundColor('#ffffff')
            .borderRadius(10)
            .border({ width: 1, color: '#eeeeee' })
            .margin({ bottom: 20 })
            
            // 输入框
            Column() {
                Text('输入速度值')
                    .fontSize(14)
                    .fontColor('#666666')
                    .margin({ bottom: 10 })
                
                TextInput({ placeholder: '输入速度值' })
                    .value(this.inputValue)
                    .onChange((value: string) => {
                        this.inputValue = value;
                    })
                    .width('100%')
                    .height(45)
                    .padding({ left: 10, right: 10 })
                    .border({ width: 1, color: '#cccccc', radius: 8 })
                    .fontSize(14)
            }
            .width('100%')
            .padding(15)
            .backgroundColor('#ffffff')
            .borderRadius(10)
            .border({ width: 1, color: '#eeeeee' })
            .margin({ bottom: 20 })
            
            // 操作按钮
            Button('执行操作')
                .width('100%')
                .height(45)
                .fontSize(16)
                .fontWeight(FontWeight.Bold)
                .backgroundColor('#1B7837')
                .fontColor('#ffffff')
                .onClick(() => {
                    this.performOperation();
                })
                .margin({ bottom: 20 })
            
            // 结果显示
            if (this.showResult) {
                Column() {
                    Text('结果')
                        .fontSize(16)
                        .fontWeight(FontWeight.Bold)
                        .fontColor('#FFFFFF')
                        .width('100%')
                        .padding(12)
                        .backgroundColor('#1B7837')
                        .borderRadius(8)
                        .margin({ bottom: 12 })
                    
                    Scroll() {
                        Text(this.result)
                            .fontSize(14)
                            .fontColor('#333333')
                            .width('100%')
                            .padding(12)
                            .backgroundColor('#f9f9f9')
                            .borderRadius(6)
                            .textAlign(TextAlign.Start)
                            .selectable(true)
                    }
                    .width('100%')
                    .height(120)
                }
                .width('100%')
                .padding(15)
                .backgroundColor('#ffffff')
                .borderRadius(10)
                .border({ width: 1, color: '#eeeeee' })
            }
            
            Blank()
        }
        .width('100%')
        .height('100%')
        .padding(15)
        .backgroundColor('#f5f5f5')
        .scrollable(ScrollDirection.Vertical)
    }
}

ArkTS 代码说明: ArkTS 调用代码展示了如何在 OpenHarmony 应用中使用速度转换工具。页面包含操作类型选择、源单位和目标单位选择、输入框、操作按钮和结果显示等功能。通过 @State 装饰器管理状态,实现了完整的用户交互流程。用户可以选择操作类型和速度单位,输入速度值,然后点击执行按钮获得结果。


实战案例

案例1:导航应用

在导航应用中,需要根据用户所在地区显示不同的速度单位。

fun displaySpeed(meterPerSecond: Double, region: String): Map<String, String> {
    val converter = SpeedConverter()
    
    return when (region) {
        "US" -> mapOf(
            "speed" to converter.formatSpeed(converter.convertBetweenSystems(meterPerSecond, "m/s", "mph"), "mph"),
            "description" to converter.describeSpeed(meterPerSecond),
            "emoji" to converter.getSpeedEmoji(meterPerSecond)
        )
        "UK" -> mapOf(
            "speed" to converter.formatSpeed(converter.convertBetweenSystems(meterPerSecond, "m/s", "mph"), "mph"),
            "description" to converter.describeSpeed(meterPerSecond),
            "emoji" to converter.getSpeedEmoji(meterPerSecond)
        )
        else -> mapOf(
            "speed" to converter.formatSpeed(converter.convertBetweenSystems(meterPerSecond, "m/s", "km/h"), "km/h"),
            "description" to converter.describeSpeed(meterPerSecond),
            "emoji" to converter.getSpeedEmoji(meterPerSecond)
        )
    }
}

案例2:运动健身

在运动健身应用中,需要记录和分析运动速度。

fun analyzeRunningSpeed(speeds: List<Double>, unit: String): Map<String, Any> {
    val converter = SpeedConverter()
    
    val analysis = converter.analyzeSpeeds(speeds, unit)
    
    return mapOf(
        "count" to analysis["count"],
        "maxSpeed" to converter.formatSpeed(analysis["max"] as Double, unit),
        "minSpeed" to converter.formatSpeed(analysis["min"] as Double, unit),
        "averageSpeed" to converter.formatSpeed((analysis["average"] as String).toDouble(), unit),
        "medianSpeed" to converter.formatSpeed(analysis["median"] as Double, unit)
    )
}

案例3:气象预报

在气象预报应用中,需要显示风速信息。

fun displayWindSpeed(meterPerSecond: Double): Map<String, String> {
    val converter = SpeedConverter()
    
    val kmh = converter.convertBetweenSystems(meterPerSecond, "m/s", "km/h")
    val mph = converter.convertBetweenSystems(meterPerSecond, "m/s", "mph")
    
    return mapOf(
        "meterPerSecond" to converter.formatSpeed(meterPerSecond, "m/s"),
        "kilometerPerHour" to converter.formatSpeed(kmh, "km/h"),
        "milePerHour" to converter.formatSpeed(mph, "mph"),
        "description" to converter.describeSpeed(meterPerSecond),
        "emoji" to converter.getSpeedEmoji(meterPerSecond)
    )
}

最佳实践

1. 速度验证

始终验证速度值是否为正数且在合理范围内。

2. 精度管理

根据应用需求选择合适的精度。运动应用需要更高的精度。

3. 单位明确

始终明确显示速度单位,避免用户混淆。

4. 系统一致

在同一应用中保持速度单位的一致性。

5. 用户体验

提供速度描述和 emoji,提高用户体验。

6. 错误处理

提供清晰的错误消息,帮助用户理解问题。


总结

速度单位转换工具是现代应用开发中的重要组件。通过 KMP 框架,我们可以创建一个跨端的速度转换系统,在 Kotlin、JavaScript 和 ArkTS 中使用相同的转换逻辑。这不仅提高了代码的可维护性,还确保了不同平台上转换结果的一致性。

在实际应用中,合理使用速度转换工具可以提高应用的国际化程度和用户体验。无论是导航应用、运动健身还是气象预报,速度转换工具都能发挥重要作用。通过提供完整的速度转换功能和人性化的速度描述,我们可以帮助用户更好地理解和使用速度数据。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐