【中软国际】HarmonyOS 日程提醒卡片应用 精华

中软HOS小鸿
发布于 2021-8-3 17:33
浏览
16收藏

效果图展示:

【中软国际】HarmonyOS 日程提醒卡片应用-鸿蒙开发者社区

一、项目介绍

    项目为一个简单的在日历上添加日程的应用,我们可以将当日的日程生成卡片到桌面,便于直观查看当日要做事项。
    此项目旨在帮助开发者快速掌握如下技术点:
    1) Js卡片的布局、初始化、更新、事件处理;
    2) Java卡片的布局、初始化、更新、事件处理。

二、代码结构解读

本教程我们只是对核心代码进行讲解,您可以在最后的参考中下载完整代码,首先来介绍下整个工程的代码结构:
【中软国际】HarmonyOS 日程提醒卡片应用-鸿蒙开发者社区
    1、java-Util:封装处理卡片数据的工具类
    2、java-widget:controller—卡片统一管理类;javacard2x4—java2x2与java2x4的卡片初始化、更新等处理类;jscard2x4—js2x2与js2x4的卡片初始化、更新等处理类;widget—js轮播卡片初始化、更新等处理类。
    3、java-CardServiceAbility:日程变动,更新卡片的service服务类。
    4、java-MainAbility:应用的入口,也是卡片初始化、更新等操作的入口。
    5、java-ServiceAbility:js与java的通信服务。
    6、js-default-page:index—应用首页,日历日程展示页面代码;schedule—日程添加、修改、删除页面代码。
    7、js-jscard2x4:js2x2与js2x4卡片页面代码;js-widget:js轮播卡片页面代码。
    8、resources-base-layout:form_grid_pattern_javacard2x4_2_2.xml—java2x2卡片页面代码;form_grid_pattern_javacard2x4_2_4.xml—java2x4卡片页面代码。
    9、config.json:java、js、卡片等配置文件。

三、Js轮播卡片

1.新建js卡片

1)右击—new—service-widget
【中软国际】HarmonyOS 日程提醒卡片应用-鸿蒙开发者社区
2)选择模板—下一步
【中软国际】HarmonyOS 日程提醒卡片应用-鸿蒙开发者社区
3)输入卡片名称、选择卡片类型(单选)、卡片大小(多选),点击finish即可。
【中软国际】HarmonyOS 日程提醒卡片应用-鸿蒙开发者社区

2.默认卡片页面

1)js-widget-pages-index-index.json默认卡片页面的数据
    data:默认数据。
    actions:routerEvent为router事件,用于应用跳转。
2)js-widget-pages-index-index.css 卡片的样式
    同js页面样式开发。
3)js-widget-pages-index-index.html 卡片的页面
    同js页面开发,不过要使用卡片支持组件;你可以点击 JS卡片组件 去学习。
    click事件关联json文件中的actions下的应用跳转事件,此处关联的是点击跳转应用的页面,页面代码:on:click=“routerEvent”(不可以传参)。

3.初始化卡片页面

在WidgetImpl.java文件中bindFromData方法中,进行页面展示数据的初始化:

public ProviderFormInfo bindFormData() {
       ZSONObject zsonObject = new ZSONObject();
       ProviderFormInfo providerFormInfo = new ProviderFormInfo();
       String scheduleData = StorageUtil.initPreferences(context).getSchedule();
       if(!"".equals(scheduleData)) {
           ZSONArray array = ZSONArray.stringToZSONArray(scheduleData);
           if(array.size()>0) {
               ZSONArray result = StorageUtil.getSwiperCardSchedule(array);
               CardConstant.SWIPER_CARD_LENGTH = result.size();
               zsonObject.put("schedule", result);
               zsonObject.put("count", array.size());
           }
       }
       zsonObject.put("index", 0);
       providerFormInfo.setJsBindingData(new FormBindingData(zsonObject));
       return providerFormInfo;
   }
4.更新卡片页面

1)config.json配置定时或周期性刷新
    定时或周期性刷新均会调用WidgetImpl.java文件中updateFormData方法,因本卡片未实现此方法,所以不支持此功能;在下面js2x2与2x4卡片中介绍周期性刷新;在下面java2x2与2x4卡片中介绍定时刷新。

2)添加当日日程导致数据变化 ,对日程进行更新介绍
    数据变化时,触发数据监听方法,代码在StorageUtil.java工具类,这里开启CardServiceAbility服务,代码如下:

private class PreferencesChangeCounter implements Preferences.PreferencesObserver {
       private Context mContext;
       public PreferencesChangeCounter(Context context){
           this.mContext = context;
       }
       @Override
       public void onChange(Preferences preferences, String key) {
           Intent intent = new Intent();
           Operation operation = new Intent.OperationBuilder()
                   .withDeviceId("")
                   .withBundleName("com.example.myohoscard")
                   .withAbilityName("com.example.myohoscard.CardServiceAbility")
                   .build();
           intent.setOperation(operation);
           mContext.startAbility(intent,0);
       }
   }

CardServiceAbility服务的onCommand方法中进行卡片更新,其更新代码如下:

   public void swiperData(ZSONArray array){
       ZSONArray result = StorageUtil.getSwiperCardSchedule(array);

       CardConstant.SWIPER_CARD_LENGTH = result.size();

       ZSONObject zsonObject = new ZSONObject();
       zsonObject.put("schedule", result);
       zsonObject.put("count", array.size());

       FormBindingData formBindingData = new FormBindingData(zsonObject);
       FormControllerManager formControllerManager = FormControllerManager.getInstance(this);

       for(long id:formControllerManager.getAllFormIdFromSharePreference(CardConstant.SWIPER_CARD_FORMS_NAME)) {
           try {
               updateForm(id, formBindingData);
           } catch (FormException e) {
               e.printStackTrace();
           }
       }
   }
5.卡片的轮播

CardServiceAbility服务的onCommand方法中调用卡片轮播,其代码如下:

public void swiperLoop(){
       ZSONObject data = new ZSONObject();
       if(CardConstant.SWIPER_CARD_THREAD != null) {
           CardConstant.SWIPER_CARD_THREAD.interrupt();
       }
       CardConstant.SWIPER_CARD_THREAD = new Thread(() -> {
           while (true) {
               try {
                   if(Thread.currentThread().isInterrupted()){
                       //处理中断逻辑
                       break;
                   }
                   Thread.sleep(2000);

                   data.put("index", index % CardConstant.SWIPER_CARD_LENGTH);
                   FormBindingData bindingData = new FormBindingData(data);
                   FormControllerManager formControllerManager = FormControllerManager.getInstance(this);

                   for(long formid:formControllerManager.getAllFormIdFromSharePreference(CardConstant.SWIPER_CARD_FORMS_NAME)) {
                       updateForm(formid, bindingData);
                   }

                   index++;
                   if(index == CardConstant.SWIPER_CARD_LENGTH){
                       index = 0;
                   }
               } catch (Exception e) {
                   break;
               }
           }
       });
       CardConstant.SWIPER_CARD_THREAD.start();
   }

缺点:此处退出应用程序时,service不再运行导致轮播线程结束,轮播失效。

四、Js2x2与2x4卡片

1.新建卡片页面

同js轮播卡片的新建卡片页面操作步骤,勾选2x2、2x4卡片。

2.默认卡片页面

1) js-card2x4-pages-index-index.json默认卡片页面的数据
    data:默认数据。
    actions:routerEvent为router事件,用于应用跳转;sendMessageEvent1与sendMessageEvent2为message事件,用于卡片开发人员自定义点击事件。
2) js-card2x4-pages-index-index.css 卡片的样式
    同js页面样式开发。
3) js-card2x4-pages-index-index.html 卡片的页面
    同js页面开发,不过要使用卡片支持组件;
    2x2或2x4的卡片公用一个html页面,利用dim2X4变量true或者false,来展示2x2或2x4的布局;
    click事件关联json文件中的actions下的操作事件,此处关联的是点击跳转应用的页面,代码:on:click="routerEvent"或on:click=“sendMessageEvent1”、on:click=“sendMessageEvent2”(不支持参数传递)。

3.初始化卡片页面

在Jscard2x4Impl.java文件中bindFromData方法中,进行页面展示数据的初始化:

public ProviderFormInfo bindFormData() {
       HiLog.info(TAG, "bind form data");
       ZSONObject zsonObject = new ZSONObject();
       ProviderFormInfo providerFormInfo = new ProviderFormInfo();
       if (dimension == DIMENSION_1X2) {
           zsonObject.put("mini", true);
       }
       if (dimension == DIMENSION_2X4) {
           zsonObject.put("dim2X4", true);
       }
       String scheduleData = StorageUtil.initPreferences(context).getSchedule();
       if(!"".equals(scheduleData)) {
           ZSONArray array = ZSONArray.stringToZSONArray(scheduleData);
           if(array.size()>0) {
               zsonObject = getObject(array,zsonObject);
           }
       }
       providerFormInfo.setJsBindingData(new FormBindingData(zsonObject));
       return providerFormInfo;
   }

   /**
    * 当天日程存在时,卡片数据展示
    * @param array
    * @param zsonObject
    * @return
    */
   public static ZSONObject getObject(ZSONArray array,ZSONObject zsonObject){
       ZSONArray result = StorageUtil.getCurrentCardSchedule(array);
       ZSONObject schedule_current = ZSONObject.stringToZSON(ZSONObject.toZSONString(result.get(0)));
       if(schedule_current != null){
           zsonObject.put("schedule_current", schedule_current);
       }
       ZSONObject schedule_1 = ZSONObject.stringToZSON(ZSONObject.toZSONString(result.get(1)));
       ZSONObject schedule_2 = ZSONObject.stringToZSON(ZSONObject.toZSONString(result.get(2)));
       if(schedule_1 != null){
           zsonObject.put("noSchedule", false);
           zsonObject.put("hasSchedule1", true);
           zsonObject.put("schedule_1", schedule_1);
       }
       if(schedule_2 != null){
           zsonObject.put("hasSchedule2", true);
           zsonObject.put("schedule_2", schedule_2);
       }
       zsonObject.put("count", array.size());
       return zsonObject;
   }
4.更新卡片页面

1)config.json配置周期性刷新
    config.json中jscard2X4卡片配置"updateEnabled": true与"updateDuration": 1,其中updateDuration配置参数为30分钟倍数,此处1即30分钟主动刷新一次卡片。
周期性刷新调用Jscard2x4Impl.java文件中updateFormData方法,代码如下:

public void updateFormData(long formId, Object... vars) {
       HiLog.info(TAG, "update form data timing, default 30 minutes");
       String scheduleData = StorageUtil.initPreferences(context).getSchedule();
       if(!"".equals(scheduleData)) {
           ZSONArray array = ZSONArray.stringToZSONArray(scheduleData);
           if(array.size()>0) {
               FormBindingData formBindingData = new FormBindingData(getObject(array,new ZSONObject()));//上一步中有getObject()方法代码
               try {
                   ((MainAbility)context).updateForm(formId, formBindingData);
               } catch (FormException e) {
                   e.printStackTrace();
               }
           }
       }

   }

2)添加当日日程导致数据变化 ,对日程进行更新介绍
    数据变化时,触发数据监听方法,代码在StorageUtil.java工具类中,这里开启CardServiceAbility服务。CardServiceAbility服务的onCommand方法中调用cardData进行卡片更新,其更新代码如下:

FormBindingData formBindingData = new FormBindingData(Jscard2X4Impl.getObject(array,new ZSONObject()));//上一步中有getObject()方法代码
       FormControllerManager formControllerManager = FormControllerManager.getInstance(this);

       try {
           for(long id:formControllerManager.getAllFormIdFromSharePreference(CardConstant.JS_CARD_FORMS_NAME)) {
               updateForm(id, formBindingData);
           }
       } catch (FormException e) {
           e.printStackTrace();
       }
5.router事件与message事件处理

1)router事件
    在跳转后的页面,接收参数并进行处理,这里请看MainAbility.java下的onStart方法,代码如下:

String strParams = intent.getStringParam("params");
       if(strParams != null) {
           ZSONObject data = ZSONObject.stringToZSON(strParams);
           String message = data.getString("message");
           //此处可以根据message判断点击了某个按钮,从而做相应的处理
           new ToastDialog(this).setText(message)
                   .setAlignment(LayoutAlignment.CENTER).show();
       }

2)message事件
    在Jscard2x4Impl.java文件中onTriggerFormEvent方法中进行处理,代码如下:

public void onTriggerFormEvent(long formId, String message) {
       HiLog.info(TAG, "handle card click event.");
       ZSONObject data = ZSONObject.stringToZSON(message);
       String msg = data.getString("msg");

       Intent intent = new Intent();
       intent.setParam("params","{\"message\":\""+msg+"\"}");
       Operation operation = new Intent.OperationBuilder()
               .withDeviceId("")
               .withBundleName("com.example.myohoscard")
               .withAbilityName("com.example.myohoscard.MainAbility")
               .build();
       intent.setOperation(operation);
       ((MainAbility)context).startAbility(intent);
   }

五、Java2x2与2x4卡片

1.新建卡片页面

    同js轮播卡片的新建卡片页面操作步骤,勾选type—java、Dimensions—2x2与2x4卡片。

2.默认卡片页面

    resources-base-layout下:java2x2卡片布局页面—form_grid_pattern_javacard2x4_2_2.xml,java2x2卡片布局页面—form_grid_pattern_javacard2x4_2_4.xml;其开发模式同应用java模式页面布局开发。

3.初始化卡片页面

在Javacard2x4Impl.java文件中bindFromData方法中,进行页面展示数据的初始化:

public ProviderFormInfo bindFormData() {
       HiLog.info(TAG, "bind form data when create form");
       ProviderFormInfo providerFormInfo = new ProviderFormInfo(RESOURCE_ID_MAP.get(dimension), context);
       String scheduleData = StorageUtil.initPreferences(context).getSchedule();
       if(!"".equals(scheduleData)) {
           ZSONArray array = ZSONArray.stringToZSONArray(scheduleData);
           if(array.size()>0) {
               // ComponentProvider表示Java卡片
               ComponentProvider componentProvider = new ComponentProvider();
               providerFormInfo.mergeActions(getFormDataCreate(array,context,dimension,componentProvider));

           }
       }

       return providerFormInfo;
   }
public static ComponentProvider getFormDataCreate(ZSONArray array,Context context,int dimension,ComponentProvider componentProvider){
       componentProvider.setVisibility(ResourceTable.Id_count, Text.VISIBLE);
       componentProvider.setText(ResourceTable.Id_count, array.size()+"");

       ZSONArray result = StorageUtil.getCurrentCardSchedule(array);
       ZSONObject schedule_current = ZSONObject.stringToZSON(ZSONObject.toZSONString(result.get(0)));
       if(schedule_current != null){
           componentProvider.setText(ResourceTable.Id_time, schedule_current.getString("startCardShow")+"-"+schedule_current.getString("endCardShow"));
           componentProvider.setText(ResourceTable.Id_schedule, schedule_current.getString("title"));
       }
       if (dimension == DEFAULT_DIMENSION_2X2) {
           componentProvider.setIntentAgent(ResourceTable.Id_layout, getStartAbilityIntentAgent(context));
       }

       if (dimension == DIMENSION_2X4) {
           componentProvider.setVisibility(ResourceTable.Id_noschedule, Text.HIDE);
           ZSONObject schedule_1 = ZSONObject.stringToZSON(ZSONObject.toZSONString(result.get(1)));
           if(schedule_1 != null){
//                componentProvider.setText(ResourceTable.Id_time1, schedule_1.getString("startCardShow")+"-"+schedule_1.getString("endCardShow"));
               componentProvider.setText(ResourceTable.Id_schedule1, schedule_1.getString("title"));
           }

           ZSONObject schedule_2 = null;
           if(result.get(2) != null){
               schedule_2 = ZSONObject.stringToZSON(ZSONObject.toZSONString(result.get(2)));
           }
           if(schedule_2 != null){
               componentProvider.setVisibility(ResourceTable.Id_line, Text.VISIBLE);
//                componentProvider.setText(ResourceTable.Id_time2, schedule_2.getString("startCardShow")+"-"+schedule_2.getString("endCardShow"));
               componentProvider.setText(ResourceTable.Id_schedule2, schedule_2.getString("title"));
           }
       }

       if (dimension == DIMENSION_2X4) {
           componentProvider.setIntentAgent(ResourceTable.Id_more, getStartAbilityIntentAgent(context));
       }
       return componentProvider;
   }
4.更新卡片页面

1)config.json配置定时刷新
    config.json中jscard2X4卡片配置"scheduledUpdateTime": “10:42"与"updateDuration”: 0,其中scheduledUpdateTime配置参数为24小时制,可以在当天指定时间对卡片进行刷新。
    定时刷新调用Javacard2x4Impl.java文件中updateFormData方法,代码如下:

public void updateFormData(long formId, Object... vars) {
       HiLog.info(TAG, "update form data timing, default 30 minutes");

       String scheduleData = StorageUtil.initPreferences(context).getSchedule();
       if(!"".equals(scheduleData)) {
           ZSONArray array = ZSONArray.stringToZSONArray(scheduleData);
           if(array.size()>0) {
               ComponentProvider componentProvider =
                       new ComponentProvider(RESOURCE_ID_MAP.get(dimension), context);
               try {
                   ((MainAbility)context).updateForm(formId, getFormDataUpdate(array,context,dimension,componentProvider));
               } catch (FormException e) {
                   HiLog.error(TAG, e.toString());
               }

           }
       }

   }
public static ComponentProvider getFormDataUpdate(ZSONArray array,Context context,int dimension,ComponentProvider componentProvider){

       componentProvider.setVisibility(ResourceTable.Id_count, Text.VISIBLE);
       componentProvider.setText(ResourceTable.Id_count, array.size()+"");

       ZSONArray result = StorageUtil.getCurrentCardSchedule(array);
       ZSONObject schedule_current = ZSONObject.stringToZSON(ZSONObject.toZSONString(result.get(0)));
       if(schedule_current != null){
           componentProvider.setText(ResourceTable.Id_time, schedule_current.getString("startCardShow")+"-"+schedule_current.getString("endCardShow"));
           componentProvider.setText(ResourceTable.Id_schedule, schedule_current.getString("title"));
       }

       if (dimension == DIMENSION_2X4) {
           componentProvider.setVisibility(ResourceTable.Id_noschedule, Text.HIDE);
           ZSONObject schedule_1 = ZSONObject.stringToZSON(ZSONObject.toZSONString(result.get(1)));
           if(schedule_1 != null){
//                componentProvider.setText(ResourceTable.Id_time1, schedule_1.getString("startCardShow")+"-"+schedule_1.getString("endCardShow"));
               componentProvider.setText(ResourceTable.Id_schedule1, schedule_1.getString("title"));
           }

           ZSONObject schedule_2 = null;
           if(result.get(2) != null){
               schedule_2 = ZSONObject.stringToZSON(ZSONObject.toZSONString(result.get(2)));
           }
           if(schedule_2 != null){
               componentProvider.setVisibility(ResourceTable.Id_line, Text.VISIBLE);
//                componentProvider.setText(ResourceTable.Id_time2, schedule_2.getString("startCardShow")+"-"+schedule_2.getString("endCardShow"));
               componentProvider.setText(ResourceTable.Id_schedule2, schedule_2.getString("title"));
           }
       }

       return componentProvider;
   }

2)添加当日日程导致数据变化 ,对日程进行更新介绍
数据变化时,触发数据监听方法,代码在StorageUtil.java工具类中,这里开启CardServiceAbility服务。CardServiceAbility服务的onCommand方法中调用cardData进行卡片更新,其更新代码如下:

try {
           for(long id:formControllerManager.getAllFormIdFromSharePreference(CardConstant.JAVA_CARD_FORMS_NAME)) {
               int dimension = formControllerManager.getDimension(id+"");

               ComponentProvider componentProvider =
                   new ComponentProvider(Javacard2x4Impl.RESOURCE_ID_MAP.get(dimension), this);
               updateForm(id, Javacard2x4Impl.getFormDataUpdate(array,this,dimension,componentProvider));//上一步中有此方法代码
           }
       } catch (FormException e) {
           e.printStackTrace();
       }
5.卡片点击事件添加

给控件点击点击事件,其代码为:componentProvider.setIntentAgent(ResourceTable.Id_more, getStartAbilityIntentAgent(context)),其中getStartAbilityIntentAgent方法代码如下:

private static IntentAgent getStartAbilityIntentAgent(Context context) {
       Intent intent = new Intent();
       Operation operation = new Intent.OperationBuilder()
               .withDeviceId("")
               .withBundleName("com.example.myohoscard")
               .withAbilityName("com.example.myohoscard.MainAbility")
               .build();
       intent.setOperation(operation);
       List<Intent> intentList = new ArrayList<>();
       intentList.add(intent);
       List<IntentAgentConstant.Flags> flags = new ArrayList<>();
       flags.add(IntentAgentConstant.Flags.UPDATE_PRESENT_FLAG);
       IntentAgentInfo paramsInfo =
               new IntentAgentInfo(200, IntentAgentConstant.OperationType.START_ABILITY, flags, intentList, null);
       return IntentAgentHelper.getIntentAgent(context, paramsInfo);
   }

六、代码参考

https://gitee.com/chinasoft6_ohos/my-ohos-card
 
作者:陈巧银

更多原创内容请关注:中软国际 HarmonyOS 技术学院

入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,共建鸿蒙生态,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。

已于2021-8-11 14:17:45修改
17
收藏 16
回复
举报
6条回复
按时间正序
/
按时间倒序
左手有一个
左手有一个

效果不错,牛逼

回复
2021-8-4 17:56:57
劳资卖个萌
劳资卖个萌

学习了!!!

回复
2021-8-4 17:58:13
1202857
1202857

厉害,深入浅出,通俗易懂

回复
2021-8-11 15:08:14
丶花猫
丶花猫

深入浅出,蒋总藕像!

回复
2021-8-12 15:00:37
坚强的奥利给
坚强的奥利给

不明觉厉

回复
2021-8-12 15:30:33
修身养生
修身养生

精华吖,感谢分享

回复
2021-9-26 16:32:46
回复
    相关推荐