codecamp

鸿蒙OS 添加智能穿戴模块

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

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

图1 开发样例效果图 点击放大

  1. 在 DevEco Studio 上方的导航栏中,依次点击“File > New > Module”,在“Device”中选择“Wearable”,添加一个新模块。

  1. 在左侧的“Project”窗口,打开“entry > src > main > resources > base”,右键点击“base”文件夹,选择“New > Directory”,命名为“layout”。

  1. 右键点击“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_type="scale_to_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>

  1. 在左侧项目文件栏中,选择“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 List<ComponentOwner> list = new ArrayList<>();

    
       private PageSliderProvider provider = new PageSliderProvider() {
           @Override
           public int getCount() {
               return list.size();
           }

    
           @Override
           public Object createPageInContainer(ComponentContainer componentContainer, int index) {
               if (index >= list.size() || componentContainer == null) {
                   HiLog.error(LABEL, "instantiateItem index error");
                   return Optional.empty();
               }
               ComponentOwner container = list.get(index);
               componentContainer.addComponent(container.getComponent());
               container.instantiateComponent();
               return container.getComponent();
           }

    
           @Override
           public void destroyPageFromContainer(ComponentContainer componentContainer, int index, Object object) {
               HiLog.info(LABEL, "destroyItem index:" + index);
               if (index >= list.size() || componentContainer == null) {
                   return;
               }
               Component content = list.get(index).getComponent();
               componentContainer.removeComponent(content);
               return;
           }

    
           @Override
           public boolean isPageMatchToObject(Component component, Object object) {
               return component == object;
           }

    
           @Override
           public void startUpdate(ComponentContainer container) {
               super.startUpdate(container);
               HiLog.info(LABEL, "startUpdate");
           }
       };

    
       @Override
       public void onStart(Intent intent) {
           super.onStart(intent);
           HiLog.info(LABEL, "onStart");

    
           // 添加子页面
           list.add(new SleepComponentOwner(this));
           list.add(new DetailComponentOwner(this));

    
           // 设置主界面
           DirectionalLayout layout = new DirectionalLayout(this);
           ComponentContainer.LayoutConfig config = new ComponentContainer.LayoutConfig(
                   ComponentContainer.LayoutConfig.MATCH_PARENT,
                   ComponentContainer.LayoutConfig.MATCH_PARENT);
           layout.setLayoutConfig(config);

    
           // 使用PageSlider做滑动效果
           PageSlider slider = new PageSlider(this);
           ComponentContainer.LayoutConfig sliderConfig = new ComponentContainer.LayoutConfig(
                   ComponentContainer.LayoutConfig.MATCH_PARENT,
                   ComponentContainer.LayoutConfig.MATCH_PARENT);
           slider.setLayoutConfig(sliderConfig);
           slider.setOrientation(DirectionalLayout.VERTICAL);
           slider.setProvider(provider);

    
           layout.addComponent(slider);

    
           setUIContent(layout);
       }
   }

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

   public interface ComponentOwner {
       // 获取存放的component
       Component getComponent();

    
       // 当包含的component被添加到容器时回调
       void instantiateComponent();
   }

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

   public class SleepComponentOwner implements ComponentOwner {
       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 static final int DEFAULT_SLEEP_TIME = 0;

    
       private CircleProgressDrawTask drawTask;

    
       private AbilityContext myContext;

    
       private Component root;

    
       public SleepComponentOwner(AbilityContext context) {
           init(context);
       }

    
       private void init(AbilityContext context) {
           myContext = context;
           LayoutScatter scatter = LayoutScatter.getInstance(context);
           root = scatter.parse(ResourceTable.Layout_layout_sleep, null, false);
           drawTask = new CircleProgressDrawTask(root);
           drawTask.setMaxValue(DEFAULT_SLEEP_TARGET_TIME);

    
           Component imageView = root.findComponentById(ResourceTable.Id_sleep_moon_img);
           imageView.setBackground(new VectorElement(context, ResourceTable.Graphic_ic_icon_moon));
       }

    
       @Override
       public Component getComponent() {
           return root;
       }

    
       @Override
       public void instantiateComponent() {
           return;
       }
   }

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

   public class DetailComponentOwner implements ComponentOwner {
       private static final String TAG = "DetailViewContainer";

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

    
       private AbilityContext myContext;

    
       private ComponentContainer root;

    
       public DetailComponentOwner(AbilityContext context) {
           init(context);
       }

    
       private void init(AbilityContext context) {
           root = new DirectionalLayout(context);
           ComponentContainer.LayoutConfig config = new ComponentContainer.LayoutConfig(
                   ComponentContainer.LayoutConfig.MATCH_PARENT,
                   ComponentContainer.LayoutConfig.MATCH_PARENT);
           root.setLayoutConfig(config);
           myContext = context;
       }

    
       @Override
       public Component getComponent() {
           return root;
       }

    
       @Override
       public void instantiateComponent() {
           return;
       }
   }

  1. 增加一个类型为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.0.8.27"
           },
           "apiVersion: {
               "compatible": 3,
               "target": 3
           }
       },
       "deviceConfig": {
           "default": {
               }
           }
       },
       "module": {
           "package": "com.huawei.health.sleep",
           "name": ".SleepApplication",
           "distro": {
               "moduleType": "entry",
               "deliveryWithInstall": true,
               "moduleName": "entry"
           },
           "deviceType": [
               "wearable"
           ],
           "reqCapabilities": [
               "video_support"
           ],
           "abilities": [
               {
                   "name": ".PageAbility",
                   "description": "$string:ability_description",
                   "icon": "$media:icon_app",
                   "label": "$string:app_name",
                   "launchType": "standard",
                   "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 的实现方法如下:

  1. 创建一个自定义 DrawTask,包含与该 Componet 相关的自定义属性和绘制的代码。
  2. 在构造方法里传入宿主 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实现绘制圆环的功能
        ......
    }
}

  
鸿蒙OS 打造智能穿戴应用
鸿蒙OS 创建应用通知介绍
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

鸿蒙OS 开发

鸿蒙OS 术语

鸿蒙OS Java API参考

鸿蒙OS ohos.aafwk.ability

鸿蒙OS ohos.aafwk.abilityjet.activedata

鸿蒙OS ohos.aafwk.content

鸿蒙OS java.lang

鸿蒙OS java.Util

鸿蒙OS java.Util class

鸿蒙OS ohos.data.dataability

鸿蒙OS ohos.data.dataability class

鸿蒙OS ohos.agp.components

鸿蒙OS ohos.agp.components interface

鸿蒙OS ohos.agp.components class

鸿蒙OS ohos.global.configuration

鸿蒙OS java.io

鸿蒙OS ohos.data.resultset

鸿蒙OS ohos.data.resultset interface

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }