•准备工作

  首先制作一张 .9 格式的聊天气泡,参见我的这篇博客

  需要注意的是,制作完成后,应该将原始文件删除,否则AS会分不清楚而报错。

  新建一个 Empty Activity,Java 和 XML 文件的命名分别为 MainActivity.java 和 activity_main.xml;

•编写精美的聊天界面

  首先编写主界面,修改 activity_main.xml 中的代码,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp"
android:background="#d8e0e8"> <androidx.recyclerview.widget.RecyclerView
android:id="@+id/msg_recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:orientation="horizontal"> <EditText
android:id="@+id/input_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="Type message here"
android:textAllCaps="false"
android:maxLines="2"
android:gravity="left"/> <Button
android:id="@+id/send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send"
android:textAllCaps="false"
android:textSize="20sp"/>
</LinearLayout> </LinearLayout>

  我们在主界面中放置了一个 RecyclerView 用于显示聊天的消息内容;

  又放置了一个 EditText 用于输入消息,还放置了一个 Button 用于发送消息;

  然后,定义消息的实体类,新建 Msg.java,代码如下:

public class Msg {
public static final int TYPE_RECEIVED = 0;
public static final int TYPE_SEND = 1;
private String content;
private int type; public Msg(String content,int type){
this.content = content;
this.type = type;
} public String getContent() {
return content;
} public int getType() {
return type;
}
}

  Msg 类中只有两个字段:

    • content 表示消息的内容
    • type 表示消息的类型;

  其中消息的类型有两个可选值:

    • TYPE_RECEIVED 表示这是一条收到的消息
    • TYPE_SEND 表示这是一条发出的消息

  接下来编写 RecyclerView 子项的布局,新建 msg_item.xml 文件,添加代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"> <LinearLayout
android:id="@+id/left_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:orientation="vertical"
android:background="@drawable/message_left"> <TextView
android:id="@+id/left_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="10dp"
android:textColor="@color/black"/> </LinearLayout> <LinearLayout
android:id="@+id/right_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:orientation="vertical"
android:background="@drawable/message_left"> <TextView
android:id="@+id/right_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="10dp"
android:textColor="@color/black"/> </LinearLayout>
</LinearLayout>

  这里我们让收到的消息居左对齐,发出的消息居右对其;

  并且使用 message_left.9 作为聊天气泡;

  接下来需要创建 RecyclerView 的适配器类,新建 MsgAdapter.java,添加代码如下:

public class MsgAdapter extends RecyclerView.Adapter<MsgAdapter.ViewHolder>{

    private List<Msg> list;
public MsgAdapter(List<Msg> list){
this.list = list;
}
static class ViewHolder extends RecyclerView.ViewHolder{
LinearLayout leftLayout;
TextView left_msg; LinearLayout rightLayout;
TextView right_msg; public ViewHolder(View view){
super(view);
leftLayout = view.findViewById(R.id.left_layout);
left_msg = view.findViewById(R.id.left_msg); rightLayout = view.findViewById(R.id.right_layout);
right_msg = view.findViewById(R.id.right_msg);
}
} @NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.msg_item,parent,false);
return new ViewHolder(view);
} @Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Msg msg = list.get(position);
if(msg.getType() == Msg.TYPE_RECEIVED){
//如果是收到的消息,则显示左边的消息布局,将右边的消息布局隐藏
holder.leftLayout.setVisibility(View.VISIBLE);
holder.left_msg.setText(msg.getContent()); //注意此处隐藏右面的消息布局用的是 View.GONE
holder.rightLayout.setVisibility(View.GONE);
}else if(msg.getType() == Msg.TYPE_SEND){
//如果是发出的消息,则显示右边的消息布局,将左边的消息布局隐藏
holder.rightLayout.setVisibility(View.VISIBLE);
holder.right_msg.setText(msg.getContent()); //同样使用View.GONE
holder.leftLayout.setVisibility(View.GONE);
}
} @Override
public int getItemCount() {
return list.size();
}
}

  最后修改 MainActivity.java 中的代码,来为 RecyclerView 初始化一些数据,并给发送按钮加入事件响应;

  代码如下:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
private List<Msg> msgList = new ArrayList<>();
private RecyclerView msgRecyclerView;
private EditText inputText;
private Button send;
private LinearLayoutManager layoutManager;
private MsgAdapter adapter; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); msgRecyclerView = findViewById(R.id.msg_recycler_view);
inputText = findViewById(R.id.input_text);
send = findViewById(R.id.send);
layoutManager = new LinearLayoutManager(this);
adapter = new MsgAdapter(msgList = getData()); msgRecyclerView.setLayoutManager(layoutManager);
msgRecyclerView.setAdapter(adapter); /* 我们还需要为button建立一个监听器,我们需要将编辑框的内容发送到 RecyclerView 上:
①获取内容,将需要发送的消息添加到 List 当中去。
②调用适配器的notifyItemInserted方法,通知有新的数据加入了,赶紧将这个数据加到 RecyclerView 上面去。
③调用RecyclerView的scrollToPosition方法,以保证一定可以看的到最后发出的一条消息。*/
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String content = inputText.getText().toString();
if(!content.equals("")) {
msgList.add(new Msg(content,Msg.TYPE_SEND));
adapter.notifyItemInserted(msgList.size()-1);
msgRecyclerView.scrollToPosition(msgList.size()-1);
inputText.setText("");//清空输入框中的内容
}
// 自定义一问一答
if(msgList.size() == 2){
msgList.add(new Msg("What's your name?",Msg.TYPE_RECEIVED));
adapter.notifyItemInserted(msgList.size()-1);
msgRecyclerView.scrollToPosition(msgList.size()-1);
}
if(msgList.size() == 4){
msgList.add(new Msg("Nice to meet you,Bye!",Msg.TYPE_RECEIVED));
adapter.notifyItemInserted(msgList.size()-1);
msgRecyclerView.scrollToPosition(msgList.size()-1);
}
}
});
} private List<Msg> getData(){
List<Msg> list = new ArrayList<>();
list.add(new Msg("Hello",Msg.TYPE_RECEIVED));
return list;
}
}

•运行效果

  

Android Studio 之 编写精美的聊天界面的更多相关文章

  1. 0.[WP Developer体验Andriod开发]之从零安装配置Android Studio并编写第一个Android App

    0. 所需的安装文件 笔者做了几年WP,近来对Android有点兴趣,尝试一下Android开发,废话不多说,直接进入主题,先安装开发环境,笔者的系统环境为windows8.1&x64. 安装 ...

  2. 0.[Andriod]之从零安装配置Android Studio并编写第一个Android App

    0. 所需的安装文件 笔者做了几年WP,近来对Android有点兴趣,尝试一下Android开发,废话不多说,直接进入主题,先安装开发环境,笔者的系统环境为windows8.1&x64. 安装 ...

  3. Android Studio 使用笔记:在图形界面使用 Gradle 配置项目所需jar包

    在 Android Studio 中使用第三方 jar 包,可以直接下载后添加到项目中,也可以使用 Gradle 配置进行管理.图形界面下十分简单. 点击下图中间的图标,或者选中 Model ,按F4 ...

  4. 【Android】17.0 UI开发(八)——利用RecyclerView列表控件实现精美的聊天界面

    1.0 首先新建一个项目,名叫:UIBestPractice,目录如下: 2.0 这里需要先准备两张图片,放在app\src\main\res\drawable-xhdpi目录下. 这里图片名称已经制 ...

  5. 从0系统学Android--3.7 聊天界面编写

    从0系统学Android--3.7 聊天界面编写 本系列文章目录:更多精品文章分类 本系列持续更新中.... 3.7 编写界面的最佳实践 前面学习了那么多 UI 开发的知识,下面来进行实践,做一个美观 ...

  6. Android基础-系统架构分析,环境搭建,下载Android Studio,AndroidDevTools,Git使用教程,Github入门,界面设计介绍

    系统架构分析 Android体系结构 安卓结构有四大层,五个部分,Android分四层为: 应用层(Applications),应用框架层(Application Framework),系统运行层(L ...

  7. Android Studio 1.0.2项目实战——从一个APP的开发过程认识Android Studio

    Android Studio 1.0.1刚刚发布不久,谷歌紧接着发布了Android Studio 1.0.2版本,和1.0.0一样,是一个Bug修复版本.在上一篇Android Studio 1.0 ...

  8. Android 开发之Windows环境下Android Studio安装和使用教程(图文详细步骤)

    鉴于谷歌最新推出的Android Studio备受开发者的推崇,所以也跟着体验一下. 一.介绍Android Studio  Android Studio 是一个Android开发环境,基于Intel ...

  9. Windows环境下Android Studio安装和使用教程

    Windows环境下Android Studio安装和使用教程 来源: http://www.cnblogs.com/liuhongfeng/archive/2015/12/30/5084896.ht ...

随机推荐

  1. D language

    D language https://en.wikipedia.org/wiki/D_(programming_language) Dart https://dlang.org/ flutter fr ...

  2. multi selects & mutually exclusive

    multi selects & mutually exclusive 互斥 selects import React, { useState, // useEffect, // useRef, ...

  3. React Hooks & react forwardRef hooks & useReducer

    React Hooks & react forwardref hooks & useReducer react how to call child component method i ...

  4. c++ string split function

    #include <string> #include <vector> #include <regex> struct SplitListItem { std::s ...

  5. .gitignore规则不生效

    .gitignore只能忽略那些原来没有被track的文件,如果某些文件已经被纳入了版本管理中,则修改.gitignore是无效的. 解决方法就是先把本地缓存删除(改变成未track状态),然后再提交 ...

  6. NGK DeFi Baccarat怎么玩能赚钱?

    市面上大多数DeFi项目都是基于以太坊来开发的,除了吞吐量低.存储量小以及交易速度慢等问题以外,高额的Gas手续费将不少终端用户拒之门外. 基于此NGK.IO推出了低门槛的DeFi项目-- Bacca ...

  7. 关于Python 编码的一点认识

    在计算机中,所有数据的存储.运算以及传输都必须是二进制数字,因为计算机只认识0和1. 当一个人把一份数据传给另一个人时,计算机传递的是其实是二进制数字,但这些数字需要被还原为原始信息. 这个工作当然是 ...

  8. 经典面试题:在浏览器地址栏输入一个 URL 后回车,背后发生了什么

    尽人事,听天命.博主东南大学硕士在读,热爱健身和篮球,乐于分享技术相关的所见所得,关注公众号 @ 飞天小牛肉,第一时间获取文章更新,成长的路上我们一起进步 本文已收录于 CS-Wiki(Gitee 官 ...

  9. vue_webpack

    1.生成项目工程描述文件 npm init 2.安装webpack开发依赖 (本地安装):npm install -D 3.(webpack4.0版本以上安装webpack cli) npm inst ...

  10. ElasticSearch 中的 Mapping

    公号:码农充电站pro 主页:https://codeshellme.github.io 1,ES 中的 Mapping ES 中的 Mapping 相当于传统数据库中的表定义,它有以下作用: 定义索 ...