左右左右左:Android对话流实现

张天宇 on 2018-01-05

一个语音助手,光会说话还不够,来简单的实现一个对话流显示聊天记录。

ListView:由于手机屏幕空间都比较有限,一次性显示所有记录显然不够现实。ListView允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上原有的数据则会滚动出屏幕。因此可以借助其实现聊天记录的滑动显示功能。

这里以最近写的Demo 小炮为例,效果如下图(参考现有语音助手UI,未设计头像与对话框):

Demo

一、布局文件

比较简单,直接贴代码

1.主布局

包含ListView和对话、菜单等按钮

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
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="20dp"
android:orientation="vertical"
tools:context="me.weyo.magicmirror.android.MainActivity">
<ListView
android:layout_marginRight="20dp"
android:layout_marginLeft="20dp"
android:layout_below="@id/iv_logo"
android:id="@+id/msg_list_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:divider="#0000">
</ListView>
<include
layout="@layout/lo_saying"
android:id="@+id/lo_saying">
</include>
<!--文字输入布局,默认关闭-->
<include
android:visibility="gone"
layout="@layout/lo_edit"
android:id="@+id/lo_edit">
</include>
</LinearLayout>

2.语音输入按钮

包含设置、话筒、帮助,文字输入类似不再赘述,效果如下:

语音输入按钮

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
<?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="80dp"
android:layout_marginBottom="20dp"
android:layout_marginTop="4dp"
android:layout_alignParentBottom="true"
android:weightSum="3"
android:gravity="center"
android:orientation="horizontal"
android:baselineAligned="false">
<LinearLayout
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:gravity="center"
android:layout_gravity="center_horizontal">
<ImageButton
android:id="@+id/setting"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_gravity="center"
android:background="@drawable/main_setting_btn_np" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_weight="1">
<ImageButton
android:id="@+id/saying"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_gravity="center"
android:background="@drawable/main_saying_btn_np"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:gravity="center">
<ImageButton
android:id="@+id/help"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_gravity="center"
android:background="@drawable/main_help_btn_np"/>
</LinearLayout>
</LinearLayout>

3.单次对话Item布局文件

包含左边(收到的消息)右边(发送的消息)

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
<?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" >
<LinearLayout
android:id="@+id/left_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left" >
<TextView
android:textSize="25dp"
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="#fff" />
</LinearLayout>
<LinearLayout
android:id="@+id/right_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right" >
<TextView
android:textSize="25dp"
android:textColor="#FFFFFF"
android:id="@+id/right_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="10dp" />
</LinearLayout>
</LinearLayout>

二、实体类

1.消息类

将消息抽象为对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* Created by zhangty1996 on 2017/2/14 0014.
* E-Mail:zhangty1996@163.com
*/

public class Msg {
//状态:收到、发出
public static final int TYPE_RECEIVED = 0;
public static final int TYPE_SENT = 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;
}
}

2.Msg适配器

将meg组装到listview显示

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
public class MsgAdapter extends ArrayAdapter<Msg> {
private int resourceId;
public MsgAdapter(Context context,
int textViewResourceId, List<Msg>
objects) {
super(context, textViewResourceId, objects);
resourceId = textViewResourceId;
}
@Override
public View getView(int position,
View convertView, ViewGroup parent) {
Msg msg = getItem(position);
View view;
ViewHolder viewHolder;
if (convertView == null) {
view = LayoutInflater.from(getContext()).inflate(resourceId, null);
viewHolder = new ViewHolder();
viewHolder.leftLayout= (LinearLayout) view.findViewById
(R.id.left_layout);
viewHolder.rightLayout = (LinearLayout) view.findViewById
(R.id.right_layout);
viewHolder.leftMsg = (TextView) view.findViewById(R.id.left_msg);
viewHolder.rightMsg = (TextView) view.findViewById(R.id.right_msg);
view.setTag(viewHolder);
} else {
view = convertView;
viewHolder = (ViewHolder) view.getTag();
}
if (msg.getType() == Msg.TYPE_RECEIVED) {
// 如果是收到的消息,则显示左消息布局,右消息布局隐藏
viewHolder.leftLayout.setVisibility(View.VISIBLE);
viewHolder.rightLayout.setVisibility(View.GONE);
viewHolder.leftMsg.setText(msg.getContent());
} else if(msg.getType() == Msg.TYPE_SENT) {
// 如果是发出的消息,则显示右消息布局,将左消息布局隐藏
viewHolder.rightLayout.setVisibility(View.VISIBLE);
viewHolder.leftLayout.setVisibility(View.GONE);
viewHolder.rightMsg.setText(msg.getContent());
}
return view;
}
class ViewHolder {
LinearLayout leftLayout;
LinearLayout rightLayout;
TextView leftMsg;
TextView rightMsg;
}
}

3.MainActivity中关键代码

装载布局及相关监听省略

1
2
3
4
//聊天窗口
private ListView msgListView;
private MsgAdapter adapter;
private List<Msg> msgList = new ArrayList<Msg>();
1
2
3
4
//对话框初始化
adapter = new MsgAdapter(MainActivity.this, R.layout.msg_item, msgList);
msgListView = (ListView) findViewById(R.id.msg_list_view);
msgListView.setAdapter(adapter);
1
2
3
4
5
6
7
8
public void setMsg(String result,int type){
Msg msg = new Msg(result, type);
msgList.add(msg);
adapter.notifyDataSetChanged();
// 当有新消息时,刷新ListView中的显示
msgListView.setSelection(msgList.size());
// 将ListView定位到最后一行
}

到这里,一个简单的对话流布局就写完了,把他应用到App中,只需要将Msg设置好内容、状态,监听里调用msg就好了!

一起来敲一个自己的语音助手吧。