介绍
使用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组件共同来构成,整体是横向布局,布局如下:
页面在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组件共同来构成,整体是横向布局,布局如下:
页面在/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);
});
}
}
效果展示
向下滚动
向上滚动
点击tab图标
完整代码
文章相关附件可以点击下面的原文链接前往下载
原文链接:https://harmonyos.51cto.com/posts/4776#bkwz
https://harmonyos.51cto.com/#bkwz