第 3 章 - 編寫界面的最佳實踐

本文初探 UI 設計,主要包含兩個點。

  1. 製作 Nine-Patch 圖片
  2. 製作精美的聊天界面

效果

在這裏插入圖片描述

製作 .9 圖

現在新版的 Android SDK 的 tools 下面已經去除了 draw9patch.bat ,轉而在 AS 中集成了該功能。只需要選中圖片,右鍵生成 .9 圖,然後編輯即可。

.9 圖的各邊規則:

左號黑色條位置向右覆蓋的區域表示圖片縱向拉伸時,只拉伸該區域
上號黑色條位置向下覆蓋的區域表示圖片橫向拉伸時,只拉伸該區域
右號黑色條位置向左覆蓋的區域表示圖片縱向顯示內容的區域(在手機上主要是文字區域)
下號黑色條位置向上覆蓋的區域表示圖片橫向顯示內容的區域(在手機上主要是文字區域)

參考:

  1. Android .9 圖片相關

製作精美的聊天界面

步驟:

  1. 製作第一部分提到的 .9 圖,用於發送聊天內容和接收聊天內容的背景圖片
  2. 編寫 xml 佈局文件
  3. 編寫適配器
  4. 在 UI 中綁定適配器,當發送一條新消息時,更新適配器數據。

以下是代碼演示,按照上面的步驟一步步來看。

  1. .9 圖已經製作好,看文末源碼就可以獲取。
  2. 編寫 xml,包含 activity_main.xml 和 msg_item.xml
    activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#d8e0e8"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/msg_list_view"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:divider="#0000" >
    </ListView>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
        <EditText
            android:id="@+id/input_text"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:hint="Type somthing here"
            android:maxLines="2" />
        <Button
            android:id="@+id/send"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Send" />
    </LinearLayout>

</LinearLayout>

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="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"
        android:background="@mipmap/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="#fff" />
    </LinearLayout>

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

        <TextView
            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. 定義適配器
package com.xzy.uibestpractice

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.LinearLayout
import android.widget.TextView

class MsgAdapter(
    context: Context?,
    private val resourceId: Int,
    objects: List<Msg>?
) : ArrayAdapter<Msg?>(context!!, resourceId, objects!!) {
    override fun getView(
        position: Int,
        convertView: View?,
        parent: ViewGroup
    ): View {
        val msg = getItem(position)
        val view: View
        val viewHolder: ViewHolder
        if (convertView == null) {
            view = LayoutInflater.from(context).inflate(resourceId, null)
            viewHolder = ViewHolder()
            viewHolder.leftLayout =
                view.findViewById<View>(R.id.left_layout) as LinearLayout
            viewHolder.rightLayout =
                view.findViewById<View>(R.id.right_layout) as LinearLayout
            viewHolder.leftMsg = view.findViewById<View>(R.id.left_msg) as TextView
            viewHolder.rightMsg = view.findViewById<View>(R.id.right_msg) as TextView
            view.tag = viewHolder
        } else {
            view = convertView
            viewHolder = view.tag as ViewHolder
        }
        if (msg?.type == Msg.TYPE_RECEIVED) {
            viewHolder.leftLayout?.visibility = View.VISIBLE
            viewHolder.rightLayout?.visibility = View.GONE
            viewHolder.leftMsg?.setText(msg.content)
        } else if (msg?.type == Msg.TYPE_SENT) {
            viewHolder.rightLayout?.visibility = View.VISIBLE
            viewHolder.leftLayout?.visibility = View.GONE
            viewHolder.rightMsg?.setText(msg.content)
        }
        return view
    }

    internal inner class ViewHolder {
        var leftLayout: LinearLayout? = null
        var rightLayout: LinearLayout? = null
        var leftMsg: TextView? = null
        var rightMsg: TextView? = null
    }

}

裏面用的消息實體定義如下:

package com.xzy.uibestpractice

class Msg(val content: String, val type: Int) {

    companion object {
        const val TYPE_RECEIVED = 0
        const val TYPE_SENT = 1
    }
}
  1. 在 UI 中實例化並綁定適配器,並進行聊天數據模擬。
package com.xzy.uibestpractice

import android.os.Bundle
import android.view.View
import android.view.Window
import android.widget.Button
import android.widget.EditText
import android.widget.ListView
import androidx.appcompat.app.AppCompatActivity
import java.util.*

class MainActivity : AppCompatActivity() {
    private var msgListView: ListView? = null
    private var inputText: EditText? = null
    private var send: Button? = null
    private var adapter: MsgAdapter? = null
    private val msgList: MutableList<Msg> = ArrayList()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        requestWindowFeature(Window.FEATURE_NO_TITLE)
        setContentView(R.layout.activity_main)
        initMsgs()
        adapter = MsgAdapter(this@MainActivity, R.layout.msg_item, msgList)
        inputText = findViewById<View>(R.id.input_text) as EditText
        send = findViewById<View>(R.id.send) as Button
        msgListView = findViewById<View>(R.id.msg_list_view) as ListView
        msgListView?.adapter = adapter
        send?.setOnClickListener {
            val content = inputText?.text.toString()
            if ("" != content) {
                val msg = Msg(content, Msg.TYPE_SENT)
                msgList.add(msg)
                adapter?.notifyDataSetChanged()
                msgListView?.setSelection(msgList.size)
                inputText?.setText("")
            }
        }
    }

    private fun initMsgs() {
        val msg1 = Msg("Hello guy.", Msg.Companion.TYPE_RECEIVED)
        msgList.add(msg1)
        val msg2 = Msg("Hello. Who is that?", Msg.Companion.TYPE_SENT)
        msgList.add(msg2)
        val msg3 = Msg("This is Tom. Nice talking to you. ", Msg.Companion.TYPE_RECEIVED)
        msgList.add(msg3)
    }
}

代碼就這些,源碼看這裏:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章