第 3 章 - 编写界面的最佳实践
程序员文章站
2024-03-25 17:16:46
...
本文初探 UI 设计,主要包含两个点。
- 制作 Nine-Patch 图片
- 制作精美的聊天界面
效果
制作 .9 图
现在新版的 Android SDK 的 tools 下面已经去除了 draw9patch.bat ,转而在 AS 中集成了该功能。只需要选中图片,右键生成 .9 图,然后编辑即可。
.9 图的各边规则:
左号黑色条位置向右覆盖的区域表示图片纵向拉伸时,只拉伸该区域
上号黑色条位置向下覆盖的区域表示图片横向拉伸时,只拉伸该区域
右号黑色条位置向左覆盖的区域表示图片纵向显示内容的区域(在手机上主要是文字区域)
下号黑色条位置向上覆盖的区域表示图片横向显示内容的区域(在手机上主要是文字区域)
参考:
制作精美的聊天界面
步骤:
- 制作第一部分提到的 .9 图,用于发送聊天内容和接收聊天内容的背景图片
- 编写 xml 布局文件
- 编写适配器
- 在 UI 中绑定适配器,当发送一条新消息时,更新适配器数据。
以下是代码演示,按照上面的步骤一步步来看。
- .9 图已经制作好,看文末源码就可以获取。
- 编写 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>
- 定义适配器
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
}
}
- 在 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)
}
}
代码就这些,源码看这里:
上一篇: docker安装Oracle数据库
下一篇: docker安装oracle数据库
推荐阅读