『牛角书』手把手教你用鸿蒙HarmonyOS实现微信聊天界面(一) 原创

发布于 2022-4-15 20:42
浏览
0收藏

简介

本系列文章记录作者大三开学第一个月中学习HarmonyOS移动应用开发学习经历,此篇为《微信聊天界面》项目,实现功能有

1、聊天信息功能,包括图片、文字

2、发送定位功能

3、选择发送本机图片功能

4、拍照并发送图片功能

项目链接 ,如果在真机调试请将config文件中包名换成自己的应用包名即可,申请权限有文件读写、位置获取、相机调用、麦克风调用。
WeChatPage: 鸿蒙版微信界面
https://gitee.com/marshou/WeChatPage
效果如图
『牛角书』手把手教你用鸿蒙HarmonyOS实现微信聊天界面(一)-开源基础软件社区

界面布局

使用的是DirectionalLayout布局,根据权重调整个部分大小。由联系人名称、消息域和输入域组成。参考了微信的UI(毕竟标题是实现微信聊天界面哈哈)。
整体布局代码

<?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:alignment="center"
    ohos:orientation="vertical"
    ohos:id="$+id:root"
    >
 
    <DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:alignment="center"
    ohos:orientation="vertical"
    ohos:background_element="#FFE3DDDD"
    ohos:id="$+id:top"
    ohos:weight="1">
 
        <Text
            ohos:id="$+id:text_name"
            ohos:width="match_parent"
            ohos:height="match_parent"
            ohos:text="张三"
            ohos:text_size="30vp"
            ohos:text_alignment="center"
            ohos:text_color="#FF030303"
            ohos:left_margin="15vp"
            ohos:right_margin="15vp"
            ohos:top_margin="15vp"
            ohos:bottom_margin="15vp"
            ohos:right_padding="15vp"
            ohos:left_padding="15vp"/>
 
        <Text
            ohos:width="match_parent"
            ohos:height="1vp"
            ohos:text_size="18fp"
            ohos:margin="2vp"
            ohos:background_element="#6A000000"/>
    </DirectionalLayout>
 
 
    <DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="0vp"
    ohos:width="match_parent"
    ohos:alignment="center"
    ohos:orientation="vertical"
    ohos:id="$+id:chats"
    ohos:weight="10">
 
        <ListContainer
            ohos:id="$+id:list_container"
            ohos:width="match_parent"
            ohos:weight="1"
            ohos:height="0vp"
            ohos:alignment="top"/>
 
    </DirectionalLayout>
 
    <DirectionalLayout
        xmlns:ohos="http://schemas.huawei.com/res/ohos"
        ohos:height="match_parent"
        ohos:width="match_parent"
        ohos:alignment="center"
        ohos:orientation="vertical"
        ohos:id="$+id:input"
        ohos:weight="1">
 
        <DependentLayout
            xmlns:ohos="http://schemas.huawei.com/res/ohos"
            ohos:width="match_parent"
            ohos:height="match_content"
            ohos:alignment="top"
            ohos:weight="1"
            ohos:background_element="#FFE3DDDD"
            >
 
            <TextField
                ohos:align_parent_left="true"
                ohos:id="$+id:text_message"
                ohos:height="50vp"
                ohos:width="220vp"
                ohos:top_margin="8vp"
                ohos:left_margin="15vp"
                ohos:right_margin="5vp"
                ohos:bottom_margin="8vp"
                ohos:background_element="$graphic:session_background_text_field"
                ohos:right_padding="0vp"
                ohos:text_alignment="vertical_center"
                ohos:text_color="#FF303030"
                ohos:text_size="27vp"
                ohos:multiple_lines="true"
                />
 
            <Button
                ohos:id="$+id:session_button_more"
                ohos:width="45vp"
                ohos:height="45vp"
                ohos:text_size="27fp"
                ohos:text_color="#FF000000"
                ohos:text="+"
                ohos:background_element="$graphic:moreinput_background"
                ohos:top_margin="8vp"
                ohos:left_margin="5vp"
                ohos:right_margin="5vp"
                ohos:bottom_margin="8vp"
                ohos:right_of="$id:text_message"
                />
 
            <Button
                ohos:id="$+id:session_button_send"
                ohos:align_parent_right="true"
                ohos:width="55vp"
                ohos:height="50vp"
                ohos:text_size="27fp"
                ohos:text_color="#FFEAE6E6"
                ohos:text="发送"
                ohos:background_element="$graphic:send_background"
                ohos:top_margin="8vp"
                ohos:left_margin="5vp"
                ohos:right_margin="5vp"
                ohos:bottom_margin="8vp"
                ohos:right_of="$id:session_button_more"
                />
 
        </DependentLayout>
 
    </DirectionalLayout>
 
</DirectionalLayout>

样式代码
session_background_text_field

<?xml version="1.0" encoding="UTF-8" ?>
<shape xmlns:ohos="http://schemas.huawei.com/res/ohos"
       ohos:shape="rectangle">
    <corners
        ohos:radius="30"/>
    <solid
        ohos:color="#FFF8F8F8"/>
</shape>

moreinput_background

<?xml version="1.0" encoding="UTF-8" ?>
<shape xmlns:ohos="http://schemas.huawei.com/res/ohos"
       ohos:shape="oval">
    <stroke
        ohos:width="5"
        ohos:color="#FF6D6B6B"/>
    <solid
        ohos:color="#EDEDED"/>
</shape>

send_background

<?xml version="1.0" encoding="UTF-8" ?>
<shape xmlns:ohos="http://schemas.huawei.com/res/ohos"
       ohos:shape="rectangle">
    <corners
        ohos:radius="30"/>
    <solid
        ohos:color="#FF01CB13"/>
</shape>

消息发送

顶栏联系人名称和底下输入部分布局都比较简单,消息部分是由组件ListContainer实现,由于这个组件中还需要实现子布局也就是分为每个消息内容的布局,根据消息有图片与文本我做了两种消息布局。两种消息布局右侧都是头像。
文本消息布局

<?xml version="1.0" encoding="utf-8"?>
<!--
 Copyright (c) 2021 Huawei Device Co., Ltd.
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
     http://www.apache.org/licenses/LICENSE-2.0
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 -->
<DirectionalLayout xmlns:ohos="http://schemas.huawei.com/res/ohos"
                   ohos:width="match_parent"
                   ohos:orientation="vertical"
                   ohos:top_padding="10vp"
                   ohos:height="match_content">
 
    <DirectionalLayout
        ohos:width="match_parent"
        ohos:orientation="horizontal"
        ohos:padding="2vp"
        ohos:left_padding="45vp"
        ohos:left_margin="0vp"
        ohos:height="match_content"
        ohos:alignment="right">
 
        <Text
            ohos:id="$+id:white"
            ohos:width="match_content"
            ohos:padding_for_text="true"
            ohos:text_color="#FF0C0C0C"
            ohos:layout_alignment="right"
            ohos:height="match_content"
            ohos:text_size="24vp"
            ohos:left_margin="15vp"
            ohos:left_padding="15vp"
            ohos:right_padding="15vp"
            ohos:right_margin="15vp"
            ohos:top_margin="15vp"
            ohos:top_padding="15vp"
            ohos:bottom_margin="15vp"
            ohos:bottom_padding="15vp"
            ohos:multiple_lines="true"
            ohos:margin="5vp"
            ohos:text="  "/>
 
        <Text
            ohos:id="$+id:message"
            ohos:width="match_content"
            ohos:padding_for_text="true"
            ohos:text_color="#FF0C0C0C"
            ohos:background_element="$graphic:message_background"
            ohos:layout_alignment="right"
            ohos:height="match_content"
            ohos:text_size="18vp"
            ohos:left_margin="15vp"
            ohos:left_padding="15vp"
            ohos:right_padding="15vp"
            ohos:right_margin="15vp"
            ohos:top_margin="15vp"
            ohos:top_padding="15vp"
            ohos:bottom_margin="15vp"
            ohos:bottom_padding="15vp"
            ohos:multiple_lines="true"
            ohos:margin="5vp"/>
 
        <Image
            ohos:width="50vp"
            ohos:image_src="$media:rick_c137"
            ohos:height="50vp"
            ohos:scale_mode="stretch"/>
 
    </DirectionalLayout>
 
</DirectionalLayout>

图片消息布局

<?xml version="1.0" encoding="utf-8"?>
<!--
 Copyright (c) 2021 Huawei Device Co., Ltd.
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
     http://www.apache.org/licenses/LICENSE-2.0
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 -->
<DirectionalLayout xmlns:ohos="http://schemas.huawei.com/res/ohos"
                   ohos:width="match_parent"
                   ohos:orientation="vertical"
                   ohos:top_padding="10vp"
                   ohos:height="match_content">
 
    <DirectionalLayout
        ohos:width="match_parent"
        ohos:orientation="horizontal"
        ohos:padding="2vp"
        ohos:left_padding="45vp"
        ohos:left_margin="0vp"
        ohos:height="300vp"
        ohos:alignment="right">
 
        <Text
            ohos:id="$+id:white"
            ohos:width="match_content"
            ohos:padding_for_text="true"
            ohos:text_color="#FF0C0C0C"
            ohos:layout_alignment="right"
            ohos:height="match_content"
            ohos:text_size="24vp"
            ohos:left_margin="15vp"
            ohos:left_padding="15vp"
            ohos:right_padding="15vp"
            ohos:right_margin="15vp"
            ohos:top_margin="15vp"
            ohos:top_padding="15vp"
            ohos:bottom_margin="15vp"
            ohos:bottom_padding="15vp"
            ohos:multiple_lines="true"
            ohos:margin="5vp"
            ohos:text="    "/>
 
        <Image
            ohos:id="$+id:image_message"
            ohos:width="match_content"
            ohos:image_src="$media:rick_c137"
            ohos:height="match_content"
            ohos:scale_mode="zoom_center"
            ohos:background_element="$graphic:message_background"
            ohos:left_margin="15vp"
            ohos:left_padding="15vp"
            ohos:right_padding="15vp"
            ohos:right_margin="15vp"
            ohos:top_margin="15vp"
            ohos:top_padding="15vp"
            ohos:bottom_margin="15vp"
            ohos:bottom_padding="15vp"
            ohos:margin="5vp"/>
 
        <Image
            ohos:width="50vp"
            ohos:image_src="$media:rick_c137"
            ohos:height="50vp"
            ohos:scale_mode="stretch"/>
 
    </DirectionalLayout>
 
</DirectionalLayout>

在这个组件展示需要有类继承BaseItemProvider本项目中为MessageItemProvider,与消息实体类。MessageItemProvider消息是List<AMessage> messageData该属性存储,初始化内容是实现getComponent,update方法更新。
消息实体类,属性有发送消息人名称,消息内容和消息类型,之后根据消息类型来使用不同的布局。

public class AMessage {
 
    private String userName;
 
    private String message;
 
    private String type;
 
    public AMessage(String name, String message) {
        this.userName = name;
        this.message = message;
    }
 
    public AMessage(String name, String message,String type) {
        this.userName = name;
        this.message = message;
        this.type = type;
    }
 
    public String getUserName() {
        return userName;
    }
 
    public void setUserName(String userName) {
        this.userName = userName;
    }
 
    public String getMessage() {
        return message;
    }
 
    public void setMessage(String message) {
        this.message = message;
    }
 
    public String getType() {
        return type;
    }
 
    public void setType(String type) {
        this.type = type;
    }
}

继承BaseItemProvider的类MessageItemProvider,通过字符串类型区分消息是image还是string。有个官方样例中没有单独提到的一点是如何在代码中在Slice类以外的引用布局,这个使用

Component container = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_message_list_item, null, false);

这句代码获得布局。
MessageItemProvider类

public class MessageItemProvider extends BaseItemProvider {
 
    private List<AMessage> messageData;
 
    private final Context context;
 
    public MessageItemProvider(Context context, List<AMessage> messageData) {
        this.messageData = messageData;
        this.context = context;
    }
 
    @Override
    public int getCount() {
        return messageData.size();
    }
 
    @Override
    public Object getItem(int position) {
        return messageData.get(position);
    }
 
    @Override
    public long getItemId(int position) {
        return position;
    }
 
    @Override
    public Component getComponent(int position, Component component, ComponentContainer componentContainer) {
        return getItemComponent(position);
    }
 
    private Component getItemComponent(int position) {
        return getComponent(position);
    }
 
    private Component getComponent(int position) {
        AMessage aMessage = messageData.get(position);
        if(aMessage.getType().equals("string")){
            Component container = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_message_list_item, null, false);
            Text message = (Text) container.findComponentById(ResourceTable.Id_message);
            message.setText(aMessage.getMessage());
            return container;
        }else if(aMessage.getType().equals("image")){
            Component container = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_image_message_list_item, null, false);
            Image image = (Image) container.findComponentById(ResourceTable.Id_image_message);
 
            DataAbilityHelper helper=DataAbilityHelper.creator(context);
            ImageSource imageSource;
            Uri uri = Uri.parse(aMessage.getMessage());
            FileDescriptor fd = null;
            try {
                fd = helper.openFile(uri, "r");
            } catch (DataAbilityRemoteException | FileNotFoundException e) {
                e.printStackTrace();
            }
            imageSource = ImageSource.create(fd, null);
            //创建位图
            PixelMap pixelMap = imageSource.createPixelmap(null);
            image.setPixelMap(pixelMap);
            imageSource.release();
            helper.release();
 
            return container;
        }
        Component container = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_message_list_item, null, false);
        Text message = (Text) container.findComponentById(ResourceTable.Id_message);
        message.setText(aMessage.getMessage());
        return container;
    }
 
 
    /**
     * update list data
     *
     * @param data contactDevicesData list
     */
    public void update(List<AMessage> data) {
        messageData = data;
        notifyDataChanged();
    }
 
}

到这里发消息功能的主要内容就讲完了,之后只要在底下文本框中获取文本然后根据发送BUTTON调用ListContainer更新方法就可以,图片则是通过加载本机图片后增加图片点击方法调用ListContainer的更新方法,具体图片如何加载在之后的文章详讲,也可以在代码中自己找一找。

Gitee链接
https://gitee.com/marshou/WeChatPage

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
标签
2
收藏
回复
举报
回复
添加资源
添加资源将有机会获得更多曝光,你也可以直接关联已上传资源 去关联
    相关推荐