•准备工作

  首先制作一张 .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. js double 精度损失 bugs

    js double 精度损失 bugs const arr = [ 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01 ]; // [ ...

  2. js web简单的路由管理器

    灵感来自此博客和此库 index.html <!DOCTYPE html> <html lang="en"> <head> <meta c ...

  3. Flutter: AnimatedList 一个滚动容器,可在插入或移除项目时为其设置动画

    Flutter Widget of the Week import 'dart:math'; import 'package:flutter/material.dart'; void main() = ...

  4. 「NGK每日快讯」2021.1.15日NGK公链第73期官方快讯!

  5. Baccarat流动性挖矿的收益能否持续?该如何参与Baccarat流动性挖矿?

    2020年DeFi市场火热,众多投资机构纷纷入场,分享这场资本盛宴.然而,目前市面上大多数DeFi项目手续费高昂,小资金的投资者无法入市.为了让更多的用户参与其中,NGK推出了Baccarat流动性挖 ...

  6. WPF 如何修改button圆角(经典)

    本人想设置Button为圆角,奈何搜索百度,找到的全是坑爹答案,现总结如下: 1. 需要添加button 的template. 2. 设置border的时候,必须要设置background, 否则会提 ...

  7. 1086 Tree Traversals Again——PAT甲级真题

    1086 Tree Traversals Again An inorder binary tree traversal can be implemented in a non-recursive wa ...

  8. ffmpeg第4篇:为视频添加动态水印

    动态分为三种: 水印本身变化 水印显示时间变化 水印位置变化 水印本身变化 看过上一篇的小伙伴可能觉得第一种很简单,把jpg格式的图片换成gif格式的不就可以了吗,然而亲自试一下就会发现,把gif图片 ...

  9. Socket实现简单聊天

    服务端: package main.java.com.socket_dome; import java.io.IOException; import java.io.InputStream; impo ...

  10. Redis缓存中的常见问题

    缓存穿透:是指查询一个Redis和数据库中都不存在的数据. 问题:查询一个Redis和数据库中都不存在的数据,大量请求去访问数据库,导致数据库宕机. 解决办法: 1.根据id查询,如果id是自增的,将 ...