HarmonyOS官方模板学习 之 About Feature Ability(Java)

介绍

使用Java语言开发,用于Phone设备的Feature Ability模板,使用XML布局。
展示了一个名片详情页的样例工程,主要由一个ScrollView嵌套的两个ListContainer组成。

搭建环境

安装DevEco Studio,详情请参考DevEco Studio下载。
设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:

如果可以直接访问Internet,只需进行下载HarmonyOS SDK操作。
如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境。

代码结构解读

功能逻辑代码

└─businesscardabilityjava
        │  MainAbility.java
        │  MyApplication.java
        │
        ├─datamodel //数据模型
        │      DefaultDoubleLineListItemInfo.java
        │      ItemInfo.java
        │      SingleButtonDoubleLineListItemInfo.java
        │
        ├─itemprovider //子项提供者
        │      ListItemProvider.java
        │
        ├─slice //核心页面
        │      MainAbilitySlice.java
        │
        ├─typefactory //列表类型工厂
        │      ListTypeFactory.java
        │      TypeFactory.java
        │
        └─viewholder  //视图持有者
                DefaultDoubleLineList.java
                SingleButtonDoubleLineList.java
                ViewHolder.java

布局及样式代码

└─resources
    ├─base
    │  ├─element
    │  │      color.json //存储了页面的一些颜色值
    │  │      float.json
    │  │      string.json
    │  │
    │  ├─graphic
    │  │      bottom_tab_background.xml //tab栏背景样式
    │  │      card_background.xml //卡片背景样式
    │  │      divider.xml //分割线样式
    │  │      ic_about.xml
    │  │      ic_actived.xml
    │  │      ic_add.xml
    │  │      ic_back.xml
    │  │      ic_call.xml
    │  │      ic_chat.xml
    │  │      ic_edit.xml //编辑tab按钮icon
    │  │      ic_edit_actived.xml //激活状态编辑tab按钮icon
    │  │      ic_enabled.xml
    │  │      ic_favorite.xml //收藏tab按钮icon
    │  │      ic_favorite_actived.xml //激活状态收藏tab按钮icon
    │  │      ic_header.xml //联系人头像icon
    │  │      ic_more.xml
    │  │      ic_mores.xml //更多tab按钮icon
    │  │      ic_mores_actived.xml //激活状态更多tab按钮icon
    │  │      ic_next.xml
    │  │      ic_normal.xml
    │  │      ic_qrcode.xml
    │  │      ic_video.xml
    │  │
    │  ├─layout
    │  │      ability_main.xml //名片主页面
    │  │      default_doublelinelist.xml //默认双行列表项组件页面
    │  │      singlebutton_doublelinelist.xml //单按钮双行列表项组件页面
    │  │      tab.xml //tab按钮组件页面
    │  │
    │  ├─media
    │  │      icon.png
    │  │      ic_next.png
    │  │      ic_update.png
    │  │      like_icon.jpg
    │  │      profile.png
    │  │      profile_mask.png
    │  │      search.jpg
    │  │      share_icon.jpg
    │  │
    │  └─profile
    └─rawfile

页面布局

1.主页面

本页面的布局包括DependentLayout和DirectionalLayout布局,
由ScrollView、ListContainer、Image、Text组件共同来构成,整体分为上中下布局。
上方是应用工具栏,使用了DirectionalLayout嵌套横向布局,布局中用Image组件提供了返回和二维码的功能,2个布局权重是1:1

中间是联系人的头像和姓名以及联系人其它信息列表,由于列表长度不固定采用了ScrollView组件,内部使用DependentLayout布局嵌套的方式,用DependentLayout包裹ListContainer组件用于列表的展示,其中列表项是由后台通过自定义的2行列表组件动态创建。

底部是联系人可操作的功能区,包括收藏、编辑、更多,采用了DirectionalLayout 嵌套布局,外层DirectionalLayout 用户背景显示,内层DirectionalLayout 用户内容的显示,其中内容的显示是通过自定义tab组件由后台动态创建实现的。

页面在resources\base\layout\ability_main.xml 代码如下:

<?xml version="1.0" encoding="utf-8"?>
<DependentLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:id="$+id:root_layout"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:orientation="vertical">

    <DirectionalLayout
        ohos:id="$+id:background"
        ohos:height="match_parent"
        ohos:width="match_parent"
        ohos:align_parent_top="true"
        ohos:background_element="$color:color_background"/>

    <DirectionalLayout
        ohos:id="$+id:appBar"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:align_parent_top="true"
        ohos:end_padding="$float:max_padding_appBar"
        ohos:layout_direction="locale"
        ohos:orientation="horizontal"
        ohos:start_padding="$float:max_padding_start">

        <DirectionalLayout
            ohos:id="$+id:appBar_leftPart"
            ohos:height="$float:height_backButton_touchTarget"
            ohos:width="0vp"
            ohos:alignment="center"
            ohos:orientation="horizontal"
            ohos:weight="1">

            <Image
                ohos:id="$+id:appBar_backButton"
                ohos:height="$float:height_appBar_Buttons"
                ohos:width="$float:width_appBar_buttons"
                ohos:image_src="$graphic:ic_back"/>

            <Text
                ohos:id="$+id:appBar_userName"
                ohos:height="match_parent"
                ohos:width="match_parent"
                ohos:alpha="0"
                ohos:left_margin="$float:leftMargin_userName"
                ohos:text="$string:title_contactsDetail"
                ohos:text_size="$float:textSize_userName"/>
        </DirectionalLayout>

        <DirectionalLayout
            ohos:id="$+id:appBar_rightPart"
            ohos:height="match_parent"
            ohos:width="0vp"
            ohos:alignment="vertical_center|right"
            ohos:focusable_in_touch="false"
            ohos:orientation="horizontal"
            ohos:start_margin="$float:start_margin_appBar"
            ohos:weight="1">

            <DirectionalLayout
                ohos:id="$+id:appBar_button3_touchTarget"
                ohos:height="$float:height_touchTarget"
                ohos:width="$float:width_touchTarget"
                ohos:alignment="center">

                <Image
                    ohos:id="$+id:appBar_button3"
                    ohos:height="$float:height_appBar_Buttons"
                    ohos:width="$float:width_appBar_buttons"
                    ohos:image_src="$graphic:ic_qrcode"/>
            </DirectionalLayout>
        </DirectionalLayout>
    </DirectionalLayout>

    <ScrollView
        ohos:id="$+id:contacts_detail_scroll"
        ohos:height="match_parent"
        ohos:width="match_parent"
        ohos:below="$id:appBar"
        ohos:bottom_margin="$float:height_bottom_tab">

        <DependentLayout
            ohos:id="$+id:contacts_detail"
            ohos:height="match_content"
            ohos:width="match_parent"
            ohos:orientation="vertical">

            <DependentLayout
                ohos:id="$+id:contacts_detail_upperCard"
                ohos:height="match_content"
                ohos:width="match_parent"
                ohos:align_parent_top="true"
                ohos:background_element="$graphic:card_background"
                ohos:left_padding="$float:max_padding_start"
                ohos:orientation="vertical"
                ohos:right_padding="$float:max_padding_end"
                ohos:top_margin="$float:topMargin_contactsDetail_upperCard">

                <ListContainer
                    ohos:id="$+id:contacts_detail_upperCard_list"
                    ohos:height="0vp"
                    ohos:width="match_parent"
                    ohos:below="$+id:contacts_detail_title"/>
            </DependentLayout>

            <Image
                ohos:id="$+id:contacts_detail_profile"
                ohos:height="$float:height_contacts_profile"
                ohos:width="$float:width_contacts_profile"
                ohos:align_parent_top="true"
                ohos:alpha="1"
                ohos:center_in_parent="true"
                ohos:image_src="$graphic:ic_header"
                ohos:top_margin="$float:topMargin_contacts_profile"/>

            <Text
                ohos:id="$+id:contacts_detail_title"
                ohos:height="match_content"
                ohos:width="match_parent"
                ohos:align_parent_top="true"
                ohos:text="$string:title_contactsDetail"
                ohos:text_alignment="horizontal_center"
                ohos:text_size="$float:textSize_contactsDetail_title"
                ohos:top_margin="$float:topMargin_contactsDetail_title"/>
        </DependentLayout>
    </ScrollView>

    <DirectionalLayout
        ohos:id="$+id:bottom_tab"
        ohos:height="$float:height_bottom_tab"
        ohos:width="match_parent"
        ohos:align_parent_bottom="true"
        ohos:alignment="vertical_center"
        ohos:background_element="$graphic:bottom_tab_background"
        ohos:left_padding="$float:max_padding_start"
        ohos:right_padding="$float:max_padding_end">

        <DirectionalLayout
            ohos:id="$+id:bottom_tabMenu"
            ohos:height="match_content"
            ohos:width="match_parent"
            ohos:orientation="horizontal"/>
    </DirectionalLayout>
</DependentLayout>

2.默认双行列表项组件页面

本页面的布局包括DirectionalLayout布局,
由Image、Text组件共同来构成,整体是横向布局,布局如下:
HarmonyOS官方模板学习 之 About Feature Ability(Java)
页面在resources\layout\default_doublelinelist.xml ,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:id="$+id:default_doubleLineList"
    ohos:height="$float:height_doubleLineList"
    ohos:width="match_parent"
    ohos:orientation="vertical">

    <DirectionalLayout
        xmlns:ohos="http://schemas.huawei.com/res/ohos"
        ohos:id="$+id:doubleLineList"
        ohos:height="$float:height_doubleLineList_text"
        ohos:width="match_parent"
        ohos:bottom_margin="$float:bottomMargin_doubleLineList"
        ohos:orientation="horizontal"
        ohos:top_margin="$float:topMargin_doubleLineList">

        <DirectionalLayout
            ohos:id="$+id:doubleLineList_text"
            ohos:height="match_parent"
            ohos:width="match_parent"
            ohos:alignment="vertical_center"
            ohos:orientation="vertical"
            ohos:weight="2">

            <DirectionalLayout
                ohos:id="$+id:doubleLineList_text_layout"
                ohos:height="match_parent"
                ohos:width="match_content"
                ohos:layout_direction="locale">

                <Text
                    ohos:id="$+id:doubleLineList_text_primary"
                    ohos:height="match_content"
                    ohos:width="match_parent"
                    ohos:bottom_margin="$float:bottomMargin_doubleLineList"
                    ohos:layout_direction="locale"
                    ohos:text_color="$color:color_doubleLineList_primary_text"
                    ohos:text_size="$float:textSize_primaryText"/>

                <Text
                    ohos:id="$+id:doubleLineList_text_secondary"
                    ohos:height="match_content"
                    ohos:width="match_parent"
                    ohos:layout_direction="locale"
                    ohos:text_color="$color:color_doubleLineList_secondary_text"
                    ohos:text_size="$float:textSize_secondaryText"/>
            </DirectionalLayout>
        </DirectionalLayout>

        <DirectionalLayout
            ohos:id="$+id:doubleLineList_right"
            ohos:height="match_parent"
            ohos:width="match_parent"
            ohos:alignment="vertical_center|right"
            ohos:orientation="horizontal"
            ohos:right_of="$+id:doubleLineList_text"
            ohos:weight="2">

            <DirectionalLayout
                ohos:id="$+id:doubleLineList_right_touchTarget1"
                ohos:height="$float:height_touchTarget"
                ohos:width="$float:width_touchTarget"
                ohos:alignment="center">

                <Image
                    ohos:id="$+id:doubleLineList_right_img1"
                    ohos:height="$float:height_doubleLineList_button"
                    ohos:width="$float:width_doubleLineList_button"/>
            </DirectionalLayout>

            <DirectionalLayout
                ohos:id="$+id:doubleLineList_right_touchTarget2"
                ohos:height="$float:height_touchTarget"
                ohos:width="$float:width_touchTarget"
                ohos:alignment="center">

                <Image
                    ohos:id="$+id:doubleLineList_right_img2"
                    ohos:height="$float:height_doubleLineList_button"
                    ohos:width="$float:width_doubleLineList_button"/>
            </DirectionalLayout>

            <DirectionalLayout
                ohos:id="$+id:doubleLineList_right_touchTarget3"
                ohos:height="$float:height_touchTarget"
                ohos:width="$float:width_touchTarget"
                ohos:alignment="center">

                <Image
                    ohos:id="$+id:doubleLineList_right_img3"
                    ohos:height="$float:height_doubleLineList_button"
                    ohos:width="$float:width_doubleLineList_button"/>
            </DirectionalLayout>
        </DirectionalLayout>
    </DirectionalLayout>

    <Image
        ohos:id="$+id:divider"
        ohos:height="$float:height_divider"
        ohos:width="match_parent"
        ohos:image_src="$graphic:divider"/>
</DirectionalLayout>

3.单按钮双行列表项组件页面

本页面和默认双行列表组件页面基本一致,只是布局中只有一个操作按钮,使用DirectionalLayout布局,
由Image、Text组件共同来构成,整体是横向布局,布局如下:
HarmonyOS官方模板学习 之 About Feature Ability(Java)
页面在/resources/base/layout/singlebutton_doublelinelist.xml,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:id="$+id:singleButton_doubleLineList"
    ohos:height="$float:height_doubleLineList"
    ohos:width="match_parent"
    ohos:orientation="vertical">

    <DirectionalLayout
        xmlns:ohos="http://schemas.huawei.com/res/ohos"
        ohos:id="$+id:singleButtonList"
        ohos:height="$float:height_doubleLineList_text"
        ohos:width="match_parent"
        ohos:bottom_margin="$float:bottomMargin_doubleLineList"
        ohos:orientation="horizontal"
        ohos:top_margin="$float:topMargin_doubleLineList">

        <DirectionalLayout
            ohos:id="$+id:singleButtonList_text"
            ohos:height="match_parent"
            ohos:width="match_parent"
            ohos:alignment="vertical_center"
            ohos:orientation="vertical"
            ohos:weight="2">
            <DirectionalLayout
                ohos:height="match_parent"
                ohos:width="match_content"
                ohos:layout_direction="locale">
                <Text
                    ohos:id="$+id:singleButtonList_text_primary"
                    ohos:height="match_content"
                    ohos:width="match_content"
                    ohos:bottom_margin="$float:bottomMargin_doubleLineList"
                    ohos:layout_direction="locale"
                    ohos:text_color="$color:color_doubleLineList_primary_text"
                    ohos:text_size="$float:textSize_primaryText"/>

                <Text
                    ohos:id="$+id:singleButtonList_text_secondary"
                    ohos:height="match_content"
                    ohos:width="match_content"
                    ohos:layout_direction="locale"
                    ohos:text_color="$color:color_doubleLineList_secondary_text"
                    ohos:text_size="$float:textSize_secondaryText"/>
            </DirectionalLayout>
        </DirectionalLayout>

        <DirectionalLayout
            ohos:id="$+id:singleButtonList_right"
            ohos:height="match_parent"
            ohos:width="match_parent"
            ohos:alignment="vertical_center|right"
            ohos:layout_direction="locale"
            ohos:weight="1">
            <DirectionalLayout
                ohos:height="match_content"
                ohos:width="match_content"
                ohos:layout_direction="locale">
                <DirectionalLayout
                    ohos:id="$+id:singleButtonList_right_touchTarget"
                    ohos:height="$float:height_touchTarget"
                    ohos:width="$float:width_touchTarget"
                    ohos:alignment="center">
                    <Image
                        ohos:id="$+id:singleButtonList_right_img"
                        ohos:height="$float:height_doubleLineList_switch"
                        ohos:width="$float:width_doubleLineList_switch"/>
                </DirectionalLayout>
            </DirectionalLayout>
        </DirectionalLayout>
    </DirectionalLayout>

    <Image
        ohos:id="$+id:divider"
        ohos:height="$float:height_divider"
        ohos:width="match_parent"
        ohos:image_src="$graphic:divider"/>
</DirectionalLayout>

4.Tab 组件页面

自定义的tab组件,用于动态渲染tab栏,使用DirectionalLayout布局,
由Image、Text组件共同来构成,整体是垂直布局。

页面在resources/base/layout/tab.xml,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:id="$+id:tab"
    ohos:height="match_content"
    ohos:width="0vp"
    ohos:alignment="center"
    ohos:orientation="vertical"
    ohos:weight="1">

    <Image
        ohos:id="$+id:bottom_tab_button_image"
        ohos:height="$float:height_tab"
        ohos:width="$float:width_tab"
        />

    <Text
        ohos:id="$+id:bottom_tab_button_text"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:text_alignment="top|horizontal_center"
        ohos:text_color="$color:color_tabText_normal"
        ohos:text_size="$float:textSize_tab"
        />

</DirectionalLayout>

说明:
布局文件中使用到了一些样式和图片,在resources\base\graphic下有做定义,详情可以参考完整代码。

相关权限

不需要额外申请权限

tab 按钮切换的业务逻辑

将动态添加的tab按钮存储到List中并进行遍历,设置当前点击的tab按钮为激活样式,其它tab按钮设置为普通效果。
后台代码在 /slice/MainAbilitySlice.java 关键代码如下:

tab.setClickedListener(component -> {
                Text focusTab = (Text) component.findComponentById(ResourceTable.Id_bottom_tab_button_text);
                //Set active tab image
                setActiveTabImage(tabList, focusTab.getText());

});
/**
     * 
     * @param tabList tab按钮列表
     * @param focusText 需要激活的tab名称
     */
    private void setActiveTabImage(List<DirectionalLayout> tabList, String focusText) {

        Element tabNormal = null;
        Element tabActived = null;
        for (DirectionalLayout btn : tabList) {
            Text text = (Text) btn.findComponentById(ResourceTable.Id_bottom_tab_button_text);
            if ("收藏".equals(text.getText())) {
                tabNormal = ElementScatter.getInstance(getContext()).parse(ResourceTable.Graphic_ic_favorite);
                tabActived = ElementScatter.getInstance(getContext()).parse(ResourceTable.Graphic_ic_favorite_actived);
                if ("收藏".equals(focusText)) {
                    ((Image) btn.findComponentById(ResourceTable.Id_bottom_tab_button_image)).setImageElement(tabActived);
                } else {
                    ((Image) btn.findComponentById(ResourceTable.Id_bottom_tab_button_image)).setImageElement(tabNormal);
                }
            }
            if ("编辑".equals(text.getText())) {
                tabNormal = ElementScatter.getInstance(getContext()).parse(ResourceTable.Graphic_ic_edit);
                tabActived = ElementScatter.getInstance(getContext()).parse(ResourceTable.Graphic_ic_edit_actived);
                if ("编辑".equals(focusText)) {
                    ((Image) btn.findComponentById(ResourceTable.Id_bottom_tab_button_image)).setImageElement(tabActived);
                } else {
                    ((Image) btn.findComponentById(ResourceTable.Id_bottom_tab_button_image)).setImageElement(tabNormal);
                }
            }
            if ("更多".equals(text.getText())) {
                tabNormal = ElementScatter.getInstance(getContext()).parse(ResourceTable.Graphic_ic_mores);
                tabActived = ElementScatter.getInstance(getContext()).parse(ResourceTable.Graphic_ic_mores_actived);
                if ("更多".equals(focusText)) {
                    ((Image) btn.findComponentById(ResourceTable.Id_bottom_tab_button_image)).setImageElement(tabActived);
                } else {
                    ((Image) btn.findComponentById(ResourceTable.Id_bottom_tab_button_image)).setImageElement(tabNormal);
                }
            }
        }
    }

滑动效果实现的业务逻辑

向上/下滑动滚动条,显示和隐藏顶部应用栏中联系人姓名(通过设置文字透明度实现)和更改背景的效果(更改背景色)
后台代码在 /slice/MainAbilitySlice.java 关键代码如下:

private void initScrollView() {
        ScrollView scrollView = (ScrollView) findComponentById(ResourceTable.Id_contacts_detail_scroll);
        int profileSizePx = AttrHelper.vp2px(COLOR_CHANGE_RANGE, this);
        if (scrollView != null) {
            scrollView.setReboundEffectParams(OVERSCROLL_PERCENT, OVERSCROLL_RATE, REMAIN_VISIBLE_PERCENT);
            scrollView.setReboundEffect(true);
            //获取appbar显示的contact name
            Text userName = (Text) findComponentById(ResourceTable.Id_appBar_userName);

            DirectionalLayout backGround = (DirectionalLayout) findComponentById(ResourceTable.Id_background);
            ShapeElement shapeElement = new ShapeElement();
            shapeElement.setShape(ShapeElement.RECTANGLE);

            // Set Scrolled listener
            scrollView.getComponentTreeObserver().addScrolledListener(() -> {

                float curY = scrollView.getScrollValue(Component.AXIS_Y);
                HiLog.info(LABEL, "curY:" + curY);

                int colorChange = (int) ((BACKGROUND_COLOR - ORIGINAL_BACKGROUND_COLOR) * curY / profileSizePx);
                HiLog.info(LABEL, "colorChange:" + colorChange);
                HiLog.info(LABEL, "colorValue:" + (ORIGINAL_BACKGROUND_COLOR + colorChange));

                //设置颜色的方法
                //1.设置ability_main.xml组件中的背景色,如:240/160/110,这是一个橙色
                //2.手动加上刚才的值,如240/160/110

                shapeElement.setRgbColor(new RgbColor(ORIGINAL_BACKGROUND_COLOR + colorChange+240,
                        ORIGINAL_BACKGROUND_COLOR + colorChange+160, ORIGINAL_BACKGROUND_COLOR + colorChange+110));
                backGround.setBackground(shapeElement);

                userName.setAlpha(1 * curY / profileSizePx);
            });
        }
    }

效果展示

HarmonyOS官方模板学习 之 About Feature Ability(Java)

向下滚动
HarmonyOS官方模板学习 之 About Feature Ability(Java)
向上滚动
HarmonyOS官方模板学习 之 About Feature Ability(Java)
点击tab图标
HarmonyOS官方模板学习 之 About Feature Ability(Java)

完整代码

文章相关附件可以点击下面的原文链接前往下载

原文链接:https://harmonyos.51cto.com/posts/4776#bkwz

想了解更多关于鸿蒙的内容,请访问:

51CTO和华为官方战略合作共建的鸿蒙技术社区

https://harmonyos.51cto.com/#bkwz

上一篇:HarmonyOS (鸿蒙操作系统)你值得拥有


下一篇:使用Data Ability读取系统设置项