0%

低仿微信聊天界面的实现

概要:今天想运用一下已学的知识试着实现一下微信的聊天界面。主要实现的功能只是聊天内容的发送和显示。
这其实是《第一行代码》中的一个实战样例,主要想记录一下心得体会。

First

定义一个消息类Msg.class。主要属性有,消息的内容,消息的类型(接受的还是发送的),并定义两个方法用于get内容与类型。

Second

布局主界面。

界面主要是对话列表与底下的输入框及输入按钮组成。先定义一个RecyclerView列表布局,当然,需要现在build.gradle中先添加依赖。

1
2
implementation 'com.android.support:recyclerview-v7:24.2.1'
//官方已不支持使用compile

然后就可以愉快的使用RecyclerView啦。

对话列表布局

布局完主界面就要对列表子项进行布局,即设置我们的对话框。新建一个message.xml,注意父布局宽度应为wrap_content。因为对话框接收与发送的方向不同,所以需要设置两个子布局,然后使用时再在代码中对其中一个进行隐藏。
接着是设置对话框的气泡图片。在网上搜到合适的对话框图片然后添加到res/drawable文件夹中。建议图片的尺寸最好小一点,这样最后效果好看一点。
这里还要插入一个知识点:

Nine-Patch图片的使用

以前制作.9图片,需要使用Android sdk/tools/draw9patch.bat,但AndroidStudio开始,就将此功能集成到了IDE中。只要右键png图片选择Create 9-Patch file即可创建。
.9图片有什么用呢,它能更方便于做出更好的图片效果。
打开.9.png,拖动图片边框黑点,左上边框用于定义图片可被拉长的部分,右下边框用于定义图片被添加内容时的位置,这样即使的我们布局时候更加方便。

Third

定义列表的配适器,建立recyclerview与数据间的联系
一直认为自定义列表配适器特别麻烦,但是写多了,思路也就清晰了。

构造方法

首先定义一个成员变量用于接收数据内容,一般是一个list。然后在构造方法中进行数据的赋值。
然后这个Adapter需要继承自RecyclerView.Adapter<Adapter类名.HolderView>

定义一个子类ViewHolder类(继承自RecyclerView.Holder)

这个类用于缓存数据内容,无需重复获取控件的实例,提高list的运行效率。
首先定义成员变量,都是需要缓存的数据或控件。接着是构造方法,需传入一个RecyclerView子项的最外层布局的view,直接传给ViewHolder的父级构造方法,然后开始对view中的控件进行获取和赋值。

加载布局,在代码中获取并将布局返回

1
2
3
4
5
6
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.message, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}

这部分代码一般没有太多改动,其中R.layout.message是要加载布局的定义。

将数据添加到布局中,子项滚动进入屏幕时执行

在这里进行消息类型的判断,用setVisibility()对布局进行显示或隐藏。

####
最后是一个每次必须重写的方法,获取子项个数。

自此Adapter就已经准备完毕,逐个理解并多加实践便不会觉得太复杂。

Forth

到此一切准备就绪,可以开始编写MainActivity。

首先定义数据列表,msg配适器,获取EditText,Button,RecyclerView实例,定义一个LinearLayoutManager,指定RecyclerView的布局方式

然后将数据列表传入配适器,指定RecyclerView的配适器。

最后设置Button的点击事件,先获取输入框内容新建一个Msg对象并添加到列表,

使用adapter.notifyItemInserted(list.size() - 1),实现有新消息时刷新RecyclerView的显示

然后recyclerview.scrollToPosition(list.size() - 1),实现将RecyclerView定位到最后一行,使每次增加对话后不会回到顶部。

到这里就大功告成了。
如果愿意的话,可以先初始化一部分Msg数据用于一开始的显示。


源码

下面贴出源代码

MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

ArrayList<Msg> msgList = new ArrayList<Msg>();

private TextView textView;

private RecyclerView msgRecycleView;

private MsgAdapter adapter;

private LinearLayoutManager manager;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

initMsg();
msgRecycleView = (RecyclerView) findViewById(R.id.list);
manager = new LinearLayoutManager(this);
msgRecycleView.setLayoutManager(manager);
adapter = new MsgAdapter(msgList);
msgRecycleView.setAdapter(adapter);

Button send = (Button) findViewById(R.id.send);
textView = findViewById(R.id.text);
textView.setText("");
send.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
String content = textView.getText().toString();
Msg msg = new Msg(content ,1);
msgList.add(msg);
msgRecycleView.setLayoutManager(manager);
adapter = new MsgAdapter(msgList);
msgRecycleView.scrollToPosition(msgList.size() -1);
msgRecycleView.setAdapter(adapter);
textView.setText("");
}
});

}

public void initMsg(){
Msg msg_1 = new Msg("Hello, How are you?", 0);
msgList.add(msg_1);
Msg msg_2 = new Msg("I am fine! Thank you!", 1);
msgList.add(msg_2);
Msg msg_3 = new Msg("Oh yeah! I am from Guangzhou, are you?", 0);
msgList.add(msg_3);
}
}

MsgAdapter.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import java.util.List;

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

private List<Msg> list;
static class ViewHolder extends RecyclerView.ViewHolder{
protected TextView leftContent;
protected TextView rightContent;
protected LinearLayout leftLayout;
protected LinearLayout rightLayout;

public ViewHolder(View v){
super(v);
leftLayout = (LinearLayout) v.findViewById(R.id.left_layout);
rightLayout = (LinearLayout) v.findViewById(R.id.right_layout);
leftContent = (TextView) v.findViewById(R.id.left);
rightContent = (TextView) v.findViewById(R.id.right);
}
}

public MsgAdapter(List<Msg> list){
this.list = list;
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.message, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Msg message = list.get(position);
if(message.getType() == 0){
holder.leftContent.setText(message.getContent());
holder.leftLayout.setVisibility(View.VISIBLE);
holder.rightLayout.setVisibility(View.GONE);
}
else if(message.getType() == 1){
holder.rightContent.setText(message.getContent());
holder.rightLayout.setVisibility(View.VISIBLE);
holder.leftLayout.setVisibility(View.GONE);
}

}

@Override
public int getItemCount() {
return list.size();
}
}

Msg.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.example.minions.uibestpractice;

public class Msg {
private final static int type_recrived = 0;
private final static int type_send = 1;
private String content;
private int type;

public Msg(String content, int type){
this.content = content;
this.type = type;
}
public int getType() {
return type;
}

public String getContent() {
return content;
}
}

activity_main.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?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.support.v7.widget.RecyclerView
android:id="@+id/list"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="0dp">

</android.support.v7.widget.RecyclerView>

<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/text"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<Button
android:id="@+id/send"
android:background="#9090"
android:textColor="#fff"
android:layout_margin="3dp"
android:text="Send"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>

message.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?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"
android:padding="10dp">

<LinearLayout
android:id="@+id/left_layout"
android:layout_gravity="left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/message_left">

<TextView
android:textSize="25dp"
android:id="@+id/left"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>

<LinearLayout
android:id="@+id/right_layout"
android:layout_gravity="right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/message_right">

<TextView
android:id="@+id/right"
android:textSize="25dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>

</LinearLayout>


完结 撒花 ฅ>ω<*ฅ