赞
踩
Layout_ability_main.xml布局:
<?xml version="1.0" encoding="utf-8"?> <DirectionalLayout xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:height="match_parent" ohos:width="match_parent" ohos:alignment="center" ohos:orientation="vertical"> <TextField ohos:id="$+id:content" ohos:height="0vp" ohos:weight="1" ohos:width="match_parent" ohos:enabled="false" ohos:padding="20vp" ohos:text="0" ohos:text_alignment="center" ohos:text_size="30"/> <ScrollView ohos:height="0vp" ohos:weight="1.8" ohos:width="match_parent"> <DirectionalLayout ohos:height="match_content" ohos:width="match_parent" ohos:alignment="horizontal_center" ohos:orientation="vertical"> <DirectionalLayout ohos:height="match_content" ohos:width="match_parent" ohos:orientation="horizontal"> <Button ohos:id="$+id:reset" ohos:height="70vp" ohos:width="0vp" ohos:background_element="$graphic:background_button2" ohos:margin="6vp" ohos:text="c" ohos:text_size="30vp" ohos:weight="1"/> <Button ohos:id="$+id:except" ohos:height="70vp" ohos:width="0vp" ohos:background_element="$graphic:background_button2" ohos:margin="6vp" ohos:text="÷" ohos:text_size="30vp" ohos:weight="1"/> <Button ohos:id="$+id:ride" ohos:height="70vp" ohos:width="0vp" ohos:background_element="$graphic:background_button2" ohos:margin="6vp" ohos:text="x" ohos:text_size="30vp" ohos:weight="1"/> <Button ohos:id="$+id:delete" ohos:height="70vp" ohos:width="0vp" ohos:background_element="$graphic:background_button2" ohos:margin="6vp" ohos:text="←" ohos:text_size="30vp" ohos:weight="1"/> </DirectionalLayout> <DirectionalLayout ohos:height="match_content" ohos:width="match_parent" ohos:orientation="horizontal"> <Button ohos:id="$+id:seven" ohos:height="70vp" ohos:width="0vp" ohos:background_element="$graphic:background_button1" ohos:margin="6vp" ohos:text="7" ohos:text_size="30vp" ohos:weight="1"/> <Button ohos:id="$+id:eight" ohos:height="70vp" ohos:width="0vp" ohos:background_element="$graphic:background_button1" ohos:margin="6vp" ohos:text="8" ohos:text_size="30vp" ohos:weight="1"/> <Button ohos:id="$+id:nine" ohos:height="70vp" ohos:width="0vp" ohos:background_element="$graphic:background_button1" ohos:margin="6vp" ohos:text="9" ohos:text_size="30vp" ohos:weight="1"/> <Button ohos:id="$+id:reduce" ohos:height="70vp" ohos:width="0vp" ohos:background_element="$graphic:background_button2" ohos:margin="6vp" ohos:text="-" ohos:text_size="30vp" ohos:weight="1"/> </DirectionalLayout> <DirectionalLayout ohos:height="match_content" ohos:width="match_parent" ohos:orientation="horizontal"> <Button ohos:id="$+id:four" ohos:height="70vp" ohos:width="0vp" ohos:background_element="$graphic:background_button1" ohos:margin="6vp" ohos:text="4" ohos:text_size="30vp" ohos:weight="1"/> <Button ohos:id="$+id:five" ohos:height="70vp" ohos:width="0vp" ohos:background_element="$graphic:background_button1" ohos:margin="6vp" ohos:text="5" ohos:text_size="30vp" ohos:weight="1"/> <Button ohos:id="$+id:six" ohos:height="70vp" ohos:width="0vp" ohos:background_element="$graphic:background_button1" ohos:margin="6vp" ohos:text="6" ohos:text_size="30vp" ohos:weight="1"/> <Button ohos:id="$+id:add" ohos:height="70vp" ohos:width="0vp" ohos:background_element="$graphic:background_button2" ohos:margin="6vp" ohos:text="+" ohos:text_size="30vp" ohos:weight="1"/> </DirectionalLayout> <DirectionalLayout ohos:height="match_content" ohos:width="match_parent" ohos:orientation="horizontal"> <Button ohos:id="$+id:one" ohos:height="70vp" ohos:width="0vp" ohos:background_element="$graphic:background_button1" ohos:margin="6vp" ohos:text="1" ohos:text_size="30vp" ohos:weight="1"/> <Button ohos:id="$+id:two" ohos:height="70vp" ohos:width="0vp" ohos:background_element="$graphic:background_button1" ohos:margin="6vp" ohos:text="2" ohos:text_size="30vp" ohos:weight="1"/> <Button ohos:id="$+id:three" ohos:height="70vp" ohos:width="0vp" ohos:background_element="$graphic:background_button1" ohos:margin="6vp" ohos:text="3" ohos:text_size="30vp" ohos:weight="1"/> <Button ohos:id="$+id:decimal_point" ohos:height="70vp" ohos:width="0vp" ohos:background_element="$graphic:background_button2" ohos:margin="6vp" ohos:text="." ohos:text_size="30vp" ohos:weight="1"/> </DirectionalLayout> <DirectionalLayout ohos:height="match_content" ohos:width="match_parent" ohos:orientation="horizontal"> <Button ohos:id="$+id:percentage" ohos:height="70vp" ohos:width="0vp" ohos:background_element="$graphic:background_button2" ohos:margin="6vp" ohos:text="%" ohos:text_size="30vp" ohos:weight="1"/> <Button ohos:id="$+id:zero" ohos:height="70vp" ohos:width="0vp" ohos:background_element="$graphic:background_button2" ohos:margin="6vp" ohos:text="0" ohos:text_size="30vp" ohos:weight="1"/> <Button ohos:id="$+id:equal" ohos:height="70vp" ohos:width="0vp" ohos:background_element="$graphic:background_button3" ohos:margin="6vp" ohos:text="=" ohos:text_size="30vp" ohos:weight="2"/> </DirectionalLayout> </DirectionalLayout> </ScrollView> </DirectionalLayout>
background_button1.xml背景样式:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:shape="rectangle">
<solid ohos:color="#CCF1F1F1"/>
<corners ohos:radius="20vp"/>
</shape>
background_button2.xml背景样式:
<shape
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:shape="rectangle">
<solid ohos:color="#FFE4F2FE"/>
<corners ohos:radius="20vp"/>
</shape>
background_button3.xml背景样式:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:shape="rectangle">
<solid ohos:color="#FF007CFD"/>
<corners ohos:radius="20vp"/>
</shape>
嗯,编写布局页面不难、稍微难点的是电视、车载设备、Pad、手机、手表五个端的屏幕适配。
界面编写完,发现各个端的屏幕高度还没有做适配,一开始认为Android与HarmonyOS用Java语言都可以编写,HarmonyOS也可以使用Android的相关框架,便想着如何在HarmonyOS上去使用Android的屏幕适配方案,在用了今日头条的屏幕适配方案开刀后,发现压根行不通,今日头条的屏幕适配方案用的单位是dp,这个单位在HarmonyOS上并没有,只有类似的vp,看来还是我太天真了。
Android屏幕单位有dp、in、mm、pt、px、sp,HarmonOS屏幕单位有fp、px、vp。
其中两者相同的单位是px,Android的dp与HarmonOS的vp都是为各自设备量身打造的单位,若想要搞一个两者都可以用的屏幕适配框架,也许,只能从px找突破口。今日头条的屏幕适配方案用的单位虽然是HarmonyOS所没有的dp,但其实它最终都是要拿dp来转换成px的喔~
继承AbilitySlice的MainAbilitySlice类:
public class MainAbilitySlice extends AbilitySlice implements Component.ClickedListener { private Utils utils = Utils.getInstance(); private TextField content; private String formula = ""; @Override public void onStart(Intent intent) { super.onStart(intent); super.setUIContent(ResourceTable.Layout_ability_main); initView(); highlyAdaptive(); } /** * 各个按钮点击事件 * @param component */ @Override public void onClick(Component component) { switch (component.getId()) { case ResourceTable.Id_one: if (utils.isNumStart(formula)) formula = utils.isZero(formula, "1"); else formula = "1"; break; case ResourceTable.Id_two: if (utils.isNumStart(formula)) formula = utils.isZero(formula, "2"); else formula = "2"; break; case ResourceTable.Id_three: if (utils.isNumStart(formula)) formula = utils.isZero(formula, "3"); else formula = "3"; break; case ResourceTable.Id_four: if (utils.isNumStart(formula)) formula = utils.isZero(formula, "4"); else formula = "4"; break; case ResourceTable.Id_five: if (utils.isNumStart(formula)) formula = utils.isZero(formula, "5"); else formula = "5"; break; case ResourceTable.Id_six: if (utils.isNumStart(formula)) formula = utils.isZero(formula, "6"); else formula = "6"; break; case ResourceTable.Id_seven: if (utils.isNumStart(formula)) formula = utils.isZero(formula, "7"); else formula = "7"; break; case ResourceTable.Id_eight: if (utils.isNumStart(formula)) formula = utils.isZero(formula, "8"); else formula = "8"; break; case ResourceTable.Id_nine: if (utils.isNumStart(formula)) formula = utils.isZero(formula, "9"); else formula = "9"; break; case ResourceTable.Id_zero: if (utils.isNumStart(formula)) formula = utils.isZero(formula, "0"); else formula = "0"; break; case ResourceTable.Id_reset: formula = "0"; break; case ResourceTable.Id_except: if (utils.isNumEnd(formula)) formula += "÷"; else if (!formula.substring(formula.length() - 1, formula.length()).equals(".")) formula = formula.substring(0, formula.length() - 1) + "÷"; break; case ResourceTable.Id_ride: formula = utils.isNum(formula, "x"); break; case ResourceTable.Id_percentage: formula = utils.isNum(formula, "%"); break; case ResourceTable.Id_decimal_point: if (utils.isNumEnd(formula) && !utils.isDecimals(formula)) formula += "."; break; case ResourceTable.Id_delete: if (!formula.equals("") && !formula.equals("0")) { formula = formula.substring(0, formula.length() - 1); if (formula.equals("")) formula = "0"; } break; case ResourceTable.Id_reduce: if (utils.isNumEnd(formula)) formula += "-"; else formula = formula.substring(0, formula.length() - 1) + "-"; break; case ResourceTable.Id_add: if (utils.isNumEnd(formula)) formula += "+"; else formula = formula.substring(0, formula.length() - 1) + "+"; break; case ResourceTable.Id_equal: equal(); break; default: break; } if (component.getId() != ResourceTable.Id_equal) { content.setText(formula); } } private void equal() { if (formula.equals("")) { // 如果没有输入公式 utils.toast(this, "还没输入公式呢"); return; } else if (!utils.isNumEnd(formula)) { // 如果公式的最后一位数非数字 utils.toast(this, "计算器表示没见过这样的数学公式,运算不出来"); return; } String[] split; if (!utils.isContains(formula, ".")) { // 计算整数 if (utils.isContains(formula, "-")) { // 减法 split = formula.split("-"); if (split.length > 1) result((Integer.parseInt(split[0]) + Integer.parseInt(split[1])) + ""); } else if (utils.isContains(formula, "+")) { // 加法 split = formula.split("\\+"); if (split.length > 1) result((Integer.parseInt(split[0]) + Integer.parseInt(split[1])) + ""); } else if (utils.isContains(formula, "x")) { // 乘法 split = formula.split("x"); if (split.length > 1) result((Integer.parseInt(split[0]) + Integer.parseInt(split[1])) + ""); } else if (utils.isContains(formula, "÷")) { // 除法 split = formula.split("÷"); if (split.length > 1) result((Integer.parseInt(split[0]) + Integer.parseInt(split[1])) + ""); } else if (utils.isContains(formula, "%")) { // 取余 split = formula.split("%"); if (split.length > 1) result((Integer.parseInt(split[0]) + Integer.parseInt(split[1])) + ""); } } else { // 计算小数 if (utils.isContains(formula, "-")) { // 减法 split = formula.split("-"); if (split.length > 1) result((Double.parseDouble(split[0]) - Double.parseDouble(split[1])) + ""); } else if (utils.isContains(formula, "+")) { // 加法 split = formula.split("\\+"); if (split.length > 1) result((Double.parseDouble(split[0]) - Double.parseDouble(split[1])) + ""); } else if (utils.isContains(formula, "x")) { // 乘法 split = formula.split("x"); if (split.length > 1) result((Double.parseDouble(split[0]) - Double.parseDouble(split[1])) + ""); } else if (utils.isContains(formula, "÷")) { // 除法` split = formula.split("÷"); if (split.length > 1) result((Double.parseDouble(split[0]) - Double.parseDouble(split[1])) + ""); } else if (utils.isContains(formula, "%")) { // 取余 split = formula.split("%"); if (split.length > 1) result((Double.parseDouble(split[0]) - Double.parseDouble(split[1])) + ""); } } } private void result(String value) { formula = value; content.setText(value); } /** * 根据不同设备调整高度 */ private void highlyAdaptive() { if (DeviceInfo.getDeviceType().equals("phone")) { // 手机设备 ComponentContainer.LayoutConfig layoutConfig = new ComponentContainer.LayoutConfig(); layoutConfig.height = 1100; content.setLayoutConfig(layoutConfig); } else if (DeviceInfo.getDeviceType().equals("tablet")) { // 平板设备 ComponentContainer.LayoutConfig layoutConfig = new ComponentContainer.LayoutConfig(); layoutConfig.height = 1200; content.setLayoutConfig(layoutConfig); } else if (DeviceInfo.getDeviceType().equals("tv")) { // TV设备 ComponentContainer.LayoutConfig layoutConfig = new ComponentContainer.LayoutConfig(); layoutConfig.height = 160; content.setLayoutConfig(layoutConfig); } else if (DeviceInfo.getDeviceType().equals("wearable")) { // 可穿戴设备 ComponentContainer.LayoutConfig layoutConfig = new ComponentContainer.LayoutConfig(); layoutConfig.height = 150; content.setLayoutConfig(layoutConfig); } else if (DeviceInfo.getDeviceType().equals("car")) { // 车载设备 ComponentContainer.LayoutConfig layoutConfig = new ComponentContainer.LayoutConfig(); layoutConfig.height = 500; content.setLayoutConfig(layoutConfig); } } /** * 初始化xml布局控件 */ private void initView() { content = (TextField) findComponentById(ResourceTable.Id_content); ((Button) findComponentById(ResourceTable.Id_one)).setClickedListener(this); ((Button) findComponentById(ResourceTable.Id_two)).setClickedListener(this); ((Button) findComponentById(ResourceTable.Id_three)).setClickedListener(this); ((Button) findComponentById(ResourceTable.Id_four)).setClickedListener(this); ((Button) findComponentById(ResourceTable.Id_five)).setClickedListener(this); ((Button) findComponentById(ResourceTable.Id_six)).setClickedListener(this); ((Button) findComponentById(ResourceTable.Id_seven)).setClickedListener(this); ((Button) findComponentById(ResourceTable.Id_eight)).setClickedListener(this); ((Button) findComponentById(ResourceTable.Id_nine)).setClickedListener(this); ((Button) findComponentById(ResourceTable.Id_zero)).setClickedListener(this); ((Button) findComponentById(ResourceTable.Id_reset)).setClickedListener(this); ((Button) findComponentById(ResourceTable.Id_except)).setClickedListener(this); ((Button) findComponentById(ResourceTable.Id_ride)).setClickedListener(this); ((Button) findComponentById(ResourceTable.Id_delete)).setClickedListener(this); ((Button) findComponentById(ResourceTable.Id_reduce)).setClickedListener(this); ((Button) findComponentById(ResourceTable.Id_add)).setClickedListener(this); ((Button) findComponentById(ResourceTable.Id_equal)).setClickedListener(this); ((Button) findComponentById(ResourceTable.Id_decimal_point)).setClickedListener(this); ((Button) findComponentById(ResourceTable.Id_percentage)).setClickedListener(this); } }
由于在编写xml UI时屏幕适配只能做到宽度适配或高度适配,没办法在一个xml界面同时适配宽度与高度,为此写了一个highlyAdaptive
方法处理xml没能完成的高度适配,方法通过DeviceInfo.getDeviceType()
来得到设备的类型,根据不同的设备去修改它的高度,也算是实现了高度适配。
Utils类:
public class Utils { private static Utils utils = new Utils(); private static ToastDialog toastDialog; private String[] symbol = new String[]{"+", "-", "x", "÷", "%"}; public static Utils getInstance() { return utils; } public void toast(Context context, String text) { if (toastDialog == null) { toastDialog = new ToastDialog(context); } toastDialog.setAlignment(LayoutAlignment.CENTER); toastDialog.setText(text); toastDialog.show(); } /** * 判断最后一位是否数字 * @param content */ public boolean isNumber(String content){ char[] chars = content.substring(content.length() - 1, content.length()).toCharArray(); return Character.isDigit(chars[0]); } /** * 判断是否是小数 */ public boolean isDecimals(String str) { if (isDecimal(str)) { for (String s : symbol) { if (isContains(str, s)) { String[] split = str.split(s); if (split != null){ if (!isDecimal(split[split.length - 1])) { return false; } else { return true; } } } } return true; } return false; } /** * 判断一位数是否是小数 */ public boolean isDecimal(String str) { if (isContains(str, ".")) return true; else return false; } /** * 是否包含某一个运算符 */ public boolean isContains(String value, String contain) { if (value.indexOf(contain) == -1) return false; else return true; } /** * 最后一个值是数字就加符号,不是数字则替换它 * @param str 符号 */ public String isNum(String content,String str) { if (isNumEnd(content)) content += str; else content = content.substring(0, content.length() - 1) + str; return content; } /** * 第一个值是0,输入整数则替换掉 */ public String isZero(String content,String str) { if (content.equals("0")) { content = str; } else { content += str; } return content; } /** * 得到第一个值是否是数字 */ public boolean isNumStart(String str) { if (str.startsWith("+") || str.startsWith("x") || str.startsWith("÷") || str.startsWith("%") || str.equals("")) { return false; } return true; } /** * 得到最后一个值是否是数字 */ public boolean isNumEnd(String str) { char[] chars = str.substring(str.length() - 1, str.length()).toCharArray(); if (!Character.isDigit(chars[chars.length - 1])) { return false; } return true; } }
Phone 设备实现效果
Pad 设备实现效果
TV 设备实现效果
Wearable 设备实现效果
目前所有设备中,Wearable是几个设备中最不好适配、最难适配的设备,但,想实现也并非不可能。
如果继续适配Wearable,目前能想到Wearable屏幕适配的方法有三种:
1、需要将背景换成一个圆,按钮都放进一个自动换行的组件。只是,这个想法不是很现实,Android的RecycleView
组件也只是一行固定多少个才会换行,HarmonyOS的ListContainer
组件能否实现效果还是个未知数。
2、使用他人开源的屏幕适配框架。不过,这个很遗憾,截止至发稿,还未能了解到有相关的适配框架。
3、另外写一个适配Wearable的布局。在onState
方法执行super.setUIContent
前更换专门为Wearable而写的xml,如:
@Override
public void onStart(Intent intent) {
super.onStart(intent);
// wearable设备换一个布局
if (DeviceInfo.getDeviceType().equals("wearable")){
super.setUIContent(Wearable布局);
}else{
super.setUIContent(ResourceTable.Layout_ability_main);
}
}
截止至发稿,Car还没有开放对应的机型,没能使用远程真机进行测试查看最终效果。这个效果图也只是点击Previewer进行查看的样式及效果。
1、点击Previewer查看xml,偶尔点击xml的一些样式并不会有响应,需要关闭Previewer并重新打开。
2、Previewer展示的样式不会显示ToastDialog等对话框、不会打印日志、不能点击Debug进行测试,还是使用真机测试真机测试香。
此次是我自HarmonyOS的DevEco Studio开发工具发布以来第一次开发的APP,身为一个Android开发工程师,做起HarmonyOS开发并不是很难,其中有很多东西都类似。DevEco Studio的远程真机测试与Previewer,效果杠杠的,要知道网上很多远程真机测试可都是收费制,且按使用时间收费,这一功能的出现可降低了不少开发费用。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。