据说,90%以上的开发者都想知道这些问题的答案 原创
在开发HarmonyOS应用时,你是否也遇翻遍资料也找不到答案的困扰?
没关系,本期我们将为大家带来开发者呼声最高的16个问题答疑,涵盖FA开发和UI组件,有原理有代码,让你快速get到解决方案。
赶紧往下看,一起来学习学习吧~
一、FA开发篇
Q1:在JS开发中,一个文件如何使用定义在其他文件中的变量?
A: 在开发过程中,有时候为了代码清晰,会新建一个文件,定义一个变量,把某个数据很大的常量数组独立到该新建文件中,其他文件有需要的时候可以使用到该数据。那么究竟应该如何使用?
举个例子,我们新建一个data.js的文件,定义一个data1的变量存储数据。
若我们需要使用到data.js中的data1变量,首先需要将data1变量导出:
在data.js文件末尾加上如下代码:
export {
data1
}
接着在需要使用该数据的文件头中导入data.js文件,假设此时是user.js需要使用data1数据,那么我们在user.js的文件头中导入data.js文件,代码如下:
import data from '../../common/js/data.js'
在user.js文件中使用data.data1就可使用data1变量了。
Q2:在JS开发中,如何控制块元素的横纵向排列?
A: 如果想在JS中实现块元素的纵向排列,需要给父元素设置flex-direction:column;如果想在JS中实现块元素的横向排列,需要给父元素设置flex-direction:row。通常容器组件flex-direction样式的缺省值为row,即默认为横向排列。
Q3:在JS开发中,如何控制一个元素显示或隐藏?
A: 在JS中,如果想要动态控制某个元素的显示或隐藏,可以为元素添加show属性,并为这个属性绑定js变量;若将变量值设为true,即可控制元素显示,设为false,则控制元素隐藏,示例代码如下:
<div class="container" show="{{flag}}">
Q4:为什么export的JS模块在别的JS文件中import时,会出现修改不生效的情况呢?
A: 在JS开发中,开发者可能会遇到这样的情况,某个变量在模块1中,被模块2 import并使用了,但是修改模块1中的这个变量,模块2中并没有生效这个修改的情况。这是由于HarmonyOS JS UI框架的import是静态import,即编译过程会把互相依赖的文件合并以提高运行效率。如果一个JS模块被多个文件import,则会在不同的文件中分别生成变量。
如果是要共享使用某个变量,使之变化在各模块中都能生效,建议在app.js里声明变量,并通过**getApp()**全局方法去获取该对象。
Q5:FA卡片如何动态更换图片?
A: 开发者可以通过调用setImageContent接口实现FA卡片图片的动态更换。但使用setImageContent接口设置图片时,涉及到资源id,需要在/base/profile中新建remote.xml配置文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<remoteresources>
<item>$media:test</item>
</remoteresources>
其中,test是需要设置的图片名。
Q6:如何定位AbilitySlice展示耗时问题?
A: 当开发者在开发自己的app的时候,如果发现页面展示的比较慢,需要对耗时问题进行定位并针对性进行改进,HarmonyOS提供两种方法帮助开发者完成该定位:
1.通过bytrace提供的接口进行打点跟踪:
● 详情请参考:
https://developer.harmonyos.com/cn/docs/documentation/doc-references/bytrace-0000001054679000
2.通过用于追踪进程轨迹、分析性能的命令行工具——bytrace来实现:
● 详情请参考:
Q7 :HarmonyOS中如何读取EXCEL中的数据?
A: 开发者可以参考以下步骤实现:
1.在entry > build.gradle中添加如下依赖:
dependencies {
……
implementation group: 'org.jxls', name: 'jxls-jexcel', version: '1.0.9'
}
2.在entry > resources > base > media目录下加入要读取的EXCEL表格,注意EXCEL表格的后缀为xls。
3.在MainAbilitySlice.java中读取EXCEL表格中的数据,代码如下:
public class MainAbilitySlice extends AbilitySlice {
private static final HiLogLabel TAG = new HiLogLabel(3, 0xD001100, "MainAbilitySlice");
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
// 处理EXCEL表格数据
try {
// 打开EXCEL文件
Resource resource = getResourceManager()
.getRawFileEntry("entry/resources/base/media/excel.xls").openRawFile();
Workbook wb = Workbook.getWorkbook(resource);
int sheetSize = wb.getNumberOfSheets();
if (sheetSize > 0) {
// 获取EXCEL的第一个sheet
Sheet sheet = wb.getSheet(0);
int rowTotal = sheet.getRows();
// 遍历单元格获取数据
for (int i = 0; i < rowTotal; i++) {
Cell[] cells = sheet.getRow(i);
for (int j = 0; j < cells.length; j++) {
String content = cells[j].getContents();
HiLog.info(TAG, "content:" + content);
}
}
}
} catch (IOException | BiffException e) {
HiLog.error(TAG, "exception");
}
}
}
二、UI组件篇
Q1:如何在JS中给image组件切换图源?
A: 将image组件中的src属性用js中的变量绑定,如 src=“{{imageSrc}}”,当需要更改图源时,仅需在js文件中将这个js变量值变更即可,如 imageSrc=“/common/pic.png”。
Q2:如何在JS中实现文本超长时显示省略号?
A: 开发者需要先为文本设置一个最大行数,接着使用样式text-overflow:ellipsis,在文本超出行数时,即会用省略号表示。
Q3:如何通过JS实现点击input组件并实现打开键盘的效果?
A: 在**.hml中给input组件设置id值,并为其设置focusable="true"的属性,在.js**中通过this.$element(“inputID”)取到input元素,然后调用focus方法即可,代码示例如下:
.hml:
<input id="box"
focusable="true"></input>
.js:
this.$element("box").focus({focus:true})
Q4:Switch组件如何设置thumb高度超出track?
A: Switch即开关选择器,通过开关,实现某个功能的开启或关闭。但在用户的实际使用中,可能出现由于手指不能完全对准Switch组件导致无法实现开关控制的情况,原始效果如下:
因此开发者的解决方案是设置组件滑动块高出底层的高度或者滑动手柄的高度超出滑动轨迹的高度来增加用户可控范围。效果如下:
可以看到蓝色圈圈的高度是超出底层灰色的高度,实现这种效果的代码如下:
Switch testSwitch = (Switch) findComponentById(ResourceTable.Id_test_switch);
ShapeElement trackOn = new ShapeElement();
trackOn.setShape(ShapeElement.PATH);
trackOn.setRgbColor(RgbPalette.BLUE);
Path pathOn = new Path();
pathOn.addRoundRect(new RectFloat(0.0f, 10.0f, 200.0f, 90.0f), 40.0f, 40.0f, Path.Direction.CLOCK_WISE);
trackOn.setBounds(0, 0, 100, 200);
trackOn.setPath(pathOn);
ShapeElement trackOff = new ShapeElement();
trackOff.setShape(ShapeElement.PATH);
trackOff.setRgbColor(RgbPalette.GRAY);
Path pathOFF = new Path();
pathOFF.addRoundRect(new RectFloat(0.0f, 10.0f, 200.0f, 90.0f), 40.0f, 40.0f, Path.Direction.CLOCK_WISE);
trackOff.setBounds(0, 0, 100, 200);
trackOff.setPath(pathOFF);
StateElement stateElement = new StateElement();
stateElement.addState(new int[]{ComponentState.COMPONENT_STATE_CHECKED}, trackOn);
stateElement.addState(new int[]{ComponentState.COMPONENT_STATE_EMPTY}, trackOff);
Q5:Java开发中,当TextField组件底部对齐时,如何才能避免输入内容后组件被软键盘遮挡?
A: 当TextField组件被设计在底部时,开发者可以通过以下方法避免输入内容后TextField组件被软键盘遮挡,步骤如下:
- 调用TextField父类Component中的setLayoutRefreshedListener方法进行组件布局刷新监听;
- 在回调中通过getWindowVisibleRect方法获取组件可视矩形区域;
- 根据可视区域算出textField需要移动的距离,使textField不被软件盘遮挡;
示例代码如下:
Component componentByIdLayout = findComponentById(ResourceTable.Id_directionlayout);
if (componentByIdLayout instanceof DirectionalLayout) {
mLayout = (DirectionalLayout) componentByIdLayout;
}
Component componentByIdTextField = findComponentById(ResourceTable.Id_text_field);
if (componentByIdTextField instanceof TextField) {
mTextField = (TextField) componentByIdTextField;
}
// 监听组件布局刷新
mLayout.setLayoutRefreshedListener(new Component.LayoutRefreshedListener() {
@Override
public void onRefreshed(Component component) {
Rect rect = new Rect();
// 获取组件可视矩形区域
boolean result = mTextField.getWindowVisibleRect(rect);
if (!result) {
HiLog.error(TAG, "getWindowVisibleRect fail");
return;
}
if (mTempVisibleHeight == 0 || mTempVisibleHeight == rect.bottom) {
mTempVisibleHeight = rect.bottom;
return;
}
// 计算textField组件需要移动的距离
int inputHeight = mTempVisibleHeight - rect.bottom;
mTempVisibleHeight = rect.bottom;
if (inputHeight > 0) {
mTextField.setText("input method height is " + inputHeight);
mTextField.setTranslationY(0 - inputHeight);
}
if (inputHeight < 0) {
mTextField.setText("input method height is 0");
mTextField.setTranslationY(0);
}
}
});
Q6:Java开发中,为什么TextField组件横、竖屏时输入样式差别很大?
A: 当TextField组件的width和height属性设置为match_parent时,会根据屏幕宽高自动适配,故横、竖屏时,TextField尺寸会发生改变,样式差别很大。如果需要保持横竖屏切换不改变TextField组件,开发者只需设置固定大小即可。
Q7:如何使应用不支持多窗口特性?
A: 一般情况下,HarmonyOS默认应用支持多窗口特性,若开发者不需要此支持,可以在config.json文件“module”节点下增加属性标识“resizeable”: false即可,该设置适用于手机、平板、智慧屏、车机、智能穿戴。
● 详情请参考:
Q8:Fraction如何在子线程中更新UI?
A: Fraction可以作为UI的一部分放在Ability或者AbilitySlice中,不能单独使用。Fraction的生命周期状态取决于它的容器。如果容器被销毁,其中的所有部分也将被销毁,开发者可以使用Fraction定义各种布局,以丰富应用程序的用户界面。开发者可以通过EventHandler的方式在子线程中更新UI,可参考如下代码实现:
public class MeFraction extends Fraction {
public void execute(Text text) {
EventHandler handler = new EventHandler(EventRunner.current()) {
// 重写实现processEvent方法处理事件
@Override
protected void processEvent(InnerEvent event) {
super.processEvent(event);
if (event == null) {
return;
}
if (event.eventId == 100) {
text.setText("更新UI");
}
}
};
// 创建子线程并通过EventHandler发送事件
new Thread(() -> handler.sendEvent(InnerEvent.get(100))).start();
}
}
Q9:如何通过代码实现横幅展示消息功能?
A: 在Java开发中,要实现消息展示功能需要用到NotificationSlot功能集合,其控制包括通知音、振动、锁屏显示和级别。当开发者将NotificationSlot的级别设置为LEVEL_HIGH,即可实现横幅展示消息功能。
NotificationSlot slot = new NotificationSlot("slot_001", "slot_default", NotificationSlot.LEVEL_HIGH);
● 更多关于NotificationSlot的介绍可以参考官网链接: