從0系統學Android--3.7 聊天界面編寫
本系列文章目錄:更多精品文章分類
本系列持續更新中….3.7 編寫界面的最佳實踐
前面學習了那麼多 UI 開發的知識,下面來進行實踐,做一個美觀的聊天界面。
3.7.1 制作 Nine-Patch 圖檔
實戰前先學習一個小知識,如何制作 Nine-Patch 圖檔。
Nine-Patch 是一種被特殊處理的
.png
圖檔,能夠指定那些區域可以被拉伸,那些區域不可以。
來看看
Nine-Patch
圖檔的實際作用。
首先我們用一張普通的圖檔作為背景
1<?xml version="1.0" encoding="utf-8"?>
2<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="match_parent"
4 android:layout_height="wrap_content"
5 android:background="@mipmap/message_"
6 android:orientation="vertical">
7</LinearLayout>
運作結果
可以看到效果非常糟糕,由于圖檔的寬度不能填滿整個螢幕的寬度,整張圖檔就被均勻的拉伸的,效果很差,這種情況,我們就可以使用
Nine-Patch
圖檔來進行改善了。
如何建立
nine-patch
圖檔呢?
首先在 Android Studio 中選中你要變成
nine-patch
的圖檔,然後右擊--->Create 9-Patch file 就可以建立 Nine-Patch 圖檔了。
我們可以在圖檔的四個邊框繪制一個個的小黑點。在
上邊框和左邊框的部分表示目前圖檔需要
拉伸的時候就會拉伸黑色點标記的
區域,在
下邊框和右邊框的部分表示
内容會被放置的區域。用滑鼠在圖檔的邊緣拖到就可以進行繪制了。按住
Shift
鍵拖動可以進行擦除。
再來看看使用 nine-patch 的效果
這樣當圖檔需要拉伸的時候就隻拉伸指定區域了。
3.7.2 編寫精美的聊天界面
聊天界面肯定有收到的消息和發送的消息,上面我們已經把發送消息的背景圖制作好了,再制作一張發送消息的背景圖。
圖檔資源都準備好了,就可以寫代碼了。
編寫首頁面布局
1<?xml version="1.0" encoding="utf-8"?>
2<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent"
5 android:orientation="vertical">
6 <androidx.recyclerview.widget.RecyclerView
7 android:id="@+id/rlv"
8 android:layout_width="match_parent"
9 android:layout_height="0dp"
10 android:layout_weight="1"/>
11 <LinearLayout
12 android:orientation="horizontal"
13 android:layout_width="match_parent"
14 android:layout_height="wrap_content">
15 <EditText
16 android:id="@+id/et_info"
17 android:layout_width="0dp"
18 android:layout_height="wrap_content"
19 android:layout_weight="1"
20 android:hint="發送資訊"
21 android:maxLines="2"/>
22 <Button
23 android:layout_width="wrap_content"
24 android:layout_height="wrap_content"
25 android:text="發送"
26 android:id="@+id/bt_send"/>
27 </LinearLayout>
28</LinearLayout>
建立聊天的消息對象
1public class Msg {
2 public static final int TYPE_RECEIVE = 0;
3 public static final int TYPE_SEND = 1;
4 private String content;
5
6 public Msg(String content, int type) {
7 this.content = content;
8 this.type = type;
9 }
10
11 private int type;
12
13 public String getContent() {
14 return content;
15 }
16
17 public void setContent(String content) {
18 this.content = content;
19 }
20
21 public int getType() {
22 return type;
23 }
24
25 public void setType(int type) {
26 this.type = type;
27 }
28}
type 用來指定消息的類型,是發送的消息還接受的消息
然後編寫 RecyclerView 的子項布局
1<?xml version="1.0" encoding="utf-8"?>
2<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="match_parent"
4 android:layout_height="wrap_content"
5 android:padding="10dp"
6 android:orientation="vertical">
7 <LinearLayout
8 android:id="@+id/ll_left"
9 android:background="@mipmap/message_left"
10 android:layout_width="wrap_content"
11 android:layout_height="wrap_content">
12 <TextView
13 android:layout_width="wrap_content"
14 android:layout_height="wrap_content"
15 android:layout_gravity="center"
16 android:id="@+id/tv_left"
17 android:textColor="#FFF"
18 android:layout_margin="10dp"/>
19
20 </LinearLayout>
21
22 <LinearLayout
23 android:layout_gravity="right"
24 android:id="@+id/ll_right"
25 android:background="@mipmap/message_right"
26 android:layout_width="wrap_content"
27 android:layout_height="wrap_content">
28 <TextView
29 android:layout_width="wrap_content"
30 android:layout_height="wrap_content"
31 android:layout_gravity="center"
32 android:id="@+id/tv_right"
33 android:layout_margin="10dp"/>
34
35 </LinearLayout>
36</LinearLayout>
這裡我們把接受消息和發送消息的布局都寫進來了,代碼中根據消息的類型來調用
visible
方法,顯示對應的消息。
建立擴充卡
1public class MsgAdapter extends RecyclerView.Adapter<MsgAdapter.MsgViewHolder> {
2 private List<Msg> list;
3 public MsgAdapter(List<Msg> list){
4 this.list = list;
5 }
6
7
8
9 class MsgViewHolder extends RecyclerView.ViewHolder{
10 LinearLayout llLeft,llRight;
11 TextView tvLeft,tvRight;
12
13 public MsgViewHolder(@NonNull View itemView) {
14 super(itemView);
15 llLeft =itemView.findViewById(R.id.ll_left);
16 llRight =itemView.findViewById(R.id.ll_right);
17 tvLeft =itemView.findViewById(R.id.tv_left);
18 tvRight =itemView.findViewById(R.id.tv_right);
19 }
20 }
21
22 @NonNull
23 @Override
24 public MsgViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
25 View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.msg_item,parent,false);
26 MsgViewHolder viewHolder = new MsgViewHolder(view);
27
28 return viewHolder;
29 }
30
31 @Override
32 public void onBindViewHolder(@NonNull MsgViewHolder holder, int position) {
33 Msg msg = list.get(position);
34 // 這裡根據消息的類型來選擇不同的布局
35 if (msg.getType() == Msg.TYPE_RECEIVE){
36 holder.llLeft.setVisibility(View.VISIBLE);
37 holder.llRight.setVisibility(View.GONE);
38 holder.tvLeft.setText(msg.getContent());
39 }else {
40 holder.llRight.setVisibility(View.VISIBLE);
41 holder.llLeft.setVisibility(View.GONE);
42 holder.tvRight.setText(msg.getContent());
43 }
44
45 }
46
47 @Override
48 public int getItemCount() {
49 return list.size();
50 }
51}
然後寫 Activity 代碼
1public class MsgActivity extends AppCompatActivity {
2
3 List<Msg> list =new ArrayList<>();
4 EditText text ;
5 @Override
6 protected void onCreate(@Nullable Bundle savedInstanceState) {
7 super.onCreate(savedInstanceState);
8 setContentView(R.layout.activity_nine_patch);
9 initData();
10 final RecyclerView recyclerView = findViewById(R.id.rlv);
11 final MsgAdapter msgAdapter = new MsgAdapter(list);
12 text = findViewById(R.id.et_info);
13 Button bt = findViewById(R.id.bt_send);
14 LinearLayoutManager layoutManager = new LinearLayoutManager(this);
15 recyclerView.setLayoutManager(layoutManager);
16 recyclerView.setAdapter(msgAdapter);
17 bt.setOnClickListener(new View.OnClickListener() {
18 @Override
19 public void onClick(View v) {
20 Random random = new Random();
21 // 這裡還是利用随機數來生成消息的類型
22 int count = random.nextInt(20);
23 Msg msg = new Msg(text.getText()+"count:"+count,count%2);
24 list.add(msg);
25 // 表示在消息的末尾插入内容
26 msgAdapter.notifyItemInserted(list.size()-1);
27 // 讓 RecyclerView 自動滾動到最底部
28 recyclerView.scrollToPosition(list.size()-1);
29 // 清空内容
30 text.setText("");
31 }
32 });
33 }
34
35 public void initData(){
36 Random random = new Random();
37 for (int i=0;i<40;i++){
38 int count = random.nextInt(20);
39 Msg msg = new Msg("消息嗯哼"+i+"count:"+count,count%2);
40 list.add(msg);
41 }
42
43
44 }
45}
notifyItemInserted()
方法,用于通知清單有新的資料插入了,這樣新增加的一條消息才能顯示出來。
scrolltoPosition()
方法将資料定位到最後一行,保證我們可以看到最後發送的内容。