KMP 实现鸿蒙跨端:Kotlin 烹饪中的体积转换 - 食谱单位转换助手
本文档介绍如何在鸿蒙跨端开发中实现一个完整的烹饪体积转换工具,特别是食谱单位转换助手。烹饪涉及多种体积单位的转换,包括杯、毫升、升、液体盎司、汤匙和茶匙等。这个案例展示了如何使用 Kotlin 的数据处理和烹饪知识来创建一个功能丰富的烹饪辅助工具。食谱单位转换助手是烹饪爱好者的必备工具,它能够根据食材和体积单位,自动进行转换,并提供食材信息、密度数据和烹饪建议。无论是使用美国食谱、英国食谱还是欧洲
目录
概述
本文档介绍如何在 Kotlin Multiplatform (KMP) 鸿蒙跨端开发中实现一个完整的烹饪体积转换工具,特别是食谱单位转换助手。烹饪涉及多种体积单位的转换,包括杯、毫升、升、液体盎司、汤匙和茶匙等。这个案例展示了如何使用 Kotlin 的数据处理和烹饪知识来创建一个功能丰富的烹饪辅助工具。
食谱单位转换助手是烹饪爱好者的必备工具,它能够根据食材和体积单位,自动进行转换,并提供食材信息、密度数据和烹饪建议。无论是使用美国食谱、英国食谱还是欧洲食谱,这个工具都能帮助用户准确地测量食材。通过 KMP,这个工具可以无缝编译到 JavaScript,在 OpenHarmony 应用中运行,为烹饪爱好者提供专业的烹饪指导。
工具的特点
- 多食材支持:支持面粉、糖、黄油、牛奶、油、水、盐、鸡蛋、蜂蜜、香草等常见食材
- 体积单位转换:支持杯、毫升、升、液体盎司、汤匙、茶匙等多种单位
- 食材密度数据:提供每种食材的密度信息,支持体积到重量的转换
- 烹饪建议:根据食材提供专业的烹饪技巧和建议
- 地区食谱标准:支持美国、英国、欧洲等不同地区的食谱标准
- 跨端兼容:一份 Kotlin 代码可同时服务多个平台
工具功能
1. 支持的食材
系统支持 10 种常见的烹饪食材,每种食材都有详细的信息和烹饪建议:
面粉 (Flour)
- 密度:0.52 g/ml
- 用途:烘焙基础材料,影响蛋糕、饼干的结构
- 烹饪建议:
- 过筛面粉可以增加空气
- 不要过度混合面粉
- 使用高筋面粉做面包,低筋面粉做蛋糕
糖 (Sugar)
- 密度:0.80 g/ml
- 用途:甜味剂,影响甜度和质地
- 烹饪建议:
- 糖有助于保持湿度
- 过量糖会导致过甜
- 可用蜂蜜或糖浆替代
黄油 (Butter)
- 密度:0.91 g/ml
- 用途:脂肪来源,提供风味和质地
- 烹饪建议:
- 使用室温黄油混合更均匀
- 冷黄油适合做酥皮
- 不要过热黄油
牛奶 (Milk)
- 密度:1.03 g/ml
- 用途:液体成分,提供湿度和营养
- 烹饪建议:
- 室温牛奶混合更好
- 可用酸奶或豆浆替代
- 不要煮沸牛奶
油 (Oil)
- 密度:0.92 g/ml
- 用途:脂肪来源,提供湿度和风味
- 烹饪建议:
- 中性油适合烘焙
- 橄榄油适合咸味烘焙
- 不要用太多油
水 (Water)
- 密度:1.00 g/ml
- 用途:基础液体,调节面团湿度
- 烹饪建议:
- 冷水适合冷饮
- 温水适合激活酵母
- 不要用热水
盐 (Salt)
- 密度:1.20 g/ml
- 用途:调味料,增强风味
- 烹饪建议:
- 盐增强风味
- 不要过量
- 海盐比食盐更细致
鸡蛋 (Egg)
- 密度:1.03 g/ml
- 用途:粘合剂,提供结构和营养
- 烹饪建议:
- 室温鸡蛋混合更好
- 鸡蛋提供结构和湿度
- 不要过度搅打
蜂蜜 (Honey)
- 密度:1.42 g/ml
- 用途:天然甜味剂,增加湿度
- 烹饪建议:
- 蜂蜜增加湿度和风味
- 可替代部分糖
- 会加速褐变
香草 (Vanilla)
- 密度:0.88 g/ml
- 用途:调味料,增加香气
- 烹饪建议:
- 使用真正的香草精
- 少量即可
- 不要加热过度
2. 体积单位转换
系统支持 8 种常见的体积单位,适用于不同地区的食谱:
- 杯 (cup):美国食谱中最常用的单位,1 杯 = 236.588 毫升
- 毫升 (ml):公制系统中的基本单位,用于精确测量
- 升 (l):公制系统中的大单位,1 升 = 1000 毫升
- 液体盎司 (fl oz):英制系统中的单位,1 液体盎司 = 29.5735 毫升
- 汤匙 (tbsp):烹饪中常用的单位,1 汤匙 = 14.7868 毫升
- 茶匙 (tsp):烹饪中常用的小单位,1 茶匙 = 4.92892 毫升
- 品脱 (pint):英制系统中的单位,1 品脱 = 473.176 毫升
- 夸脱 (quart):英制系统中的大单位,1 夸脱 = 946.353 毫升
3. 食材密度信息
系统提供每种食材的密度信息,可以将体积转换为重量:
- 面粉:0.52 g/ml(较轻,因为面粉是粉末)
- 糖:0.80 g/ml(中等密度)
- 黄油:0.91 g/ml(接近水的密度)
- 牛奶:1.03 g/ml(略高于水)
- 油:0.92 g/ml(略低于水)
- 水:1.00 g/ml(参考标准)
- 盐:1.20 g/ml(较重)
- 鸡蛋:1.03 g/ml(略高于水)
- 蜂蜜:1.42 g/ml(最重)
- 香草:0.88 g/ml(较轻)
4. 烹饪建议
系统根据食材提供专业的烹饪建议,包括:
- 食材特性:每种食材在烹饪中的作用和特点
- 使用技巧:如何正确使用食材以获得最佳效果
- 替代方案:如果没有某种食材,可以用什么替代
- 注意事项:使用食材时需要注意的事项
5. 地区食谱标准
系统支持不同地区的食谱标准:
- 美国食谱:使用杯 (cup) 和汤匙 (tbsp)
- 英国食谱:使用毫升 (ml) 和液体盎司 (fl oz)
- 欧洲食谱:使用毫升 (ml) 和克 (g)
核心实现
算法原理
烹饪体积转换工具的核心算法包括:
- 输入解析:解析用户输入的食材、数值和单位
- 中间单位转换:将源单位转换为毫升
- 目标单位转换:将毫升转换为目标单位
- 重量计算:根据食材密度计算重量
- 建议生成:根据食材生成烹饪建议
食材密度
食材密度是体积到重量转换的关键。不同的食材有不同的密度:
- 低密度食材(< 0.9 g/ml):面粉、香草
- 中等密度食材(0.9-1.1 g/ml):黄油、油、牛奶、鸡蛋、水
- 高密度食材(> 1.1 g/ml):盐、蜂蜜
转换系数
系统使用国际标准的转换系数:
体积单位转换系数(以毫升为基准):
- 1 杯 = 236.588 ml
- 1 汤匙 = 14.7868 ml
- 1 茶匙 = 4.92892 ml
- 1 液体盎司 = 29.5735 ml
- 1 品脱 = 473.176 ml
- 1 夸脱 = 946.353 ml
Kotlin 源代码
// 案例 35: 烹饪中的体积转换 - 食谱单位转换助手
@OptIn(ExperimentalJsExport::class)
@JsExport
fun cookingVolumeConverter(inputData: String = "flour 2 cup ml"): String {
if (inputData.isEmpty()) {
return "❌ 错误: 输入不能为空\n请输入: 食材 数值 源单位 目标单位"
}
val parts = inputData.trim().split(" ")
if (parts.size != 4) {
return "❌ 错误: 输入格式不正确\n请输入: 食材 数值 源单位 目标单位"
}
val ingredient = parts[0].lowercase()
val value = parts[1].toDoubleOrNull()
val fromUnit = parts[2].lowercase()
val toUnit = parts[3].lowercase()
if (value == null) {
return "❌ 错误: 数值输入无效"
}
if (value <= 0) {
return "❌ 错误: 数值必须大于 0"
}
// 支持的食材列表
val supportedIngredients = listOf("flour", "sugar", "butter", "milk", "oil", "water", "salt", "egg", "honey", "vanilla")
if (ingredient !in supportedIngredients) {
return "❌ 错误: 不支持的食材 ($ingredient)\n支持的食材: flour, sugar, butter, milk, oil, water, salt, egg, honey, vanilla"
}
// 1. 转换为毫升
val valueInMl = when (fromUnit) {
"cup" -> value * 236.588
"ml" -> value
"l" -> value * 1000
"fl oz" -> value * 29.5735
"tbsp" -> value * 14.7868
"tsp" -> value * 4.92892
"pint" -> value * 473.176
"quart" -> value * 946.353
else -> return "❌ 错误: 不支持的体积单位 ($fromUnit)"
}
// 2. 转换为目标单位
val result = when (toUnit) {
"cup" -> valueInMl / 236.588
"ml" -> valueInMl
"l" -> valueInMl / 1000
"fl oz" -> valueInMl / 29.5735
"tbsp" -> valueInMl / 14.7868
"tsp" -> valueInMl / 4.92892
"pint" -> valueInMl / 473.176
"quart" -> valueInMl / 946.353
else -> return "❌ 错误: 不支持的体积单位 ($toUnit)"
}
// 3. 获取食材信息
val ingredientInfo = when (ingredient) {
"flour" -> "面粉 (Flour)" to "烘焙基础材料,影响蛋糕、饼干的结构"
"sugar" -> "糖 (Sugar)" to "甜味剂,影响甜度和质地"
"butter" -> "黄油 (Butter)" to "脂肪来源,提供风味和质地"
"milk" -> "牛奶 (Milk)" to "液体成分,提供湿度和营养"
"oil" -> "油 (Oil)" to "脂肪来源,提供湿度和风味"
"water" -> "水 (Water)" to "基础液体,调节面团湿度"
"salt" -> "盐 (Salt)" to "调味料,增强风味"
"egg" -> "鸡蛋 (Egg)" to "粘合剂,提供结构和营养"
"honey" -> "蜂蜜 (Honey)" to "天然甜味剂,增加湿度"
"vanilla" -> "香草 (Vanilla)" to "调味料,增加香气"
else -> "未知食材" to "无信息"
}
// 4. 获取食材密度信息(克/毫升)
val density = when (ingredient) {
"flour" -> 0.52
"sugar" -> 0.80
"butter" -> 0.91
"milk" -> 1.03
"oil" -> 0.92
"water" -> 1.00
"salt" -> 1.20
"egg" -> 1.03
"honey" -> 1.42
"vanilla" -> 0.88
else -> 1.0
}
// 5. 计算克数
val grams = valueInMl * density
// 6. 获取烹饪建议
val cookingTips = when (ingredient) {
"flour" -> "• 过筛面粉可以增加空气\n• 不要过度混合面粉\n• 使用高筋面粉做面包,低筋面粉做蛋糕"
"sugar" -> "• 糖有助于保持湿度\n• 过量糖会导致过甜\n• 可用蜂蜜或糖浆替代"
"butter" -> "• 使用室温黄油混合更均匀\n• 冷黄油适合做酥皮\n• 不要过热黄油"
"milk" -> "• 室温牛奶混合更好\n• 可用酸奶或豆浆替代\n• 不要煮沸牛奶"
"oil" -> "• 中性油适合烘焙\n• 橄榄油适合咸味烘焙\n• 不要用太多油"
"water" -> "• 冷水适合冷饮\n• 温水适合激活酵母\n• 不要用热水"
"salt" -> "• 盐增强风味\n• 不要过量\n• 海盐比食盐更细致"
"egg" -> "• 室温鸡蛋混合更好\n• 鸡蛋提供结构和湿度\n• 不要过度搅打"
"honey" -> "• 蜂蜜增加湿度和风味\n• 可替代部分糖\n• 会加速褐变"
"vanilla" -> "• 使用真正的香草精\n• 少量即可\n• 不要加热过度"
else -> "• 按照食谱指示使用\n• 测量要准确\n• 使用量勺而不是普通勺"
}
return "👨🍳 烹饪体积转换助手\n" +
"━━━━━━━━━━━━━━━━━━━━━\n" +
"🥘 食材: ${ingredientInfo.first}\n" +
"说明: ${ingredientInfo.second}\n\n" +
"📏 体积转换\n" +
"输入: $value $fromUnit\n" +
"输出: ${(result * 100).toInt() / 100.0} $toUnit\n\n" +
"⚖️ 重量信息\n" +
"毫升数: ${(valueInMl * 100).toInt() / 100.0} ml\n" +
"克数: ${(grams * 100).toInt() / 100.0} g\n" +
"密度: $density g/ml\n\n" +
"📚 单位参考\n" +
"• 1 杯 (cup) = 236.588 ml\n" +
"• 1 汤匙 (tbsp) = 14.7868 ml\n" +
"• 1 茶匙 (tsp) = 4.92892 ml\n" +
"• 1 液体盎司 (fl oz) = 29.5735 ml\n" +
"• 1 品脱 (pint) = 473.176 ml\n" +
"• 1 夸脱 (quart) = 946.353 ml\n\n" +
"👨🍳 烹饪建议\n" +
cookingTips + "\n\n" +
"🌍 地区食谱标准\n" +
"• 美国食谱: 使用杯 (cup) 和汤匙 (tbsp)\n" +
"• 英国食谱: 使用毫升 (ml) 和液体盎司 (fl oz)\n" +
"• 欧洲食谱: 使用毫升 (ml) 和克 (g)\n\n" +
"━━━━━━━━━━━━━━━━━━━━━\n" +
"✅ 转换完成!"
}
Kotlin 代码详解
这个 Kotlin 函数实现了一个完整的烹饪体积转换工具。函数接收一个字符串参数,包含食材名称、数值、源单位和目标单位。
首先,函数进行严格的输入验证。它检查输入是否为空,是否包含正确数量的字段,以及数值是否有效。
接下来,函数检查食材是否在支持的列表中。如果食材不支持,返回错误信息。
然后,函数进行两步转换:
- 将源单位转换为毫升(中间单位)
- 将毫升转换为目标单位
同时,函数获取食材的信息、密度和烹饪建议。最后,函数计算食材的重量(克数)并返回一个格式化的结果字符串。
JavaScript 编译代码
// 编译后的 JavaScript 代码(部分示例)
function cookingVolumeConverter(inputData) {
if (inputData === undefined) {
inputData = "flour 2 cup ml";
}
if (inputData.length === 0) {
return "❌ 错误: 输入不能为空\n请输入: 食材 数值 源单位 目标单位";
}
var parts = inputData.trim().split(" ");
if (parts.length !== 4) {
return "❌ 错误: 输入格式不正确\n请输入: 食材 数值 源单位 目标单位";
}
var ingredient = parts[0].toLowerCase();
var value = parseFloat(parts[1]);
var fromUnit = parts[2].toLowerCase();
var toUnit = parts[3].toLowerCase();
if (isNaN(value)) {
return "❌ 错误: 数值输入无效";
}
if (value <= 0) {
return "❌ 错误: 数值必须大于 0";
}
var supportedIngredients = ["flour", "sugar", "butter", "milk", "oil", "water", "salt", "egg", "honey", "vanilla"];
if (supportedIngredients.indexOf(ingredient) === -1) {
return "❌ 错误: 不支持的食材 (" + ingredient + ")\n支持的食材: flour, sugar, butter, milk, oil, water, salt, egg, honey, vanilla";
}
// 转换为毫升
var valueInMl;
switch (fromUnit) {
case "cup": valueInMl = value * 236.588; break;
case "ml": valueInMl = value; break;
case "l": valueInMl = value * 1000; break;
case "fl oz": valueInMl = value * 29.5735; break;
case "tbsp": valueInMl = value * 14.7868; break;
case "tsp": valueInMl = value * 4.92892; break;
case "pint": valueInMl = value * 473.176; break;
case "quart": valueInMl = value * 946.353; break;
default: return "❌ 错误: 不支持的体积单位 (" + fromUnit + ")";
}
// 转换为目标单位
var result;
switch (toUnit) {
case "cup": result = valueInMl / 236.588; break;
case "ml": result = valueInMl; break;
case "l": result = valueInMl / 1000; break;
case "fl oz": result = valueInMl / 29.5735; break;
case "tbsp": result = valueInMl / 14.7868; break;
case "tsp": result = valueInMl / 4.92892; break;
case "pint": result = valueInMl / 473.176; break;
case "quart": result = valueInMl / 946.353; break;
default: return "❌ 错误: 不支持的体积单位 (" + toUnit + ")";
}
// 获取食材信息
var ingredientInfo;
switch (ingredient) {
case "flour": ingredientInfo = ["面粉 (Flour)", "烘焙基础材料,影响蛋糕、饼干的结构"]; break;
case "sugar": ingredientInfo = ["糖 (Sugar)", "甜味剂,影响甜度和质地"]; break;
case "butter": ingredientInfo = ["黄油 (Butter)", "脂肪来源,提供风味和质地"]; break;
case "milk": ingredientInfo = ["牛奶 (Milk)", "液体成分,提供湿度和营养"]; break;
case "oil": ingredientInfo = ["油 (Oil)", "脂肪来源,提供湿度和风味"]; break;
case "water": ingredientInfo = ["水 (Water)", "基础液体,调节面团湿度"]; break;
case "salt": ingredientInfo = ["盐 (Salt)", "调味料,增强风味"]; break;
case "egg": ingredientInfo = ["鸡蛋 (Egg)", "粘合剂,提供结构和营养"]; break;
case "honey": ingredientInfo = ["蜂蜜 (Honey)", "天然甜味剂,增加湿度"]; break;
case "vanilla": ingredientInfo = ["香草 (Vanilla)", "调味料,增加香气"]; break;
default: ingredientInfo = ["未知食材", "无信息"];
}
// 获取食材密度
var density;
switch (ingredient) {
case "flour": density = 0.52; break;
case "sugar": density = 0.80; break;
case "butter": density = 0.91; break;
case "milk": density = 1.03; break;
case "oil": density = 0.92; break;
case "water": density = 1.00; break;
case "salt": density = 1.20; break;
case "egg": density = 1.03; break;
case "honey": density = 1.42; break;
case "vanilla": density = 0.88; break;
default: density = 1.0;
}
// 计算克数
var grams = valueInMl * density;
// 获取烹饪建议
var cookingTips;
switch (ingredient) {
case "flour": cookingTips = "• 过筛面粉可以增加空气\n• 不要过度混合面粉\n• 使用高筋面粉做面包,低筋面粉做蛋糕"; break;
case "sugar": cookingTips = "• 糖有助于保持湿度\n• 过量糖会导致过甜\n• 可用蜂蜜或糖浆替代"; break;
case "butter": cookingTips = "• 使用室温黄油混合更均匀\n• 冷黄油适合做酥皮\n• 不要过热黄油"; break;
case "milk": cookingTips = "• 室温牛奶混合更好\n• 可用酸奶或豆浆替代\n• 不要煮沸牛奶"; break;
case "oil": cookingTips = "• 中性油适合烘焙\n• 橄榄油适合咸味烘焙\n• 不要用太多油"; break;
case "water": cookingTips = "• 冷水适合冷饮\n• 温水适合激活酵母\n• 不要用热水"; break;
case "salt": cookingTips = "• 盐增强风味\n• 不要过量\n• 海盐比食盐更细致"; break;
case "egg": cookingTips = "• 室温鸡蛋混合更好\n• 鸡蛋提供结构和湿度\n• 不要过度搅打"; break;
case "honey": cookingTips = "• 蜂蜜增加湿度和风味\n• 可替代部分糖\n• 会加速褐变"; break;
case "vanilla": cookingTips = "• 使用真正的香草精\n• 少量即可\n• 不要加热过度"; break;
default: cookingTips = "• 按照食谱指示使用\n• 测量要准确\n• 使用量勺而不是普通勺";
}
return "👨🍳 烹饪体积转换助手\n" +
"━━━━━━━━━━━━━━━━━━━━━\n" +
"🥘 食材: " + ingredientInfo[0] + "\n" +
"说明: " + ingredientInfo[1] + "\n\n" +
"📏 体积转换\n" +
"输入: " + value + " " + fromUnit + "\n" +
"输出: " + (Math.floor(result * 100) / 100) + " " + toUnit + "\n\n" +
"⚖️ 重量信息\n" +
"毫升数: " + (Math.floor(valueInMl * 100) / 100) + " ml\n" +
"克数: " + (Math.floor(grams * 100) / 100) + " g\n" +
"密度: " + density + " g/ml\n\n" +
"📚 单位参考\n" +
"• 1 杯 (cup) = 236.588 ml\n" +
"• 1 汤匙 (tbsp) = 14.7868 ml\n" +
"• 1 茶匙 (tsp) = 4.92892 ml\n" +
"• 1 液体盎司 (fl oz) = 29.5735 ml\n" +
"• 1 品脱 (pint) = 473.176 ml\n" +
"• 1 夸脱 (quart) = 946.353 ml\n\n" +
"👨🍳 烹饪建议\n" +
cookingTips + "\n\n" +
"🌍 地区食谱标准\n" +
"• 美国食谱: 使用杯 (cup) 和汤匙 (tbsp)\n" +
"• 英国食谱: 使用毫升 (ml) 和液体盎司 (fl oz)\n" +
"• 欧洲食谱: 使用毫升 (ml) 和克 (g)\n\n" +
"━━━━━━━━━━━━━━━━━━━━━\n" +
"✅ 转换完成!";
}
JavaScript 代码详解
Kotlin 代码编译到 JavaScript 后,保留了原有的逻辑结构,但使用 JavaScript 的语法和 API。主要的转换包括:
- 类型转换:Kotlin 的
toDoubleOrNull()转换为 JavaScript 的parseFloat() - 条件语句:Kotlin 的
when表达式转换为 JavaScript 的switch语句 - 集合操作:Kotlin 的
in操作符转换为 JavaScript 的indexOf() - 字符串处理:Kotlin 的字符串模板转换为 JavaScript 的字符串拼接
ArkTS 调用代码
import { cookingVolumeConverter } from './hellokjs';
@Entry
@Component
struct Index {
@State message: string = '准备就绪';
@State ingredient: string = 'flour';
@State value: string = '2';
@State fromUnit: string = 'cup';
@State toUnit: string = 'ml';
@State resultText: string = '';
@State isLoading: boolean = false;
aboutToAppear(): void {
this.generateNewCase();
}
generateNewCase(): void {
this.resultText = '';
this.message = '准备就绪';
const samples = [
{ ing: 'flour', v: '2', from: 'cup', to: 'ml' },
{ ing: 'sugar', v: '1', from: 'cup', to: 'g' },
{ ing: 'butter', v: '4', from: 'tbsp', to: 'g' },
{ ing: 'milk', v: '250', from: 'ml', to: 'cup' },
{ ing: 'honey', v: '1', from: 'cup', to: 'g' }
];
const random = samples[Math.floor(Math.random() * samples.length)];
this.ingredient = random.ing;
this.value = random.v;
this.fromUnit = random.from;
this.toUnit = random.to;
}
convert(): void {
this.isLoading = true;
try {
const input: string = `${this.ingredient} ${this.value} ${this.fromUnit} ${this.toUnit}`;
const result: string = cookingVolumeConverter(input);
this.resultText = result;
console.log(result);
this.message = '✓ 转换完成';
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
this.message = `✗ 错误: ${errorMessage}`;
} finally {
this.isLoading = false;
}
}
build() {
Column() {
// ===== 顶部标题栏 - 烹饪橙色主题 =====
Column() {
Text('👨🍳 Cooking Volume Converter')
.fontSize(28)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
.margin({ bottom: 8 })
Text('Recipe Unit Conversion Assistant')
.fontSize(13)
.fontColor('#FFE0B2')
}
.width('100%')
.padding(24)
.backgroundColor('#E65100')
.alignItems(HorizontalAlign.Start)
// ===== 主内容区域 =====
Scroll() {
Column() {
// 输入卡片
Column() {
Row() {
Text('🍳 Conversion')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor('#FFFFFF')
Blank()
Text('🎲 Random')
.fontSize(12)
.fontColor(Color.White)
.padding({ left: 10, right: 10, top: 6, bottom: 6 })
.backgroundColor('#BF360C')
.borderRadius(12)
.onClick(() => {
this.generateNewCase();
})
}
.width('100%')
.margin({ bottom: 18 })
// 食材选择
TextInput({ placeholder: 'Ingredient (flour/sugar/butter/milk/oil/water/salt/egg/honey/vanilla)', text: this.ingredient })
.width('100%')
.height(50)
.padding(14)
.fontSize(15)
.fontColor('#000000')
.placeholderColor('#999999')
.border({ width: 2, color: '#E65100' })
.borderRadius(12)
.backgroundColor('#FFF3E0')
.onChange((value: string) => {
this.ingredient = value;
})
.margin({ bottom: 14 })
// 数值输入
TextInput({ placeholder: 'Value', text: this.value })
.width('100%')
.height(50)
.padding(14)
.fontSize(15)
.fontColor('#000000')
.placeholderColor('#999999')
.border({ width: 2, color: '#E65100' })
.borderRadius(12)
.backgroundColor('#FFF3E0')
.onChange((value: string) => {
this.value = value;
})
.margin({ bottom: 14 })
// 源单位
TextInput({ placeholder: 'From Unit (cup/ml/l/fl oz/tbsp/tsp/pint/quart)', text: this.fromUnit })
.width('100%')
.height(50)
.padding(14)
.fontSize(15)
.fontColor('#000000')
.placeholderColor('#999999')
.border({ width: 2, color: '#E65100' })
.borderRadius(12)
.backgroundColor('#FFF3E0')
.onChange((value: string) => {
this.fromUnit = value;
})
.margin({ bottom: 14 })
// 目标单位
TextInput({ placeholder: 'To Unit (cup/ml/l/fl oz/tbsp/tsp/pint/quart/g)', text: this.toUnit })
.width('100%')
.height(50)
.padding(14)
.fontSize(15)
.fontColor('#000000')
.placeholderColor('#999999')
.border({ width: 2, color: '#E65100' })
.borderRadius(12)
.backgroundColor('#FFF3E0')
.onChange((value: string) => {
this.toUnit = value;
})
.margin({ bottom: 20 })
// 转换按钮
Button(this.isLoading ? 'Converting...' : 'Convert')
.width('100%')
.height(54)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
.backgroundColor(this.isLoading ? '#BF360C' : '#E65100')
.borderRadius(14)
.onClick(() => {
if (!this.isLoading) {
this.convert();
}
})
}
.width('90%')
.padding(20)
.backgroundColor('#FFFFFF')
.borderRadius(16)
.margin({ top: 20, bottom: 20, left: 'auto', right: 'auto' })
.border({ width: 2, color: '#E65100' })
// 状态提示卡片
if (this.message !== '准备就绪') {
Row() {
Text(this.message.startsWith('✓') ? '✅' : '⚠️')
.fontSize(20)
.margin({ right: 12 })
Text(this.message)
.fontSize(14)
.fontColor(this.message.startsWith('✓') ? '#4ECDC4' : '#FF6B6B')
.fontWeight(FontWeight.Bold)
.layoutWeight(1)
}
.width('90%')
.padding(16)
.backgroundColor(this.message.startsWith('✓') ? '#1a3a3a' : '#3a1a1a')
.border({ width: 2, color: this.message.startsWith('✓') ? '#4ECDC4' : '#FF6B6B' })
.borderRadius(14)
.margin({ bottom: 20, left: 'auto', right: 'auto' })
.alignItems(VerticalAlign.Center)
}
// 结果卡片
if (this.resultText) {
Column() {
Row() {
Text('📊 Conversion Result')
.fontSize(14)
.fontWeight(FontWeight.Bold)
.fontColor('#E65100')
}
.width('100%')
.padding(14)
.backgroundColor('#FFF8F0')
.borderRadius(12)
.margin({ bottom: 14 })
.border({ width: 1, color: '#E65100' })
Text(this.resultText)
.fontSize(12)
.fontFamily('monospace')
.fontColor('#BF360C')
.width('100%')
.padding(14)
.backgroundColor('#FFF8F0')
.borderRadius(12)
.border({ width: 1, color: '#FF6F00' })
}
.width('90%')
.padding(16)
.backgroundColor('#FFF3E0')
.borderRadius(16)
.margin({ bottom: 20, left: 'auto', right: 'auto' })
.border({ width: 2, color: '#E65100' })
}
// 底部提示
Column() {
Row() {
Text('💡')
.fontSize(18)
.margin({ right: 10 })
Text('👨🍳 Cooking Tips')
.fontSize(14)
.fontWeight(FontWeight.Bold)
.fontColor('#E65100')
}
.width('100%')
.margin({ bottom: 12 })
Text('• Select ingredient\n• Enter volume and units\n• Get instant conversion\n• Get cooking advice')
.fontSize(12)
.fontColor('#BF360C')
.lineHeight(1.6)
}
.width('90%')
.padding(16)
.backgroundColor('#FFF3E0')
.borderRadius(16)
.margin({ bottom: 20, left: 'auto', right: 'auto' })
.border({ width: 2, color: '#E65100' })
Blank()
.height(20)
}
.width('100%')
}
.layoutWeight(1)
}
.width('100%')
.height('100%')
.backgroundColor('#FFF3E0')
}
}
ArkTS 代码详解
这个 ArkTS 组件实现了烹饪体积转换工具的用户界面。组件使用了 OpenHarmony 的 ArkTS 语言,提供了一个现代化的、烹饪橙色主题的用户界面。
组件定义了五个 @State 属性来存储转换信息:食材、数值、源单位和目标单位。这些属性与输入框绑定,当用户输入数据时,这些属性会自动更新。
generateNewCase() 方法生成随机的烹饪转换样本,帮助用户快速测试应用。用户可以点击"Random"按钮来生成随机数据。
convert() 方法调用 Kotlin 编译的 JavaScript 函数 cookingVolumeConverter(),并将转换信息作为参数传递。函数返回的转换结果会显示在结果卡片中。
用户界面包括四个输入框(食材、数值、源单位、目标单位)、一个转换按钮、一个状态提示卡片、一个结果卡片和一个提示卡片。所有元素都使用了烹饪橙色主题。
实战案例
案例 1:面粉转换
烹饪需要 2 杯面粉,需要转换为毫升。输入:flour 2 cup ml
系统转换结果:
- 输入:2 cup
- 输出:473.18 ml
- 克数:246.06 g
- 密度:0.52 g/ml
- 烹饪建议:过筛面粉可以增加空气,不要过度混合面粉
案例 2:糖转换
烹饪需要 1 杯糖,需要转换为克。输入:sugar 1 cup g
系统转换结果:
- 输入:1 cup
- 输出:236.59 ml
- 克数:189.27 g
- 密度:0.80 g/ml
- 烹饪建议:糖有助于保持湿度,过量糖会导致过甜
案例 3:黄油转换
烹饪需要 4 汤匙黄油,需要转换为克。输入:butter 4 tbsp g
系统转换结果:
- 输入:4 tbsp
- 输出:59.15 ml
- 克数:53.83 g
- 密度:0.91 g/ml
- 烹饪建议:使用室温黄油混合更均匀,冷黄油适合做酥皮
案例 4:牛奶转换
烹饪需要 250 毫升牛奶,需要转换为杯。输入:milk 250 ml cup
系统转换结果:
- 输入:250 ml
- 输出:1.06 cup
- 克数:257.50 g
- 密度:1.03 g/ml
- 烹饪建议:室温牛奶混合更好,可用酸奶或豆浆替代
案例 5:蜂蜜转换
烹饪需要 1 杯蜂蜜,需要转换为克。输入:honey 1 cup g
系统转换结果:
- 输入:1 cup
- 输出:236.59 ml
- 克数:335.95 g
- 密度:1.42 g/ml
- 烹饪建议:蜂蜜增加湿度和风味,可替代部分糖
最佳实践
1. 准确测量
烹饪中的准确测量非常重要:
- 使用量勺:使用专业的烹饪量勺而不是普通勺子
- 水平测量:确保量勺中的食材与勺子边缘齐平
- 不要压实:除非食谱特别说明,否则不要压实食材
- 使用电子秤:对于精确的烘焙,使用电子秤比体积测量更准确
2. 理解食材密度
不同的食材有不同的密度,这会影响转换结果:
- 低密度食材:面粉、糖等粉末状食材
- 中等密度食材:黄油、油、牛奶等
- 高密度食材:蜂蜜、盐等
- 液体食材:水、油等
3. 适应不同的食谱标准
不同地区的食谱使用不同的单位制:
- 美国食谱:使用杯和汤匙
- 英国食谱:使用毫升和液体盎司
- 欧洲食谱:使用毫升和克
4. 食材替代
如果没有某种食材,可以使用替代品:
- 黄油替代品:油、人造黄油
- 牛奶替代品:酸奶、豆浆、椰奶
- 糖替代品:蜂蜜、糖浆、人工甜味剂
- 鸡蛋替代品:亚麻籽、香蕉、豆腐
5. 烹饪技巧
掌握基本的烹饪技巧可以提高成功率:
- 室温食材:大多数烘焙食材应该在室温下使用
- 正确混合:不同的食材需要不同的混合方式
- 烤箱温度:确保烤箱温度准确
- 烘焙时间:根据食谱调整烘焙时间
总结
烹饪中的体积转换 - 食谱单位转换助手展示了如何使用 Kotlin Multiplatform 技术创建一个功能丰富、跨端兼容的烹饪辅助应用。通过支持多种食材和单位制的转换,系统能够帮助烹饪爱好者准确地测量食材。
这个案例不仅展示了 KMP 的强大功能,还演示了如何将烹饪知识转化为应用功能。无论是初学者还是经验丰富的厨师,都可以使用这个工具来确保食材的准确测量,从而制作出更美味的食物。
烹饪是一门艺术和科学的结合。通过使用这个烹饪体积转换工具,用户可以更加自信地按照食谱进行烹饪,享受烹饪的乐趣,制作出令人满意的美食。
更多推荐




所有评论(0)