HarmonyOS-鸿蒙app开发 —基于java_智能穿戴_添加智能穿戴模块

HarmonyOS-鸿蒙app开发 —基于java_智能穿戴_添加智能穿戴模块

以下根据实际的开发样例来展示如何在已有的HarmonyOS工程中添加一个智能穿戴模块。

如图所示,这是一个睡眠检测应用,应用分为主界面和详情界面,可以选择使用PageSlider实现界面间的切换。PageSlider是一个布局管理器,用于实现左右滑动以及上下滑动的翻页效果。

图1 开发样例效果图

在工程中添加一个模块,设备类型设置为“Wearable”,具体参考在工程中添加Module

在左侧的Project窗口,打开entry > src > main > resources > base > layout,右键点击“layout”文件夹,选择New > File,新建两个UI布局文件,分别命名为“layout_sleep.xml”“layout_detail.xml”

主界面的UI布局文件是“layout_sleep.xml”,其完整示例代码如下:

<?xml version=”1.0″ encoding=”utf-8″?>

<DirectionalLayout xmlns:ohos=“http://schemas.huawei.com/res/ohos”

ohos:width=“match_parent”

ohos:height=“match_parent”

ohos:background_element=“#FF000000”

ohos:orientation=“vertical”>

 

<Image

ohos:id=“$+id:sleep_moon_img”

ohos:width=“46vp”

ohos:height=“46vp”

ohos:top_margin=“11vp”

ohos:layout_alignment=“horizontal_center”/>

 

<Text

ohos:width=“match_parent”

ohos:height=“19.5vp”

ohos:alpha=“0.66”

ohos:layout_alignment=“horizontal_center”

ohos:text_alignment=“center”

ohos:text=“$string:sleep”

ohos:text_color=“$color:sleep_text_white”

ohos:text_size=“16vp”/>

 

<DirectionalLayout xmlns:ohos=“http://schemas.huawei.com/res/ohos”

ohos:width=“match_content”

ohos:height=“65vp”

ohos:top_margin=“8vp”

ohos:layout_alignment=“horizontal_center”

ohos:orientation=“horizontal”>

<Text

ohos:id=“$+id:sleep_hour_text”

ohos:width=“match_content”

ohos:height=“match_content”

ohos:layout_alignment=“center”

ohos:text_alignment=“center”

ohos:text=“$string:dash”

ohos:text_color=“$color:sleep_text_white”

ohos:text_size=“58vp”

/>

<Text

ohos:width=“match_content”

ohos:height=“match_content”

ohos:left_margin=“2vp”

ohos:alpha=“0.66”

ohos:layout_alignment=“bottom”

ohos:bottom_padding=“9.5vp”

ohos:text=“$string:hour”

ohos:text_color=“$color:sleep_text_white”

ohos:text_size=“16vp”

/>

<Text

ohos:id=“$+id:sleep_min_text”

ohos:width=“match_content”

ohos:height=“match_content”

ohos:left_margin=“2vp”

ohos:layout_alignment=“center”

ohos:text_alignment=“center”

ohos:text=“$string:double_dash”

ohos:text_color=“$color:sleep_text_white”

ohos:text_size=“58vp”

/>

<Text

ohos:width=“match_content”

ohos:height=“match_content”

ohos:left_margin=“2vp”

ohos:alpha=“0.66”

ohos:layout_alignment=“bottom”

ohos:bottom_padding=“9.5vp”

ohos:text=“$string:minute”

ohos:text_color=“$color:sleep_text_white”

ohos:text_size=“16vp”

/>

</DirectionalLayout>

<DirectionalLayout xmlns:ohos=“http://schemas.huawei.com/res/ohos”

ohos:width=“match_content”

ohos:height=“25vp”

ohos:top_margin=“20.5vp”

ohos:layout_alignment=“horizontal_center”

ohos:orientation=“horizontal”>

<Text

ohos:width=“match_content”

ohos:height=“19.5vp”

ohos:text=“$string:goal”

ohos:alpha=“0.66”

ohos:text_alignment=“bottom”

ohos:bottom_margin=“1vp”

ohos:text_color=“$color:sleep_text_white”

ohos:text_size=“16vp”

/>

<Text

ohos:id=“$+id:sleep_goal_text”

ohos:width=“match_content”

ohos:height=“match_parent”

ohos:left_margin=“2vp”

ohos:text=“$string:target_sleep_time”

ohos:text_weight=“600”

ohos:text_color=“$color:sleep_text_white”

ohos:bottom_padding=“2vp”

ohos:text_size=“21vp”

/>

<Text

ohos:width=“match_content”

ohos:height=“19.5vp”

ohos:left_margin=“2vp”

ohos:alpha=“0.66”

ohos:text=“$string:hour”

ohos:text_color=“$color:sleep_text_white”

ohos:text_size=“16vp”

/>

</DirectionalLayout>

</DirectionalLayout>

详情界面的UI布局文件是“layout_detail.xml”,其完整示例代码如下:

<?xml version=”1.0″ encoding=”utf-8″?>

<DirectionalLayout xmlns:ohos=“http://schemas.huawei.com/res/ohos”

ohos:width=“match_parent”

ohos:height=“match_parent”

ohos:orientation=“vertical”

ohos:background_element=“#FF000000”>

<Text

ohos:id=“$+id:detail_nodata_date”

ohos:width=“match_content”

ohos:height=“23vp”

ohos:top_margin=“20vp”

ohos:layout_alignment=“horizontal_center”

ohos:text_alignment=“bottom”

ohos:text_color=“$color:sleep_text_white”

ohos:text_weight=“600”

ohos:text_size=“19vp”/>

 

<Image

ohos:id=“$+id:detail_nodata_img”

ohos:width=“46vp”

ohos:height=“46vp”

ohos:top_margin=“25vp”

ohos:layout_alignment=“horizontal_center”

ohos:scale_mode=“zoom_center”/>

 

<Text

ohos:width=“match_content”

ohos:height=“match_content”

ohos:alpha=“0.66”

ohos:top_margin=“12vp”

ohos:layout_alignment=“horizontal_center”

ohos:text_alignment=“center”

ohos:text=“$string:no_data”

ohos:text_color=“$color:sleep_text_white”

ohos:text_size=“16vp”/>

<Text

ohos:width=“match_content”

ohos:height=“match_content”

ohos:alpha=“0.66”

ohos:layout_alignment=“horizontal_center”

ohos:text_alignment=“center”

ohos:text=“$string:wearing_watch_tips”

ohos:text_color=“$color:sleep_text_white”

ohos:text_size=“16vp”/>

</DirectionalLayout>

在左侧项目文件栏中,选择entry > src > main > java > 应用包名 > slice,在对应的AbilitySlice文件的onStart里,使用代码创建PageSlider,添加这两个相应的界面。

public class SleepPageSlice extends AbilitySlice {

private static final String TAG = “SleepPageSlice”;

 

private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0, TAG);

 

// 页面类型总数

private static final int PAGE_CAPACITY = 2;

 

private PageSlider mPageSlider;

 

private SleepViewContainer mSleepViewContainer;

 

private PageContainerSlideProvider mAdapter = new PageContainerSlideProvider(PAGE_CAPACITY);

 

@Override

public void onStart(Intent intent) {

super.onStart(intent);

HiLog.info(LABEL, “onStart”);

 

// 设置主界面

DirectionalLayout layout = new DirectionalLayout(this);

ComponentContainer.LayoutConfig config = new ComponentContainer.LayoutConfig(

ComponentContainer.LayoutConfig.MATCH_PARENT,

ComponentContainer.LayoutConfig.MATCH_PARENT);

layout.setLayoutConfig(config);

 

// 使用ViwePager做滑动效果

mPageSlider = new PageSlider(this);

ComponentContainer.LayoutConfig viewPagerParam = new ComponentContainer.LayoutConfig(

ComponentContainer.LayoutConfig.MATCH_PARENT,

ComponentContainer.LayoutConfig.MATCH_PARENT);

mPageSlider.setLayoutConfig(viewPagerParam);

mPageSlider.setOrientation(DirectionalLayout.VERTICAL);

layout.addComponent(mPageSlider);

setUIContent(layout);

 

// 添加子页面

mSleepViewContainer = new SleepViewContainer(this);

mAdapter.addPageContainer(mSleepViewContainer);

mAdapter.addPageContainer(new DetailViewContainer(this));

mPageSlider.setProvider(mAdapter);

}

}

以下是page数据提供器PageContainerSlideProvider的实现。

public class PageContainerSlideProvider extends PageSliderProvider {

private static final String TAG = “PageContainerSlideProvider”;

 

private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0, TAG);

 

private final List<PageContainer> mList;

 

public PageContainerSlideProvider(int capacity) {

mList = new ArrayList<>(capacity);

}

 

@Override

public int getCount() {

return mList.size();

}

 

@Override

public Object createPageInContainer(ComponentContainer componentContainer, int index) {

HiLog.info(LABEL, “createPageInContainer index: %{public}d.”, index);

if (index >= mList.size() || (componentContainer == null)) {

HiLog.error(LABEL, “instantiateItem index error”);

return Optional.empty();

}

PageContainer item = mList.get(index);

item.getComponent().ifPresent(componentContainer::addComponent);

return item;

}

 

@Override

public void destroyPageFromContainer(ComponentContainer componentContainer, int index, Object obj) {

HiLog.info(LABEL, “destroyPageFromContainer index: %{public}d”, index);

if (componentContainer == null) {

HiLog.error(LABEL, “destroyPageFromContainer componentContainer is null”);

return;

}

if (!(obj instanceof PageContainer)) {

HiLog.error(LABEL, “destroyPageFromContainer obj error”);

return;

}

PageContainer item = (PageContainer) obj;

item.getComponent().ifPresent(componentContainer::removeComponent);

}

 

@Override

public boolean isPageMatchToObject(Component component, Object object) {

return component == object;

}

 

/**

* 增加分页

*

* @param pageContainer 分页

*/

public void addPageContainer(PageContainer pageContainer) {

HiLog.info(LABEL, “addPageContainer”);

pageContainer.onPageCreated();

mList.add(pageContainer);

}

 

 

// 清除所有页面

 

public void clearPageContainer() {

HiLog.info(LABEL, “clearPageContainer”);

for (PageContainer item : mList) {

item.onPageDestroy();

}

mList.clear();

notifyDataChanged();

}

 

/**

* 获取当前条目

*

* @param index page的index

* @return 当前的条目

*/

public Optional<PageContainer> getItemOfIndex(int index) {

if (index >= mList.size() || index < 0) {

HiLog.error(LABEL, “get item error, index: %{public}d”, index);

return Optional.empty();

}

return Optional.of(mList.get(index));

}

}

增加PageContainer容器接口和两个页面的实现方式,如下是容器的接口PageContainer.java。

public interface PageContainer {

/**

* 获取存放的component

*

* @return 存放的component

*/

default Optional<Component> getComponent() {

return Optional.empty();

}

 

// 页面加载的回调

default void onPageCreated() { }

 

// 页面销毁的回调

default void onPageDestroy() { }

 

// 页面被选中的回调

default void onPageSelected() { }

}

增加第一个页面SleepViewContainer 和第二个页面DetailViewContainer ,这两个页面从xml里加载。以下是首页SleepViewContainer 的实现。

public class SleepViewContainer implements PageContainer {

private static final String TAG = “SleepViewContainer”;

 

private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0, TAG);

 

// 目标睡眠时长默认值,单位:分钟

private static final int DEFAULT_SLEEP_TARGET_TIME = 480;

 

private CircleProgressDrawTask mDrawTask;

 

private AbilityContext mContext;

 

private Component mView;

 

private Image mImageView;

 

private Text mHourText;

 

private Text mMinText;

 

private Text mSleepContentText;

 

private Text mSleepHourTextUnit;

 

private Text mSleepMinTextUnit;

 

private Text mGoalText;

 

public SleepViewContainer(AbilityContext context) {

HiLog.info(LABEL, “constructor enter”);

this.mContext = context;

}

 

@Override

public Optional<Component> getComponent() {

HiLog.info(LABEL, “getComponent enter”);

return Optional.ofNullable(mView);

}

 

@Override

public void onPageCreated() {

HiLog.info(LABEL, “onPageCreated enter”);

mView = LayoutBoost.inflate(LayoutScatter.getInstance(mContext), mContext,

ResourceTable.Layout_layout_sleep, null, false);

init();

}

 

@Override

public void onPageDestroy() {

HiLog.info(LABEL, “onPageDestroy enter”);

}

 

private void init() {

HiLog.info(LABEL, “init enter”);

ByTrace.startTrace(“SleepViewContainer.init”);

mDrawTask = new CircleProgressDrawTask(mView);

mDrawTask.setMaxValue(DEFAULT_SLEEP_TARGET_TIME);

mImageView = (Image) mView.findComponentById(ResourceTable.Id_sleep_moon_img);

mImageView.setPixelMap(ResourceTable.Media_sleep_001);

mHourText = (Text) mView.findComponentById(ResourceTable.Id_sleep_hour_text);

mMinText = (Text) mView.findComponentById(ResourceTable.Id_sleep_min_text);

mSleepContentText = (Text) mView.findComponentById(ResourceTable.Id_sleep_content);

mSleepHourTextUnit = (Text) mView.findComponentById(ResourceTable.Id_sleep_hour_text_unit);

mSleepMinTextUnit = (Text) mView.findComponentById(ResourceTable.Id_sleep_min_text_unit);

mGoalText = (Text) mView.findComponentById(ResourceTable.Id_goal);

}

}

以下是第二个页面DetailViewContainer 的实现。

public class DetailViewContainer implements PageContainer {

private static final String TAG = “DetailViewContainer”;

 

private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0, TAG);

 

private AbilityContext mContext;

 

private ComponentContainer mRoot;

 

public DetailViewContainer(AbilityContext context) {

HiLog.info(LABEL, “constructor enter”);

this.mContext = context;

}

 

@Override

public Optional<Component> getComponent() {

HiLog.info(LABEL, “getComponent enter”);

return Optional.ofNullable(mRoot);

}

 

@Override

public void onPageCreated() {

HiLog.info(LABEL, “onPageCreated”);

mRoot = new DirectionalLayout(mContext);

ComponentContainer.LayoutConfig config = new ComponentContainer.LayoutConfig(

ComponentContainer.LayoutConfig.MATCH_PARENT,

ComponentContainer.LayoutConfig.MATCH_PARENT);

mRoot.setLayoutConfig(config);

}

 

@Override

public void onPageDestroy() {

HiLog.info(LABEL, “onPageDestroy”);

}

}

增加一个类型为Page的Ability,并在config.json里进行注册。需要在onStart里调用setSwipeToDismiss(true),来设置右滑退出。示例代码如下:

public class PageAbility extends Ability {

@Override

public void onStart(Intent intent) {

super.onStart(intent);

super.setMainRoute(SleepPageSlice.class.getName());

setSwipeToDismiss(true);

}

}

如下是配置文件config.json,注册PageAbility的时候,需要指明action.system.home,用来保证该Ability能在launcher上显示对应的图标。

{

“app”: {

“bundleName”: “com.huawei.health.sleep”,

“vendor”: “huawei”,

“version”: {

“code”: 1,

“name”: “1.1.06.04”

},

“apiVersion”: {

“compatible”: 2,

“target”: 2,

“releaseType”: “Release”

}

},

“deviceConfig”: {

“default”: {}

},

“module”: {

“package”: “com.huawei.health.sleep”,

“entryTheme”: “$theme:hapTheme”,

“name”: “.SleepApplication”,

“distro”: {

“moduleType”: “entry”,

“deliveryWithInstall”: true,

“moduleName”: “entry”

},

“deviceType”: [

“default”,

“wearable”

],

“reqCapabilities”: [

“video_support”

],

“abilities”: [

{

“name”: “.PageAbility”,

“icon”: “$media:icon_app”,

“label”: “$string:app_name”,

“launchType”: “singleton”,

“orientation”: “portrait”,

“visible”: true,

“permissions”: [],

“skills”: [

{

“actions”: [

“action.system.home”

],

“entities”: [

“entity.system.home”

]

}

],

“type”: “page”,

“formEnabled”: false

}

]

}

}

在睡眠界面中,我们用到了圆环效果,这里我们看一下圆环效果是如何实现的,如何实现自定义Component的效果。调用方代码如下:

drawTask = new CircleProgressDrawTask(root);

Componet类提供了UI的基本组件,包括方法addDrawTask(Component.DrawTask task)。该方法可以给任意一个Componet添加一段自定义绘制的代码。自定义Component的实现方法如下:

创建一个自定义DrawTask,包含与该Componet相关的自定义属性和绘制的代码。

在构造方法里传入宿主Component,跟自定义的DrawTask绑定。

实现睡眠圆环效果的示例代码如下。

public class CircleProgressDrawTask implements Component.DrawTask {

// 用于配置圆环的粗细,具体参数可以在xml文件中配置

private static final String STROKE_WIDTH_KEY = “stroke_width”;

 

// 用于配置圆环的最大值,具体参数可以在xml文件中配置

private static final String MAX_PROGRESS_KEY = “max_progress”;

 

// 用于配置圆环的当前值,具体参数可以在xml文件中配置

private static final String CURRENT_PROGRESS_KEY = “current_progress”;

 

// 用于配置起始位置的颜色,具体参数可以在xml文件中配置

private static final String START_COLOR_KEY = “start_color”;

 

// 用于配置结束位置的颜色,具体参数可以在xml文件中配置

private static final String END_COLOR_KEY = “end_color”;

 

// 用于配置背景色,具体参数可以在xml文件中配置

private static final String BACKGROUND_COLOR_KEY = “background_color”;

 

// 用于配置起始位置的角度,具体参数可以在xml文件中配置

private static final String START_ANGLE = “start_angle”;

 

private static final float MAX_ARC = 360f;

 

private static final int DEFAULT_STROKE_WIDTH = 10;

 

private static final int DEFAULT_MAX_VALUE = 100;

 

private static final int DEFAULT_START_COLOR = 0xFFB566FF;

 

private static final int DEFAULT_END_COLOR = 0xFF8A2BE2;

 

private static final int DEFAULT_BACKGROUND_COLOR = 0xA8FFFFFF;

 

private static final int DEFAULT_START_ANGLE = –90;

 

private static final float DEFAULT_LINER_MAX = 100f;

 

private static final int HALF = 2;

 

// 圆环的宽度, 默认10个像素

private int myStrokeWidth = DEFAULT_STROKE_WIDTH;

 

// 最大的进度值, 默认是100

private int myMaxValue = DEFAULT_MAX_VALUE;

 

// 当前的进度值, 默认是0

private int myCurrentValue = 0;

 

// 起始位置的颜色, 默认浅紫色

private Color myStartColor = new Color(DEFAULT_START_COLOR);

 

// 结束位置的颜色, 默认深紫色

private Color myEndColor = new Color(DEFAULT_END_COLOR);

 

// 背景颜色, 默认浅灰色

private Color myBackgroundColor = new Color(DEFAULT_BACKGROUND_COLOR);

 

// 当前的进度值, 默认从-90度进行绘制

private int myStartAngle = DEFAULT_START_ANGLE;

 

private Component myComponent;

 

// 传入要进行修改的component

public CircleProgressDrawTask(Component component) {

myComponent = component;

myComponent.addDrawTask(this);

}

 

// 设置当前进度并且刷新component,value值为当前进度

public void setValue(int value) {

myCurrentValue = value;

myComponent.invalidate();

}

 

public void setMaxValue(int maxValue) {

myMaxValue = maxValue;

myComponent.invalidate();

}

 

@Override

public void onDraw(Component component, Canvas canvas) {

// 通过canvas实现绘制圆环的功能

……

}

}

 

🚀 如未找到文章请搜索栏搜素 | Ctrl+D收藏本站 | 联系邮箱:15810050733@qq.com