HarmonyOS实战—服务卡片初体验

一、什么是服务卡片服务卡片(以下简称“卡片”)是FA的一种界面展示形式,将FA的重要信息或操作直接放置到卡片中,用户通过直接操作卡片就可以达到应用的使用体验,这样做大大减少了应用的使用层级性。

一、什么是服务卡片

服务卡片(以下简称“卡片”)是FA的一种界面展示形式,将FA的重要信息或操作直接放置到卡片中,用户通过直接操作卡片就可以达到应用的使用体验,这样做大大减少了应用的使用层级性。

卡片常用于嵌入到其他应用中作为其界面的一部分显示(也可以使用原子化服务将应用保存到服务中心中,这种方式不需要安装应用),并支持拉起页面,发送消息等基础的交互功能。

示例如下图所示。

HarmonyOS实战—服务卡片初体验

为了开发者能够便于理解,官方将服务卡片分为三方面:

  • 卡片使用方 显示卡片内容的宿主应用,控制卡片在宿主中展示的位置。
  • 卡片管理服务 用于管理系统中所添加卡片的常驻代理服务,包括卡片对象的管理与使用,以及卡片周期性刷新等。
  • 卡片提供方 提供卡片显示内容的HarmonyOS应用或原子化服务,控制卡片的显示内容、控件布局以及控件点击事件。

二、服务卡片的运作机制

文字描述滞后,先上图。(图片由官网提供,此处借用一下)

HarmonyOS实战—服务卡片初体验

从图中可以清楚的看到服务卡片的整体通信层都是由"RPC"负责,通过通信适配层构成了数据发送接收的通道。

卡片管理服务

  • 周期性刷新:在卡片添加后,根据卡片的刷新策略启动定时任务周期性触发卡片的刷新。
  • 卡片缓存管理:在卡片添加到卡片管理服务后,对卡片的视图信息进行缓存,以便下次获取卡片时可以直接返回缓存数据,降低时延。
  • 卡片生命周期管理:对于卡片切换到后台或者被遮挡时,暂停卡片的刷新;以及卡片的升级/卸载场景下对卡片数据的更新和清理。
  • 卡片使用方对象管理:对卡片使用方的RPC对象进行管理,用于使用方请求进行校验以及对卡片更新后的回调处理。

卡片提供方

  • 创建卡片实例并实现onCreateForm、onUpdateForm和onDeleteForm处理创建卡片、更新卡片以及删除卡片等请求,提供相应的卡片服务。

三、服务卡片的实现(java方式)

第一步、下载、安装、配置 DevEco Studio

点击查看

第二步、运行DevEco Studio创建新项目

因为要使用java语言编写,所以此处要选择支持Java语言的空页面。

HarmonyOS实战—服务卡片初体验

选择成功进入新建项目配置界面。

HarmonyOS实战—服务卡片初体验

点击Finish进入项目。

HarmonyOS实战—服务卡片初体验

第三步、添加卡片模板

创建模板:右击“Entry”→“New”→“Server Widget

HarmonyOS实战—服务卡片初体验

HarmonyOS实战—服务卡片初体验

设置模板

HarmonyOS实战—服务卡片初体验

第四步、查看卡片服务配置

项目目录

HarmonyOS实战—服务卡片初体验

由图可见:添加卡片模板后在原来项目中增加一个widget文件夹,并在文件夹中出现了三个文件FormControllerManager.java、FormController.java、CardWidgetImpl.java。三个文件对应了卡片服务的运行机制,通过关系的对应可以清楚的了解到代码运行原理。

FormControllerManager.java(卡片控制器管理【卡片管理服务】)

public class FormControllerManager {    private static final HiLogLabel TAG = new HiLogLabel(HiLog.DEBUG, 0x0, FormControllerManager.class.getName());    private static final String PACKAGE_PATH = "com.example.carddemo.widget";    private static final String SHARED_SP_NAME = "form_info_sp.xml";    private static final String FORM_NAME = "formName";    private static final String DIMENSION = "dimension";    private static FormControllerManager managerInstance = null;    private final HashMap<Long, FormController> controllerHashMap = new HashMap<>();    private final Context context;    private final Preferences preferences;    /**     * 初始化构造器     *     * @param context instance of Context.     */    private FormControllerManager(Context context) {        this.context = context;        DatabaseHelper databaseHelper = new DatabaseHelper(this.context.getApplicationContext());        preferences = databaseHelper.getPreferences(SHARED_SP_NAME);    }    /**     * FormControllerManager 实例化     *     * @param context instance of Context.     * @return FormControllerManager instance.     */    public static FormControllerManager getInstance(Context context) {        if (managerInstance == null) {            synchronized (FormControllerManager.class) {                if (managerInstance == null) {                    managerInstance = new FormControllerManager(context);                }            }        }        return managerInstance;    }    /**     * 通过构造器将传入的卡片信息进行封装,返回卡片服务     *     * @param formId    form id.     * @param formName  form name.     * @param dimension form dimension     * @return FormController form controller     */    public FormController createFormController(long formId, String formName, int dimension) {        synchronized (controllerHashMap) {            if (formId < 0 || formName.isEmpty()) {                return null;            }            HiLog.info(TAG,                    "saveFormId() formId: " + formId + ", formName: " + formName + ", preferences: " + preferences);            if (preferences != null) {                ZSONObject formObj = new ZSONObject();                formObj.put(FORM_NAME, formName);                formObj.put(DIMENSION, dimension);                preferences.putString(Long.toString(formId), ZSONObject.toZSONString(formObj));                preferences.flushSync();            }            // Create controller instance.            FormController controller = newInstance(formName, dimension, context);            // Cache the controller.            if (controller != null) {                if (!controllerHashMap.containsKey(formId)) {                    controllerHashMap.put(formId, controller);                }            }            return controller;        }    }    /**     * 获取卡片控制器实例     *     * @param formId form id.     * @return the instance of form controller.     */    public FormController getController(long formId) {        synchronized (controllerHashMap) {            if (controllerHashMap.containsKey(formId)) {                return controllerHashMap.get(formId);            }            Map<String, ?> forms = preferences.getAll();            String formIdString = Long.toString(formId);            if (forms.containsKey(formIdString)) {                ZSONObject formObj = ZSONObject.stringToZSON((String) forms.get(formIdString));                String formName = formObj.getString(FORM_NAME);                int dimension = formObj.getIntValue(DIMENSION);                FormController controller = newInstance(formName, dimension, context);                controllerHashMap.put(formId, controller);            }            return controllerHashMap.get(formId);        }    }    private FormController newInstance(String formName, int dimension, Context context) {        FormController ctrInstance = null;        if (formName == null || formName.isEmpty()) {            HiLog.error(TAG, "newInstance() get empty form name");            return ctrInstance;        }        try {            String className = PACKAGE_PATH + "." + formName.toLowerCase(Locale.ROOT) + "."                    + getClassNameByFormName(formName);            Class<?> clazz = Class.forName(className);            if (clazz != null) {                Object controllerInstance = clazz.getConstructor(Context.class, String.class, Integer.class)                        .newInstance(context, formName, dimension);                if (controllerInstance instanceof FormController) {                    ctrInstance = (FormController) controllerInstance;                }            }        } catch (NoSuchMethodException | InstantiationException | IllegalArgumentException | InvocationTargetException                | IllegalAccessException | ClassNotFoundException | SecurityException exception) {            HiLog.error(TAG, "newInstance() get exception: " + exception.getMessage());        }        return ctrInstance;    }    /**     * 从数组中获取所有卡片id     *     * @return form id list     */    public List<Long> getAllFormIdFromSharePreference() {        List<Long> result = new ArrayList<>();        Map<String, ?> forms = preferences.getAll();        for (String formId : forms.keySet()) {            result.add(Long.parseLong(formId));        }        return result;    }    /**     * 删除卡片服务     *     * @param formId form id     */    public void deleteFormController(long formId) {        synchronized (controllerHashMap) {            preferences.delete(Long.toString(formId));            preferences.flushSync();            controllerHashMap.remove(formId);        }    }    private String getClassNameByFormName(String formName) {        String[] strings = formName.split("_");        StringBuilder result = new StringBuilder();        for (String string : strings) {            result.append(string);        }        char[] charResult = result.toString().toCharArray();        charResult[0] = (charResult[0] >= 'a' && charResult[0] <= 'z') ? (char) (charResult[0] - 32) : charResult[0];        return String.copyValueOf(charResult) + "Impl";    }}

FormController.java(卡片控制器【卡片提供方】)

public abstract class FormController {    protected final Context context;    protected final String formName;    protected final int dimension;    public FormController(Context context, String formName, Integer dimension) {        this.context = context;        this.formName = formName;        this.dimension = dimension;    }    /**     * 创建卡片信息提供者     */    public abstract ProviderFormInfo bindFormData();    /**     * 更新卡片信息     */    public abstract void updateFormData(long formId, Object... vars);    /**     * 在接收服务小部件消息事件时调用     */    public abstract void onTriggerFormEvent(long formId, String message);    /**     * 获取路由的目标界面     */    public abstract Class<? extends AbilitySlice> getRoutePageSlice(Intent intent);}

CardWidgetImpl.java(卡片应用【卡片使用方】)

public class CardWidgetImpl extends FormController {    public static final int DIMENSION_1X2 = 1;    public static final int DIMENSION_2X4 = 3;    private static final HiLogLabel TAG = new HiLogLabel(HiLog.DEBUG, 0x0, CardWidgetImpl.class.getName());    private static final int DEFAULT_DIMENSION_2X2 = 2;    private static final Map<Integer, Integer> RESOURCE_ID_MAP = new HashMap<>();    static {        RESOURCE_ID_MAP.put(DIMENSION_1X2, ResourceTable.Layout_form_grid_pattern_cardwidget_1_2);        RESOURCE_ID_MAP.put(DEFAULT_DIMENSION_2X2, ResourceTable.Layout_form_grid_pattern_cardwidget_2_2);        RESOURCE_ID_MAP.put(DIMENSION_2X4, ResourceTable.Layout_form_grid_pattern_cardwidget_2_4);    }    public CardWidgetImpl(Context context, String formName, Integer dimension) {        super(context, formName, dimension);    }    //创建好卡片服务后,在界面展示卡片    @Override    public ProviderFormInfo bindFormData() {        HiLog.info(TAG, "bind form data when create form");        return new ProviderFormInfo(RESOURCE_ID_MAP.get(dimension), context);    }    //更新卡片信息    @Override    public void updateFormData(long formId, Object... vars) {        HiLog.info(TAG, "update form data timing, default 30 minutes");    }    //卡片中内容手势触发方法    @Override    public void onTriggerFormEvent(long formId, String message) {        HiLog.info(TAG, "handle card click event.");    }    @Override    public Class<? extends AbilitySlice> getRoutePageSlice(Intent intent) {        HiLog.info(TAG, "get the default page to route when you click card.");        return null;    }}

MainAbility的变化,新增了一些方法。

public class MainAbility extends Ability {    public static final int DEFAULT_DIMENSION_2X2 = 2;    public static final int DIMENSION_1X2 = 1;    public static final int DIMENSION_2X4 = 3;    public static final int DIMENSION_4X4 = 4;    private static final int INVALID_FORM_ID = -1;    private static final HiLogLabel TAG = new HiLogLabel(HiLog.DEBUG, 0x0, MainAbility.class.getName());    private String topWidgetSlice;    @Override    public void onStart(Intent intent) {        super.onStart(intent);        super.setMainRoute(MainAbilitySlice.class.getName());        if (intentFromWidget(intent)) {            topWidgetSlice = getRoutePageSlice(intent);            if (topWidgetSlice != null) {                setMainRoute(topWidgetSlice);            }        }        stopAbility(intent);    }    //创建卡片信息并返回卡片内容    @Override    protected ProviderFormInfo onCreateForm(Intent intent) {        HiLog.info(TAG, "onCreateForm");        long formId = intent.getLongParam(AbilitySlice.PARAM_FORM_IDENTITY_KEY, INVALID_FORM_ID);        String formName = intent.getStringParam(AbilitySlice.PARAM_FORM_NAME_KEY);        int dimension = intent.getIntParam(AbilitySlice.PARAM_FORM_DIMENSION_KEY, DEFAULT_DIMENSION_2X2);        HiLog.info(TAG, "onCreateForm: formId=" + formId + ",formName=" + formName);        FormControllerManager formControllerManager = FormControllerManager.getInstance(this);        FormController formController = formControllerManager.getController(formId);        //通过调用布局Id将卡片布局与卡片信息进行绑定        formController = (formController == null) ? formControllerManager.createFormController(formId,                formName, dimension) : formController;        if (formController == null) {            HiLog.error(TAG, "Get null controller. formId: " + formId + ", formName: " + formName);            return null;        }        return formController.bindFormData();    }    //更新卡片信息    @Override    protected void onUpdateForm(long formId) {        HiLog.info(TAG, "onUpdateForm");        super.onUpdateForm(formId);        FormControllerManager formControllerManager = FormControllerManager.getInstance(this);        FormController formController = formControllerManager.getController(formId);        formController.updateFormData(formId);    }    //删除卡片    @Override    protected void onDeleteForm(long formId) {        HiLog.info(TAG, "onDeleteForm: formId=" + formId);        super.onDeleteForm(formId);        FormControllerManager formControllerManager = FormControllerManager.getInstance(this);        formControllerManager.deleteFormController(formId);    }    //卡片手势触发    @Override    protected void onTriggerFormEvent(long formId, String message) {        HiLog.info(TAG, "onTriggerFormEvent: " + message);        super.onTriggerFormEvent(formId, message);        FormControllerManager formControllerManager = FormControllerManager.getInstance(this);        FormController formController = formControllerManager.getController(formId);        formController.onTriggerFormEvent(formId, message);    }    @Override    public void onNewIntent(Intent intent) {        if (intentFromWidget(intent)) { // Only response to it when starting from a service widget.            String newWidgetSlice = getRoutePageSlice(intent);            if (topWidgetSlice == null || !topWidgetSlice.equals(newWidgetSlice)) {                topWidgetSlice = newWidgetSlice;                restart();            }        }    }    private boolean intentFromWidget(Intent intent) {        long formId = intent.getLongParam(AbilitySlice.PARAM_FORM_IDENTITY_KEY, INVALID_FORM_ID);        return formId != INVALID_FORM_ID;    }    //跳转至对应的卡片界面    private String getRoutePageSlice(Intent intent) {        long formId = intent.getLongParam(AbilitySlice.PARAM_FORM_IDENTITY_KEY, INVALID_FORM_ID);        if (formId == INVALID_FORM_ID) {            return null;        }        FormControllerManager formControllerManager = FormControllerManager.getInstance(this);        FormController formController = formControllerManager.getController(formId);        if (formController == null) {            return null;        }        Class<? extends AbilitySlice> clazz = formController.getRoutePageSlice(intent);        if (clazz == null) {            return null;        }        return clazz.getName();    }}

配置文件

HarmonyOS实战—服务卡片初体验

属性名称

子属性名称

含义

数据类型

name

-

表示卡片的类名。字符串最大长度为127字节。

字符串

description

-

表示卡片的描述。取值可以是描述性内容,也可以是对描述性内容的资源索引,以支持多语言。字符串最大长度为255字节。

字符串

isDefault

-

表示该卡片是否为默认卡片,每个Ability有且只有一个默认卡片。

  • true:默认卡片。
  • false:非默认卡片。

布尔值

type

-

表示卡片的类型。取值范围如下:

  • Java:Java卡片。
  • JS:JS卡片。

字符串

colorMode

-

表示卡片的主题样式,取值范围如下:

  • auto:自适应。
  • dark:深色主题。
  • light:浅色主题。

字符串

supportDimensions

-

表示卡片支持的外观规格,取值范围:

  • 1*2:表示1行2列的二宫格。
  • 2*2:表示2行2列的四宫格。
  • 2*4:表示2行4列的八宫格。
  • 4*4:表示4行4列的十六宫格。

字符串数组

defaultDimension

-

表示卡片的默认外观规格,取值必须在该卡片supportDimensions配置的列表中。

字符串

landscapeLayouts

-

表示卡片外观规格对应的横向布局文件,与supportDimensions中的规格一一对应。

仅当卡片类型为Java卡片时,需要配置该标签。

字符串数组

portraitLayouts

-

表示卡片外观规格对应的竖向布局文件,与supportDimensions中的规格一一对应。

仅当卡片类型为Java卡片时,需要配置该标签。

字符串数组

updateEnabled

-

表示卡片是否支持周期性刷新,取值范围:

  • true:表示支持周期性刷新,可以在定时刷新(updateDuration)和定点刷新(scheduledUpdateTime)两种方式任选其一,优先选择定时刷新。
  • false:表示不支持周期性刷新。

布尔类型

scheduledUpdateTime

-

表示卡片的定点刷新的时刻,采用24小时制,精确到分钟。

字符串

updateDuration

-

表示卡片定时刷新的更新周期,单位为30分钟,取值为自然数。

  • 当取值为0时,表示该参数不生效。
  • 当取值为正整数N时,表示刷新周期为30*N分钟。

数值

formConfigAbility

-

表示卡片的配置跳转链接,采用URI格式。

字符串

jsComponentName

-

表示JS卡片的Component名称。字符串最大长度为127字节。

仅当卡片类型为JS卡片时,需要配置该标签。

字符串

metaData

-

表示卡片的自定义信息,包含customizeData数组标签。

对象

customizeData

-

表示自定义的卡片信息。

对象数组

name

表示数据项的键名称。字符串最大长度为255字节。

字符串

value

表示数据项的值。字符串最大长度为255字节。

字符串

第五步、编写卡片界面

HarmonyOS实战—服务卡片初体验

分别修改form_grid_pattern_cardwidget_1_2、form_grid_pattern_cardwidget_2_2.xml和form_grid_pattern_cardwidget_2_4.xml文件。

form_grid_pattern_cardwidget_1_2.xml

<?xml version="1.0" encoding="utf-8"?><DependentLayout    xmlns:ohos="http://schemas.huawei.com/res/ohos"    ohos:height="match_parent"    ohos:width="match_parent"    ohos:remote="true">    <Image        ohos:height="match_parent"        ohos:width="match_parent"        ohos:background_element="#1281f0"        ohos:scale_mode="clip_center"/>    <DirectionalLayout        ohos:height="match_parent"        ohos:width="match_parent"        ohos:alignment="center"        ohos:orientation="horizontal">        <Text            ohos:id="$+id:tv_name"            ohos:height="match_content"            ohos:width="match_content"            ohos:text="$string:cardwidget_title"            ohos:text_color="#E5FFFFFF"            ohos:text_size="16fp"            ohos:text_weight="1200"/>        <Text            ohos:height="match_content"            ohos:width="match_content"            ohos:text="3350"            ohos:text_color="#E5FFFFFF"            ohos:text_size="16fp"            ohos:text_weight="1200"/>    </DirectionalLayout></DependentLayout>

form_grid_pattern_cardwidget_2_2.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:background_element="#FFFFFFFF"    ohos:remote="true"    ohos:orientation="vertical">    <DirectionalLayout        ohos:id="$+id:tv_top"        ohos:height="match_parent"        ohos:width="match_parent"        ohos:weight="1"        ohos:orientation="horizontal">        <DirectionalLayout            ohos:height="match_parent"            ohos:width="match_parent"            ohos:weight="1"            ohos:orientation="vertical"            ohos:alignment="center">            <Text                ohos:height="match_content"                ohos:width="match_content"                ohos:text="消耗热量"                ohos:top_margin="5vp"                ohos:text_size="10fp"                ohos:text_weight="500">            </Text>            <Text                ohos:height="60vp"                ohos:width="60vp"                ohos:text="2.1 Kcal"                ohos:text_alignment="center"                ohos:text_color="#1281f0"                ohos:background_element="$media:aa_1"                ohos:text_size="10fp"                ohos:text_weight="500"/>        </DirectionalLayout>        <DirectionalLayout            ohos:height="match_parent"            ohos:width="match_parent"            ohos:weight="1"            ohos:orientation="vertical"            ohos:alignment="center">            <Text                ohos:height="match_content"                ohos:width="match_content"                ohos:text="实时心率"                ohos:top_margin="5vp"                ohos:text_size="10fp"                ohos:text_weight="500">            </Text>            <Text                ohos:height="60vp"                ohos:width="60vp"                ohos:text="99/min"                ohos:text_alignment="center"                ohos:text_color="#1281f0"                ohos:background_element="$media:aa_1"                ohos:text_size="10fp"                ohos:text_weight="500"/>        </DirectionalLayout>    </DirectionalLayout>    <DirectionalLayout        ohos:id="$+id:tv_blow"        ohos:height="60vp"        ohos:width="match_parent"        ohos:align_parent_bottom="true"        ohos:background_element="#1281f0"        ohos:alignment="center"        ohos:orientation="vertical">        <DirectionalLayout            ohos:height="match_content"            ohos:width="match_parent"            ohos:alignment="center"            ohos:orientation="horizontal">            <Text                ohos:id="$+id:tv_name"                ohos:height="match_content"                ohos:width="match_content"                ohos:text="$string:cardwidget_title"                ohos:text_color="#E5FFFFFF"                ohos:text_size="16fp"                ohos:text_weight="600"/>            <Text                ohos:height="match_content"                ohos:width="match_content"                ohos:text="3350"                ohos:text_color="#E5FFFFFF"                ohos:text_size="16fp"                ohos:text_weight="1000"/>        </DirectionalLayout>        <Text            ohos:height="match_content"            ohos:width="match_content"            ohos:text="$string:cardwidget_introduction"            ohos:text_color="#ffffff"            ohos:text_size="14fp"            ohos:text_weight="800"            ohos:top_margin="7vp"/>    </DirectionalLayout></DirectionalLayout>

form_grid_pattern_cardwidget_2_4.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:background_element="#FFFFFFFF"    ohos:orientation="horizontal"    ohos:remote="true">    <DirectionalLayout        ohos:height="match_parent"        ohos:width="match_parent"        ohos:weight="1"        ohos:orientation="vertical">        <DirectionalLayout            ohos:height="match_parent"            ohos:width="match_parent"            ohos:weight="1"            ohos:orientation="horizontal">            <DirectionalLayout                ohos:height="match_parent"                ohos:width="match_parent"                ohos:weight="1"                ohos:orientation="vertical"                ohos:alignment="center">                <Text                    ohos:height="match_content"                    ohos:width="match_content"                    ohos:text="消耗热量"                    ohos:top_margin="5vp"                    ohos:text_size="10fp"                    ohos:text_weight="500">                </Text>                <Text                    ohos:height="60vp"                    ohos:width="60vp"                    ohos:text="2.1 Kcal"                    ohos:text_alignment="center"                    ohos:text_color="#1281f0"                    ohos:background_element="$media:aa_1"                    ohos:text_size="10fp"                    ohos:text_weight="500"/>            </DirectionalLayout>            <DirectionalLayout                ohos:height="match_parent"                ohos:width="match_parent"                ohos:weight="1"                ohos:orientation="vertical"                ohos:alignment="center">                <Text                    ohos:height="match_content"                    ohos:width="match_content"                    ohos:text="实时心率"                    ohos:top_margin="5vp"                    ohos:text_size="10fp"                    ohos:text_weight="500">                </Text>                <Text                    ohos:height="60vp"                    ohos:width="60vp"                    ohos:text="99/min"                    ohos:text_alignment="center"                    ohos:text_color="#1281f0"                    ohos:background_element="$media:aa_1"                    ohos:text_size="10fp"                    ohos:text_weight="500"/>            </DirectionalLayout>        </DirectionalLayout>        <DirectionalLayout            ohos:height="60vp"            ohos:width="match_parent"            ohos:align_parent_bottom="true"            ohos:background_element="#1281f0"            ohos:alignment="center"            ohos:orientation="vertical">            <DirectionalLayout                ohos:height="match_content"                ohos:width="match_parent"                ohos:alignment="center"                ohos:orientation="horizontal">                <Text                    ohos:height="match_content"                    ohos:width="match_content"                    ohos:text="$string:cardwidget_title"                    ohos:text_color="#E5FFFFFF"                    ohos:text_size="16fp"                    ohos:text_weight="600"/>                <Text                    ohos:height="match_content"                    ohos:width="match_content"                    ohos:text="3350"                    ohos:text_color="#E5FFFFFF"                    ohos:text_size="16fp"                    ohos:text_weight="1000"/>            </DirectionalLayout>            <Text                ohos:height="match_content"                ohos:width="match_content"                ohos:text="$string:cardwidget_introduction"                ohos:text_color="#ffffff"                ohos:text_size="14fp"                ohos:text_weight="800"                ohos:top_margin="7vp"/>        </DirectionalLayout>    </DirectionalLayout>    <DirectionalLayout        ohos:height="match_parent"        ohos:width="match_parent"        ohos:weight="1">    </DirectionalLayout></DirectionalLayout>

第六步、运行程序、查看效果

点击图标上划,出现卡片。

HarmonyOS实战—服务卡片初体验

点击右上角图钉按钮,将卡片放在屏幕中。

HarmonyOS实战—服务卡片初体验

长按应用,出现服务卡片。

HarmonyOS实战—服务卡片初体验

HarmonyOS实战—服务卡片初体验

点击服务卡片选择界面,上下滑动可选择卡片内容。

HarmonyOS实战—服务卡片初体验

HarmonyOS实战—服务卡片初体验

点击添加到桌面,则将卡片添加到桌面中。

HarmonyOS实战—服务卡片初体验

至此,卡片服务应用就以全部开发完成,后续会对卡片内部进行相关编写。使其进行动态的刷新及动态的获取数据。

项目地址: https://github.com/GQ105501/CardDemo

喜欢的请为作者点个喜欢或者赞赏~

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/101949.html

(0)

相关推荐