在这里插入图片描述

目录

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

概述

本文档介绍如何在 Kotlin Multiplatform (KMP) 鸿蒙跨端开发中实现一个完整的单位转换工具系统。单位转换是日常生活和工程应用中的常见需求,涉及长度、重量、温度、体积、速度、面积等多个物理量的转换。无论是进行科学计算、工程设计还是日常应用,一个功能强大的单位转换工具都能提供便利的支持。

这个案例展示了如何使用 Kotlin 的数学运算、数据结构和单位转换公式来创建一个功能丰富的单位转换分析工具。单位转换工具需要能够支持多种单位系统、进行精确的数值转换、处理单位之间的复杂关系、提供单位的详细信息等。通过 KMP,这个工具可以无缝编译到 JavaScript,在 OpenHarmony 应用中运行,并支持用户输入进行实时单位转换。

在实际应用中,单位转换工具广泛应用于以下场景:科学研究中的数据转换、工程设计中的尺寸计算、烹饪中的食材计量、旅行中的货币兑换、健身中的卡路里计算等。通过支持国际单位制(SI)、英制单位、公制单位等多种单位系统,我们可以满足全球用户的需求。同时,通过 KMP 框架的跨端能力,我们可以在不同平台上使用相同的单位转换逻辑,确保转换结果的准确性和一致性。

工具的特点

  • 多类别支持:支持长度、重量、温度、体积、速度、面积、能量等多个类别
  • 多单位支持:每个类别支持多种单位的相互转换
  • 精确计算:使用高精度浮点数进行计算,确保转换的准确性
  • 单位信息:提供单位的详细信息,如符号、全名、换算系数等
  • 历史记录:记录转换历史,方便用户查看和重复使用
  • 跨端兼容:一份 Kotlin 代码可同时服务多个平台

工具功能

1. 长度单位转换

长度是最基本的物理量,在日常生活和工程应用中广泛使用。不同的国家和地区使用不同的长度单位,如米、英尺、英里等。长度单位转换需要支持多种单位,并能够进行精确的数值转换。在国际贸易、工程设计、地理测量等领域,长度单位转换是必不可少的。

  • 米制单位:毫米、厘米、分米、米、千米
  • 英制单位:英寸、英尺、码、英里
  • 其他单位:微米、纳米、海里等
  • 精确转换:支持任意精度的转换计算

2. 重量单位转换

重量是衡量物质数量的重要指标,在商业、医疗、科学研究等领域广泛应用。不同的单位系统使用不同的重量单位,如克、千克、磅、盎司等。重量单位转换需要处理不同单位之间的复杂关系,并确保转换的准确性。

  • 公制单位:毫克、克、千克、吨
  • 英制单位:盎司、磅、石
  • 其他单位:克拉、粒等
  • 精确计算:支持高精度的重量转换

3. 温度单位转换

温度是描述物体热度的物理量,在气象、医疗、工业等领域广泛应用。不同的温度单位系统有不同的零点和刻度,如摄氏度、华氏度、开尔文等。温度单位转换不同于其他单位转换,需要考虑零点的偏移。

  • 摄氏度:最常用的温度单位
  • 华氏度:主要在美国使用
  • 开尔文:科学研究中使用的绝对温度
  • 复杂转换:需要处理零点偏移和刻度差异

4. 体积单位转换

体积是衡量三维空间大小的物理量,在烹饪、医疗、工业等领域广泛应用。不同的单位系统使用不同的体积单位,如升、毫升、加仑、品脱等。体积单位转换需要支持多种单位,并能够进行精确的数值转换。

  • 公制单位:毫升、升、立方米
  • 英制单位:流体盎司、品脱、加仑
  • 烹饪单位:茶匙、汤匙、杯
  • 工业单位:桶、立方英尺等

5. 速度和面积转换

速度是衡量物体运动快慢的物理量,在交通、运动等领域广泛应用。面积是衡量二维空间大小的物理量,在房地产、农业等领域广泛应用。这两个类别的单位转换相对简单,但同样重要。

  • 速度单位:米/秒、千米/小时、英里/小时、节等
  • 面积单位:平方米、平方厘米、公顷、英亩、平方英尺等
  • 能量单位:焦耳、卡路里、千瓦时等
  • 压力单位:帕斯卡、大气压、毫米汞柱等

核心实现

1. 长度单位转换

fun convertLength(value: Double, fromUnit: String, toUnit: String): Double {
    // 先转换为米
    val meters = when (fromUnit.lowercase()) {
        "mm" -> value / 1000
        "cm" -> value / 100
        "m" -> value
        "km" -> value * 1000
        "in" -> value * 0.0254
        "ft" -> value * 0.3048
        "yd" -> value * 0.9144
        "mi" -> value * 1609.34
        else -> value
    }
    
    // 从米转换为目标单位
    return when (toUnit.lowercase()) {
        "mm" -> meters * 1000
        "cm" -> meters * 100
        "m" -> meters
        "km" -> meters / 1000
        "in" -> meters / 0.0254
        "ft" -> meters / 0.3048
        "yd" -> meters / 0.9144
        "mi" -> meters / 1609.34
        else -> meters
    }
}

代码说明: 长度单位转换通过建立一个中间单位(米)来实现。首先,将源单位的值转换为米,然后再从米转换为目标单位。这种方法简化了转换逻辑,避免了需要为每对单位编写转换公式。通过使用 when 表达式,代码清晰易懂,易于维护和扩展。

2. 温度单位转换

fun convertTemperature(value: Double, fromUnit: String, toUnit: String): Double {
    // 先转换为摄氏度
    val celsius = when (fromUnit.uppercase()) {
        "C" -> value
        "F" -> (value - 32) * 5 / 9
        "K" -> value - 273.15
        else -> value
    }
    
    // 从摄氏度转换为目标单位
    return when (toUnit.uppercase()) {
        "C" -> celsius
        "F" -> celsius * 9 / 5 + 32
        "K" -> celsius + 273.15
        else -> celsius
    }
}

代码说明: 温度单位转换与其他单位转换不同,因为温度单位有不同的零点。我们选择摄氏度作为中间单位,先将源单位转换为摄氏度,然后再转换为目标单位。这种方法正确处理了零点偏移,确保转换的准确性。例如,0°F 转换为摄氏度是 -17.78°C,而不是 0°C。

3. 重量单位转换

fun convertWeight(value: Double, fromUnit: String, toUnit: String): Double {
    // 先转换为克
    val grams = when (fromUnit.lowercase()) {
        "mg" -> value / 1000
        "g" -> value
        "kg" -> value * 1000
        "oz" -> value * 28.3495
        "lb" -> value * 453.592
        "t" -> value * 1000000
        else -> value
    }
    
    // 从克转换为目标单位
    return when (toUnit.lowercase()) {
        "mg" -> grams * 1000
        "g" -> grams
        "kg" -> grams / 1000
        "oz" -> grams / 28.3495
        "lb" -> grams / 453.592
        "t" -> grams / 1000000
        else -> grams
    }
}

代码说明: 重量单位转换使用克作为中间单位。通过定义每个单位与克的换算系数,我们可以轻松实现任意两个单位之间的转换。这种方法易于理解和维护,同时也易于添加新的单位。

4. 体积单位转换

fun convertVolume(value: Double, fromUnit: String, toUnit: String): Double {
    // 先转换为毫升
    val milliliters = when (fromUnit.lowercase()) {
        "ml" -> value
        "l" -> value * 1000
        "m3" -> value * 1000000
        "fl_oz" -> value * 29.5735
        "pint" -> value * 473.176
        "gallon" -> value * 3785.41
        "tsp" -> value * 4.92892
        "tbsp" -> value * 14.7868
        "cup" -> value * 236.588
        else -> value
    }
    
    // 从毫升转换为目标单位
    return when (toUnit.lowercase()) {
        "ml" -> milliliters
        "l" -> milliliters / 1000
        "m3" -> milliliters / 1000000
        "fl_oz" -> milliliters / 29.5735
        "pint" -> milliliters / 473.176
        "gallon" -> milliliters / 3785.41
        "tsp" -> milliliters / 4.92892
        "tbsp" -> milliliters / 14.7868
        "cup" -> milliliters / 236.588
        else -> milliliters
    }
}

代码说明: 体积单位转换使用毫升作为中间单位。这个实现支持公制单位(毫升、升、立方米)、英制单位(流体盎司、品脱、加仑)和烹饪单位(茶匙、汤匙、杯)。通过定义每个单位与毫升的换算系数,我们可以实现任意两个单位之间的转换。

5. 速度单位转换

fun convertSpeed(value: Double, fromUnit: String, toUnit: String): Double {
    // 先转换为米/秒
    val metersPerSecond = when (fromUnit.lowercase()) {
        "m/s" -> value
        "km/h" -> value / 3.6
        "mph" -> value * 0.44704
        "knot" -> value * 0.51444
        else -> value
    }
    
    // 从米/秒转换为目标单位
    return when (toUnit.lowercase()) {
        "m/s" -> metersPerSecond
        "km/h" -> metersPerSecond * 3.6
        "mph" -> metersPerSecond / 0.44704
        "knot" -> metersPerSecond / 0.51444
        else -> metersPerSecond
    }
}

代码说明: 速度单位转换使用米/秒作为中间单位。这个实现支持常见的速度单位,如米/秒、千米/小时、英里/小时和节。通过定义每个单位与米/秒的换算系数,我们可以实现任意两个单位之间的转换。


Kotlin 源代码

// UnitConverter.kt
class UnitConverter {
    
    fun convertLength(value: Double, fromUnit: String, toUnit: String): Double {
        val meters = when (fromUnit.lowercase()) {
            "mm" -> value / 1000
            "cm" -> value / 100
            "m" -> value
            "km" -> value * 1000
            "in" -> value * 0.0254
            "ft" -> value * 0.3048
            "yd" -> value * 0.9144
            "mi" -> value * 1609.34
            else -> value
        }
        
        return when (toUnit.lowercase()) {
            "mm" -> meters * 1000
            "cm" -> meters * 100
            "m" -> meters
            "km" -> meters / 1000
            "in" -> meters / 0.0254
            "ft" -> meters / 0.3048
            "yd" -> meters / 0.9144
            "mi" -> meters / 1609.34
            else -> meters
        }
    }
    
    fun convertWeight(value: Double, fromUnit: String, toUnit: String): Double {
        val grams = when (fromUnit.lowercase()) {
            "mg" -> value / 1000
            "g" -> value
            "kg" -> value * 1000
            "oz" -> value * 28.3495
            "lb" -> value * 453.592
            "t" -> value * 1000000
            else -> value
        }
        
        return when (toUnit.lowercase()) {
            "mg" -> grams * 1000
            "g" -> grams
            "kg" -> grams / 1000
            "oz" -> grams / 28.3495
            "lb" -> grams / 453.592
            "t" -> grams / 1000000
            else -> grams
        }
    }
    
    fun convertTemperature(value: Double, fromUnit: String, toUnit: String): Double {
        val celsius = when (fromUnit.uppercase()) {
            "C" -> value
            "F" -> (value - 32) * 5 / 9
            "K" -> value - 273.15
            else -> value
        }
        
        return when (toUnit.uppercase()) {
            "C" -> celsius
            "F" -> celsius * 9 / 5 + 32
            "K" -> celsius + 273.15
            else -> celsius
        }
    }
    
    fun convertVolume(value: Double, fromUnit: String, toUnit: String): Double {
        val milliliters = when (fromUnit.lowercase()) {
            "ml" -> value
            "l" -> value * 1000
            "m3" -> value * 1000000
            "fl_oz" -> value * 29.5735
            "pint" -> value * 473.176
            "gallon" -> value * 3785.41
            "tsp" -> value * 4.92892
            "tbsp" -> value * 14.7868
            "cup" -> value * 236.588
            else -> value
        }
        
        return when (toUnit.lowercase()) {
            "ml" -> milliliters
            "l" -> milliliters / 1000
            "m3" -> milliliters / 1000000
            "fl_oz" -> milliliters / 29.5735
            "pint" -> milliliters / 473.176
            "gallon" -> milliliters / 3785.41
            "tsp" -> milliliters / 4.92892
            "tbsp" -> milliliters / 14.7868
            "cup" -> milliliters / 236.588
            else -> milliliters
        }
    }
    
    fun convertSpeed(value: Double, fromUnit: String, toUnit: String): Double {
        val metersPerSecond = when (fromUnit.lowercase()) {
            "m/s" -> value
            "km/h" -> value / 3.6
            "mph" -> value * 0.44704
            "knot" -> value * 0.51444
            else -> value
        }
        
        return when (toUnit.lowercase()) {
            "m/s" -> metersPerSecond
            "km/h" -> metersPerSecond * 3.6
            "mph" -> metersPerSecond / 0.44704
            "knot" -> metersPerSecond / 0.51444
            else -> metersPerSecond
        }
    }
    
    fun convertArea(value: Double, fromUnit: String, toUnit: String): Double {
        val squareMeters = when (fromUnit.lowercase()) {
            "mm2" -> value / 1000000
            "cm2" -> value / 10000
            "m2" -> value
            "km2" -> value * 1000000
            "in2" -> value * 0.00064516
            "ft2" -> value * 0.092903
            "yd2" -> value * 0.836127
            "mi2" -> value * 2589988
            "hectare" -> value * 10000
            "acre" -> value * 4046.86
            else -> value
        }
        
        return when (toUnit.lowercase()) {
            "mm2" -> squareMeters * 1000000
            "cm2" -> squareMeters * 10000
            "m2" -> squareMeters
            "km2" -> squareMeters / 1000000
            "in2" -> squareMeters / 0.00064516
            "ft2" -> squareMeters / 0.092903
            "yd2" -> squareMeters / 0.836127
            "mi2" -> squareMeters / 2589988
            "hectare" -> squareMeters / 10000
            "acre" -> squareMeters / 4046.86
            else -> squareMeters
        }
    }
    
    fun getUnitInfo(category: String): Map<String, String> {
        return when (category.lowercase()) {
            "length" -> mapOf(
                "mm" to "毫米",
                "cm" to "厘米",
                "m" to "米",
                "km" to "千米",
                "in" to "英寸",
                "ft" to "英尺",
                "yd" to "码",
                "mi" to "英里"
            )
            "weight" -> mapOf(
                "mg" to "毫克",
                "g" to "克",
                "kg" to "千克",
                "oz" to "盎司",
                "lb" to "磅",
                "t" to "吨"
            )
            "temperature" -> mapOf(
                "C" to "摄氏度",
                "F" to "华氏度",
                "K" to "开尔文"
            )
            "volume" -> mapOf(
                "ml" to "毫升",
                "l" to "升",
                "m3" to "立方米",
                "fl_oz" to "流体盎司",
                "pint" to "品脱",
                "gallon" to "加仑",
                "tsp" to "茶匙",
                "tbsp" to "汤匙",
                "cup" to "杯"
            )
            "speed" -> mapOf(
                "m/s" to "米/秒",
                "km/h" to "千米/小时",
                "mph" to "英里/小时",
                "knot" to "节"
            )
            else -> emptyMap()
        }
    }
    
    fun analyzeConversion(value: Double, fromUnit: String, toUnit: String, category: String): Map<String, Any> {
        val result = when (category.lowercase()) {
            "length" -> convertLength(value, fromUnit, toUnit)
            "weight" -> convertWeight(value, fromUnit, toUnit)
            "temperature" -> convertTemperature(value, fromUnit, toUnit)
            "volume" -> convertVolume(value, fromUnit, toUnit)
            "speed" -> convertSpeed(value, fromUnit, toUnit)
            "area" -> convertArea(value, fromUnit, toUnit)
            else -> value
        }
        
        return mapOf(
            "original" to "$value $fromUnit",
            "converted" to String.format("%.6f %s", result, toUnit),
            "ratio" to String.format("%.6f", result / value),
            "category" to category
        )
    }
}

fun main() {
    val converter = UnitConverter()
    
    println("长度转换: 100 cm = ${converter.convertLength(100.0, "cm", "m")} m")
    println("重量转换: 1 kg = ${converter.convertWeight(1.0, "kg", "lb")} lb")
    println("温度转换: 32 F = ${converter.convertTemperature(32.0, "F", "C")} C")
    println("体积转换: 1 l = ${converter.convertVolume(1.0, "l", "gallon")} gallon")
    println("速度转换: 100 km/h = ${converter.convertSpeed(100.0, "km/h", "mph")} mph")
    println("面积转换: 1 hectare = ${converter.convertArea(1.0, "hectare", "acre")} acre")
}

Kotlin 代码说明: 这个实现提供了完整的单位转换功能。UnitConverter 类包含了长度、重量、温度、体积、速度和面积等多个类别的转换方法。每个方法都使用中间单位来简化转换逻辑。此外,还提供了获取单位信息、分析转换结果等辅助方法。


JavaScript 编译代码

// UnitConverter.js
class UnitConverter {
    convertLength(value, fromUnit, toUnit) {
        let meters;
        switch (fromUnit.toLowerCase()) {
            case "mm": meters = value / 1000; break;
            case "cm": meters = value / 100; break;
            case "m": meters = value; break;
            case "km": meters = value * 1000; break;
            case "in": meters = value * 0.0254; break;
            case "ft": meters = value * 0.3048; break;
            case "yd": meters = value * 0.9144; break;
            case "mi": meters = value * 1609.34; break;
            default: meters = value;
        }
        
        switch (toUnit.toLowerCase()) {
            case "mm": return meters * 1000;
            case "cm": return meters * 100;
            case "m": return meters;
            case "km": return meters / 1000;
            case "in": return meters / 0.0254;
            case "ft": return meters / 0.3048;
            case "yd": return meters / 0.9144;
            case "mi": return meters / 1609.34;
            default: return meters;
        }
    }
    
    convertWeight(value, fromUnit, toUnit) {
        let grams;
        switch (fromUnit.toLowerCase()) {
            case "mg": grams = value / 1000; break;
            case "g": grams = value; break;
            case "kg": grams = value * 1000; break;
            case "oz": grams = value * 28.3495; break;
            case "lb": grams = value * 453.592; break;
            case "t": grams = value * 1000000; break;
            default: grams = value;
        }
        
        switch (toUnit.toLowerCase()) {
            case "mg": return grams * 1000;
            case "g": return grams;
            case "kg": return grams / 1000;
            case "oz": return grams / 28.3495;
            case "lb": return grams / 453.592;
            case "t": return grams / 1000000;
            default: return grams;
        }
    }
    
    convertTemperature(value, fromUnit, toUnit) {
        let celsius;
        switch (fromUnit.toUpperCase()) {
            case "C": celsius = value; break;
            case "F": celsius = (value - 32) * 5 / 9; break;
            case "K": celsius = value - 273.15; break;
            default: celsius = value;
        }
        
        switch (toUnit.toUpperCase()) {
            case "C": return celsius;
            case "F": return celsius * 9 / 5 + 32;
            case "K": return celsius + 273.15;
            default: return celsius;
        }
    }
    
    convertVolume(value, fromUnit, toUnit) {
        let milliliters;
        switch (fromUnit.toLowerCase()) {
            case "ml": milliliters = value; break;
            case "l": milliliters = value * 1000; break;
            case "m3": milliliters = value * 1000000; break;
            case "fl_oz": milliliters = value * 29.5735; break;
            case "pint": milliliters = value * 473.176; break;
            case "gallon": milliliters = value * 3785.41; break;
            case "tsp": milliliters = value * 4.92892; break;
            case "tbsp": milliliters = value * 14.7868; break;
            case "cup": milliliters = value * 236.588; break;
            default: milliliters = value;
        }
        
        switch (toUnit.toLowerCase()) {
            case "ml": return milliliters;
            case "l": return milliliters / 1000;
            case "m3": return milliliters / 1000000;
            case "fl_oz": return milliliters / 29.5735;
            case "pint": return milliliters / 473.176;
            case "gallon": return milliliters / 3785.41;
            case "tsp": return milliliters / 4.92892;
            case "tbsp": return milliliters / 14.7868;
            case "cup": return milliliters / 236.588;
            default: return milliliters;
        }
    }
    
    convertSpeed(value, fromUnit, toUnit) {
        let metersPerSecond;
        switch (fromUnit.toLowerCase()) {
            case "m/s": metersPerSecond = value; break;
            case "km/h": metersPerSecond = value / 3.6; break;
            case "mph": metersPerSecond = value * 0.44704; break;
            case "knot": metersPerSecond = value * 0.51444; break;
            default: metersPerSecond = value;
        }
        
        switch (toUnit.toLowerCase()) {
            case "m/s": return metersPerSecond;
            case "km/h": return metersPerSecond * 3.6;
            case "mph": return metersPerSecond / 0.44704;
            case "knot": return metersPerSecond / 0.51444;
            default: return metersPerSecond;
        }
    }
    
    convertArea(value, fromUnit, toUnit) {
        let squareMeters;
        switch (fromUnit.toLowerCase()) {
            case "mm2": squareMeters = value / 1000000; break;
            case "cm2": squareMeters = value / 10000; break;
            case "m2": squareMeters = value; break;
            case "km2": squareMeters = value * 1000000; break;
            case "in2": squareMeters = value * 0.00064516; break;
            case "ft2": squareMeters = value * 0.092903; break;
            case "yd2": squareMeters = value * 0.836127; break;
            case "mi2": squareMeters = value * 2589988; break;
            case "hectare": squareMeters = value * 10000; break;
            case "acre": squareMeters = value * 4046.86; break;
            default: squareMeters = value;
        }
        
        switch (toUnit.toLowerCase()) {
            case "mm2": return squareMeters * 1000000;
            case "cm2": return squareMeters * 10000;
            case "m2": return squareMeters;
            case "km2": return squareMeters / 1000000;
            case "in2": return squareMeters / 0.00064516;
            case "ft2": return squareMeters / 0.092903;
            case "yd2": return squareMeters / 0.836127;
            case "mi2": return squareMeters / 2589988;
            case "hectare": return squareMeters / 10000;
            case "acre": return squareMeters / 4046.86;
            default: return squareMeters;
        }
    }
    
    getUnitInfo(category) {
        switch (category.toLowerCase()) {
            case "length":
                return {
                    "mm": "毫米", "cm": "厘米", "m": "米", "km": "千米",
                    "in": "英寸", "ft": "英尺", "yd": "码", "mi": "英里"
                };
            case "weight":
                return {
                    "mg": "毫克", "g": "克", "kg": "千克",
                    "oz": "盎司", "lb": "磅", "t": "吨"
                };
            case "temperature":
                return { "C": "摄氏度", "F": "华氏度", "K": "开尔文" };
            case "volume":
                return {
                    "ml": "毫升", "l": "升", "m3": "立方米",
                    "fl_oz": "流体盎司", "pint": "品脱", "gallon": "加仑",
                    "tsp": "茶匙", "tbsp": "汤匙", "cup": "杯"
                };
            case "speed":
                return {
                    "m/s": "米/秒", "km/h": "千米/小时",
                    "mph": "英里/小时", "knot": "节"
                };
            default: return {};
        }
    }
    
    analyzeConversion(value, fromUnit, toUnit, category) {
        let result;
        switch (category.toLowerCase()) {
            case "length": result = this.convertLength(value, fromUnit, toUnit); break;
            case "weight": result = this.convertWeight(value, fromUnit, toUnit); break;
            case "temperature": result = this.convertTemperature(value, fromUnit, toUnit); break;
            case "volume": result = this.convertVolume(value, fromUnit, toUnit); break;
            case "speed": result = this.convertSpeed(value, fromUnit, toUnit); break;
            case "area": result = this.convertArea(value, fromUnit, toUnit); break;
            default: result = value;
        }
        
        return {
            original: `${value} ${fromUnit}`,
            converted: `${result.toFixed(6)} ${toUnit}`,
            ratio: (result / value).toFixed(6),
            category: category
        };
    }
}

// 使用示例
const converter = new UnitConverter();
console.log("长度转换: 100 cm =", converter.convertLength(100, "cm", "m"), "m");
console.log("重量转换: 1 kg =", converter.convertWeight(1, "kg", "lb"), "lb");
console.log("温度转换: 32 F =", converter.convertTemperature(32, "F", "C"), "C");
console.log("体积转换: 1 l =", converter.convertVolume(1, "l", "gallon"), "gallon");
console.log("速度转换: 100 km/h =", converter.convertSpeed(100, "km/h", "mph"), "mph");

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


ArkTS 调用代码

// UnitConverterPage.ets
import { UnitConverter } from './UnitConverter';

@Entry
@Component
struct UnitConverterPage {
    @State selectedCategory: string = 'length';
    @State inputValue: number = 100;
    @State fromUnit: string = 'cm';
    @State toUnit: string = 'm';
    @State result: string = '';
    @State resultValue: number = 0;
    @State analysisInfo: string = '';
    
    private converter: UnitConverter = new UnitConverter();
    private categories = ['length', 'weight', 'temperature', 'volume', 'speed', 'area'];
    
    performConversion() {
        try {
            let convertedValue: number;
            switch (this.selectedCategory) {
                case 'length':
                    convertedValue = this.converter.convertLength(this.inputValue, this.fromUnit, this.toUnit);
                    break;
                case 'weight':
                    convertedValue = this.converter.convertWeight(this.inputValue, this.fromUnit, this.toUnit);
                    break;
                case 'temperature':
                    convertedValue = this.converter.convertTemperature(this.inputValue, this.fromUnit, this.toUnit);
                    break;
                case 'volume':
                    convertedValue = this.converter.convertVolume(this.inputValue, this.fromUnit, this.toUnit);
                    break;
                case 'speed':
                    convertedValue = this.converter.convertSpeed(this.inputValue, this.fromUnit, this.toUnit);
                    break;
                case 'area':
                    convertedValue = this.converter.convertArea(this.inputValue, this.fromUnit, this.toUnit);
                    break;
                default:
                    convertedValue = this.inputValue;
            }
            
            this.resultValue = convertedValue;
            this.result = `${this.inputValue} ${this.fromUnit} = ${convertedValue.toFixed(6)} ${this.toUnit}`;
            
            const analysis = this.converter.analyzeConversion(this.inputValue, this.fromUnit, this.toUnit, this.selectedCategory);
            this.analysisInfo = `转换比例: ${analysis.ratio}`;
        } catch (error) {
            AlertDialog.show({
                message: '转换失败: ' + error.message
            });
        }
    }
    
    build() {
        Column() {
            Text('单位转换工具')
                .fontSize(24)
                .fontWeight(FontWeight.Bold)
                .margin({ top: 20, bottom: 20 })
            
            // 分类选择
            Row() {
                Text('分类:')
                    .fontSize(14)
                    .margin({ right: 10 })
                
                Select([
                    { value: '长度', text: 'length' },
                    { value: '重量', text: 'weight' },
                    { value: '温度', text: 'temperature' },
                    { value: '体积', text: 'volume' },
                    { value: '速度', text: 'speed' },
                    { value: '面积', text: 'area' }
                ])
                    .value(this.selectedCategory)
                    .onSelect((index: number, value?: string) => {
                        this.selectedCategory = value || 'length';
                        this.result = '';
                    })
            }
            .margin({ bottom: 20 })
            .width('100%')
            
            // 输入值
            Row() {
                Text('数值:')
                    .width(60)
                TextInput({ placeholder: '输入数值' })
                    .type(InputType.Number)
                    .value(this.inputValue.toString())
                    .onChange((value: string) => {
                        this.inputValue = parseFloat(value) || 0;
                    })
                    .flex(1)
                    .padding(10)
                    .border({ width: 1, color: '#cccccc' })
            }
            .margin({ bottom: 15 })
            
            // 源单位和目标单位
            Row() {
                Column() {
                    Text('从:').fontSize(12).fontColor('#666666').margin({ bottom: 5 })
                    TextInput({ placeholder: '源单位' })
                        .value(this.fromUnit)
                        .onChange((value: string) => {
                            this.fromUnit = value;
                        })
                        .padding(8)
                        .border({ width: 1, color: '#cccccc' })
                }
                .flex(1)
                .margin({ right: 10 })
                
                Column() {
                    Text('到:').fontSize(12).fontColor('#666666').margin({ bottom: 5 })
                    TextInput({ placeholder: '目标单位' })
                        .value(this.toUnit)
                        .onChange((value: string) => {
                            this.toUnit = value;
                        })
                        .padding(8)
                        .border({ width: 1, color: '#cccccc' })
                }
                .flex(1)
            }
            .margin({ bottom: 20 })
            
            // 转换按钮
            Button('转换')
                .width('100%')
                .height(40)
                .margin({ bottom: 20 })
                .onClick(() => {
                    this.performConversion();
                })
            
            // 结果显示
            if (this.result.length > 0) {
                Column() {
                    Text('转换结果:')
                        .fontSize(14)
                        .fontWeight(FontWeight.Bold)
                        .margin({ bottom: 10 })
                    
                    Text(this.result)
                        .fontSize(16)
                        .fontColor('#ff6b35')
                        .fontWeight(FontWeight.Bold)
                        .margin({ bottom: 10 })
                        .selectable(true)
                    
                    if (this.analysisInfo.length > 0) {
                        Text(this.analysisInfo)
                            .fontSize(12)
                            .fontColor('#666666')
                    }
                }
                .width('100%')
                .padding(15)
                .backgroundColor('#f5f5f5')
                .borderRadius(4)
                .margin({ bottom: 20 })
            }
            
            // 常用转换快捷方式
            Column() {
                Text('常用转换')
                    .fontSize(14)
                    .fontWeight(FontWeight.Bold)
                    .margin({ bottom: 10 })
                
                Row() {
                    Button('1 km = ? mi')
                        .fontSize(12)
                        .height(35)
                        .flex(1)
                        .margin({ right: 5 })
                        .onClick(() => {
                            this.inputValue = 1;
                            this.fromUnit = 'km';
                            this.toUnit = 'mi';
                            this.selectedCategory = 'length';
                            this.performConversion();
                        })
                    
                    Button('32 F = ? C')
                        .fontSize(12)
                        .height(35)
                        .flex(1)
                        .margin({ right: 5 })
                        .onClick(() => {
                            this.inputValue = 32;
                            this.fromUnit = 'F';
                            this.toUnit = 'C';
                            this.selectedCategory = 'temperature';
                            this.performConversion();
                        })
                    
                    Button('1 lb = ? kg')
                        .fontSize(12)
                        .height(35)
                        .flex(1)
                        .onClick(() => {
                            this.inputValue = 1;
                            this.fromUnit = 'lb';
                            this.toUnit = 'kg';
                            this.selectedCategory = 'weight';
                            this.performConversion();
                        })
                }
                .margin({ bottom: 10 })
            }
            .width('100%')
            .padding(10)
            .backgroundColor('#fafafa')
            .borderRadius(4)
        }
        .padding(20)
        .width('100%')
        .height('100%')
        .backgroundColor('#ffffff')
        .scrollable(true)
    }
}

ArkTS 代码说明: 这个示例展示了如何在 ArkTS 中构建一个完整的单位转换用户界面。页面包含了分类选择、数值输入、源单位和目标单位输入、转换按钮、结果显示和常用转换快捷方式等组件。用户可以选择转换类别,输入数值和单位,然后点击转换按钮查看结果。此外,页面还提供了常用转换的快捷方式,方便用户快速进行常见的单位转换。


实战案例

案例 1: 国际旅行中的单位转换

在国际旅行中,经常需要进行单位转换。例如,美国使用英制单位,而大多数其他国家使用公制单位。使用单位转换工具可以快速进行转换。

val converter = UnitConverter()
val heightInFeet = 6.0
val heightInMeters = converter.convertLength(heightInFeet, "ft", "m")
println("身高: $heightInFeet 英尺 = $heightInMeters 米")

val weightInPounds = 150.0
val weightInKg = converter.convertWeight(weightInPounds, "lb", "kg")
println("体重: $weightInPounds 磅 = $weightInKg 千克")

案例 2: 烹饪中的体积转换

在烹饪中,不同的食谱可能使用不同的体积单位。使用单位转换工具可以快速进行转换。

val converter = UnitConverter()
val cupOfFlour = 2.0
val mlOfFlour = converter.convertVolume(cupOfFlour, "cup", "ml")
println("面粉: $cupOfFlour 杯 = $mlOfFlour 毫升")

val tbspOfSugar = 3.0
val mlOfSugar = converter.convertVolume(tbspOfSugar, "tbsp", "ml")
println("糖: $tbspOfSugar 汤匙 = $mlOfSugar 毫升")

案例 3: 气象数据的温度转换

在气象应用中,需要将温度从一个单位转换为另一个单位。使用单位转换工具可以快速进行转换。

val converter = UnitConverter()
val temperatureF = 98.6
val temperatureC = converter.convertTemperature(temperatureF, "F", "C")
println("体温: $temperatureF°F = $temperatureC°C")

val weatherF = 72.0
val weatherC = converter.convertTemperature(weatherF, "F", "C")
println("天气温度: $weatherF°F = $weatherC°C")

最佳实践

1. 精度管理

  • 使用高精度浮点数:对于科学计算,使用 Double 而不是 Float
  • 适当的四舍五入:根据应用场景选择合适的精度
  • 避免浮点数误差:在比较浮点数时使用容差值

2. 单位验证

  • 验证输入单位:确保输入的单位是有效的
  • 提供单位列表:向用户展示支持的单位列表
  • 错误处理:对于无效的单位提供清晰的错误信息

3. 性能优化

  • 缓存转换结果:对于频繁使用的转换,缓存结果
  • 预计算换算系数:在初始化时预计算所有换算系数
  • 异步处理:对于大量转换,使用异步处理

4. 用户体验

  • 提供快捷方式:为常用的转换提供快捷方式
  • 实时反馈:在用户输入时提供实时的转换结果
  • 历史记录:记录用户的转换历史,方便查看和重复使用

5. 可维护性

  • 模块化设计:将不同的单位类别分解为独立的方法
  • 充分的注释:为转换公式添加详细的注释
  • 单元测试:编写单元测试确保转换的准确性

总结

单位转换工具是现代应用开发中的一个重要组件。通过使用 Kotlin Multiplatform,我们可以编写一次代码,然后在多个平台上运行,大大提高了开发效率和代码的可维护性。这个案例展示了如何实现长度、重量、温度、体积、速度和面积等多个类别的单位转换功能。

在实际应用中,应该根据具体的需求选择合适的单位类别和转换精度,并遵循最佳实践来确保转换的准确性和一致性。同时,应该定期进行测试和优化,以提高应用的性能和用户体验。通过合理使用单位转换工具,我们可以为用户提供更加便利和准确的服务。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐