当前位置:   article > 正文

Android类似微信聊天的页面开发教程(Kotlin)三_android 仿微信聊天界面

android 仿微信聊天界面

 

前提条件

安装并配置好Android Studio

Android Studio Electric Eel | 2022.1.1 Patch 2
Build #AI-221.6008.13.2211.9619390, built on February 17, 2023
Runtime version: 11.0.15+0-b2043.56-9505619 amd64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
Windows 11 10.0
GC: G1 Young Generation, G1 Old Generation
Memory: 1280M
Cores: 6
Registry:
    external.system.auto.import.disabled=true
    ide.text.editor.with.preview.show.floating.toolbar=false
    ide.balloon.shadow.size=0
 
Non-Bundled Plugins:
    com.intuit.intellij.makefile (1.0.15)
    com.github.setial (4.0.2)
    com.alayouni.ansiHighlight (1.2.4)
    GsonOrXmlFormat (2.0)
    GLSL (1.19)
    com.mistamek.drawablepreview.drawable-preview (1.1.5)
    com.layernet.plugin.adbwifi (1.0.5)
    com.likfe.ideaplugin.eventbus3 (2020.0.2)

gradle-wrapper.properties

  1. #Tue Apr 25 13:34:44 CST 2023
  2. distributionBase=GRADLE_USER_HOME
  3. distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
  4. distributionPath=wrapper/dists
  5. zipStorePath=wrapper/dists
  6. zipStoreBase=GRADLE_USER_HOME

build.gradle(:Project)

  1. // Top-level build file where you can add configuration options common to all sub-projects/modules.
  2. plugins {
  3.     id 'com.android.application' version '7.3.1' apply false
  4.     id 'com.android.library' version '7.3.1' apply false
  5.     id 'org.jetbrains.kotlin.android' version '1.7.20' apply false
  6. }


setting.gradle

  1. pluginManagement {
  2.     repositories {
  3.         google()
  4.         mavenCentral()
  5.         gradlePluginPortal()
  6.         maven { url 'https://jitpack.io' }
  7.     }
  8. }
  9. dependencyResolutionManagement {
  10.     repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
  11.     repositories {
  12.         google()
  13.         mavenCentral()
  14.         gradlePluginPortal()
  15.         maven { url 'https://jitpack.io' }
  16.     }
  17. }
  18. rootProject.name = "logindemo"
  19. include ':app'

build.gralde(:app)

  1. plugins {
  2. id 'com.android.application'
  3. id 'org.jetbrains.kotlin.android'
  4. }
  5. android {
  6. namespace 'com.example.fechat'
  7. compileSdk 33
  8. defaultConfig {
  9. applicationId "com.example.fechat"
  10. minSdk 26
  11. targetSdk 33
  12. versionCode 1
  13. versionName "1.0"
  14. }
  15. buildTypes {
  16. release {
  17. minifyEnabled false
  18. proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
  19. }
  20. }
  21. compileOptions {
  22. sourceCompatibility JavaVersion.VERSION_11
  23. targetCompatibility JavaVersion.VERSION_11
  24. }
  25. kotlinOptions {
  26. jvmTarget = '1.8'
  27. }
  28. }
  29. dependencies {
  30. implementation 'androidx.core:core-ktx:1.7.0'
  31. implementation 'androidx.appcompat:appcompat:1.6.1'
  32. implementation 'com.google.android.material:material:1.8.0'
  33. implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
  34. // 沉浸式状态栏 https://github.com/gyf-dev/ImmersionBar
  35. implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
  36. implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0' // fragment快速实现(可选)
  37. implementation 'com.gyf.immersionbar:immersionbar-ktx:3.0.0' // kotlin扩展(可选)
  38. implementation 'com.google.code.gson:gson:2.8.9'
  39. }

对Kotlin语言有基本了解

内容在前一篇博客中写了基础配置,如果本篇内容看不懂,可以先去上一篇。

增加聊天页面

activity_message.xml中 标题+内容RecyclerView+底部输入框+发送
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:fitsSystemWindows="true">
  6. <RelativeLayout
  7. android:id="@+id/titleLayout"
  8. android:layout_width="match_parent"
  9. android:layout_height="50dp"
  10. android:background="@color/title">
  11. <TextView
  12. android:id="@+id/backTv"
  13. android:layout_width="wrap_content"
  14. android:layout_height="wrap_content"
  15. android:text="返回"
  16. android:textSize="16sp"
  17. android:textColor="#000000"
  18. android:padding="10dp"
  19. android:layout_centerVertical="true"
  20. android:layout_marginStart="15dp"/>
  21. <TextView
  22. android:id="@+id/userName"
  23. android:layout_width="wrap_content"
  24. android:layout_height="wrap_content"
  25. android:text="用户X"
  26. android:textSize="16sp"
  27. android:textColor="#000000"
  28. android:layout_centerInParent="true"/>
  29. </RelativeLayout>
  30. <androidx.recyclerview.widget.RecyclerView
  31. android:id="@+id/itemView"
  32. android:layout_width="match_parent"
  33. android:layout_height="match_parent"
  34. android:background="@color/white"
  35. android:layout_below="@+id/titleLayout"
  36. android:layout_above="@+id/messageLayout"/>
  37. <RelativeLayout
  38. android:id="@+id/messageLayout"
  39. android:layout_width="match_parent"
  40. android:layout_height="wrap_content"
  41. android:layout_alignParentBottom="true"
  42. android:background="#F6F6F6"
  43. android:gravity="center_vertical">
  44. <EditText
  45. android:id="@+id/inputText"
  46. android:layout_width="match_parent"
  47. android:layout_height="40dp"
  48. android:background="@drawable/message_text_shape"
  49. android:layout_toStartOf="@+id/sendText"
  50. android:layout_marginStart="16dp"
  51. android:layout_marginTop="6dp"
  52. android:layout_marginEnd="6dp"
  53. android:layout_marginBottom="6dp"
  54. android:padding="10dp"
  55. android:maxLines="1"
  56. android:singleLine="true"
  57. android:textSize="16sp"
  58. android:textColor="#000000"/>
  59. <TextView
  60. android:id="@+id/sendText"
  61. android:layout_width="70dp"
  62. android:layout_height="40dp"
  63. android:background="@drawable/message_send_shape"
  64. android:layout_alignParentEnd="true"
  65. android:layout_marginStart="6dp"
  66. android:layout_marginTop="6dp"
  67. android:layout_marginEnd="16dp"
  68. android:layout_marginBottom="6dp"
  69. android:textSize="16sp"
  70. android:textColor="@color/white"
  71. android:text="发送"
  72. android:gravity="center"/>
  73. </RelativeLayout>
  74. </RelativeLayout>
  1. package com.example.fechat.activity
  2. import android.annotation.SuppressLint
  3. import android.os.Bundle
  4. import android.widget.EditText
  5. import android.widget.TextView
  6. import androidx.appcompat.app.AppCompatActivity
  7. import androidx.recyclerview.widget.LinearLayoutManager
  8. import androidx.recyclerview.widget.RecyclerView
  9. import com.example.fechat.R
  10. import com.example.fechat.adapter.ChatAdapter
  11. import com.example.fechat.bean.ChatBean
  12. import com.example.fechat.bean.MessageBean
  13. import com.google.gson.Gson
  14. import com.gyf.immersionbar.ImmersionBar
  15. class MessageActivity : AppCompatActivity() {
  16. private val beans: MutableList<MessageBean> = ArrayList()
  17. private var adapter: ChatAdapter? = null
  18. private lateinit var itemView: RecyclerView
  19. private lateinit var chatBean: ChatBean
  20. override fun onCreate(savedInstanceState: Bundle?) {
  21. super.onCreate(savedInstanceState)
  22. ImmersionBar.with(this)
  23. .statusBarDarkFont(true)
  24. .statusBarColor(R.color.title)
  25. .navigationBarColor(R.color.white)
  26. .navigationBarDarkIcon(true)
  27. .init()
  28. setContentView(R.layout.activity_message)
  29. val backTv = findViewById<TextView>(R.id.backTv)
  30. val inputText: EditText = findViewById(R.id.inputText)
  31. val sendText: TextView = findViewById(R.id.sendText)
  32. val userName: TextView = findViewById(R.id.userName)
  33. backTv.setOnClickListener {
  34. finish()
  35. }
  36. sendText.setOnClickListener {
  37. sendText(inputText.text.toString())
  38. }
  39. initItemRecyclerView()
  40. getBundle()
  41. userName.text = chatBean.nick
  42. }
  43. private fun getBundle() {
  44. val userInfo = intent.getStringExtra("UserInfo")
  45. chatBean = Gson().fromJson(userInfo, ChatBean::class.java)
  46. }
  47. private fun initItemRecyclerView() {
  48. itemView = findViewById(R.id.itemView)
  49. val layoutManager = LinearLayoutManager(this)
  50. layoutManager.orientation = RecyclerView.VERTICAL
  51. itemView.layoutManager = layoutManager
  52. adapter = ChatAdapter(beans)
  53. itemView.adapter = adapter
  54. }
  55. @SuppressLint("NotifyDataSetChanged")
  56. private fun sendText(message: String) {
  57. beans.add(
  58. MessageBean(
  59. message,
  60. "用户",
  61. false,
  62. System.currentTimeMillis()
  63. )
  64. )
  65. beans.add(
  66. MessageBean(
  67. message,
  68. chatBean.nick,
  69. true,
  70. System.currentTimeMillis(),
  71. true
  72. )
  73. )
  74. adapter?.notifyDataSetChanged()
  75. }
  76. }

制作聊天适配器

适配器的xml中,分为两部分 主用户发送消息,同时接收聊天对象的消息

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout
  3. xmlns:android="http://schemas.android.com/apk/res/android"
  4. android:layout_width="match_parent"
  5. android:layout_height="wrap_content"
  6. xmlns:app="http://schemas.android.com/apk/res-auto">
  7. <RelativeLayout
  8. android:id="@+id/userLayout"
  9. android:layout_width="match_parent"
  10. android:layout_height="wrap_content"
  11. android:layout_marginStart="30dp"
  12. android:layout_marginTop="10dp">
  13. <com.example.fechat.view.CircleImageView
  14. android:id="@+id/userHead"
  15. android:layout_width="46dp"
  16. android:layout_height="46dp"
  17. android:src="@mipmap/ic_ai_user"
  18. android:layout_alignParentEnd="true"/>
  19. <androidx.constraintlayout.widget.ConstraintLayout
  20. android:id="@+id/messageLayout"
  21. android:layout_width="wrap_content"
  22. android:layout_height="wrap_content"
  23. android:layout_toStartOf="@+id/userHead"
  24. android:layout_marginEnd="12dp">
  25. <TextView
  26. android:id="@+id/userMessage"
  27. android:layout_width="wrap_content"
  28. android:layout_height="wrap_content"
  29. app:layout_constraintTop_toTopOf="parent"
  30. app:layout_constraintEnd_toEndOf="parent"
  31. android:background="@drawable/message_user_shape"
  32. android:textSize="16sp"
  33. android:textColor="@color/black"
  34. android:paddingStart="15dp"
  35. android:paddingEnd="15dp"
  36. android:paddingTop="20dp"
  37. android:paddingBottom="20dp"
  38. android:text="请推荐"
  39. android:textIsSelectable="true"/>
  40. <TextView
  41. android:id="@+id/userTime"
  42. android:layout_width="wrap_content"
  43. android:layout_height="wrap_content"
  44. app:layout_constraintTop_toBottomOf="@+id/userMessage"
  45. app:layout_constraintStart_toStartOf="parent"
  46. android:text="22:32"
  47. android:textColor="#B1B1B1"
  48. android:textSize="14sp"
  49. android:layout_marginTop="8dp"/>
  50. </androidx.constraintlayout.widget.ConstraintLayout>
  51. </RelativeLayout>
  52. <RelativeLayout
  53. android:id="@+id/respLayout"
  54. android:layout_width="match_parent"
  55. android:layout_height="wrap_content"
  56. android:layout_marginEnd="30dp"
  57. android:layout_marginTop="10dp"
  58. android:visibility="gone">
  59. <com.example.fechat.view.CircleImageView
  60. android:id="@+id/respHead"
  61. android:layout_width="46dp"
  62. android:layout_height="46dp"
  63. android:src="@mipmap/ic_ai_user"/>
  64. <androidx.constraintlayout.widget.ConstraintLayout
  65. android:layout_width="wrap_content"
  66. android:layout_height="wrap_content"
  67. android:layout_toEndOf="@+id/respHead"
  68. android:layout_marginStart="12dp">
  69. <RelativeLayout
  70. android:id="@+id/respMessageLayout"
  71. android:layout_width="wrap_content"
  72. android:layout_height="wrap_content"
  73. app:layout_constraintStart_toStartOf="parent"
  74. app:layout_constraintTop_toTopOf="parent"
  75. android:background="@drawable/message_ai_shape">
  76. <TextView
  77. android:id="@+id/respMessage"
  78. android:layout_width="wrap_content"
  79. android:layout_height="wrap_content"
  80. android:textSize="16sp"
  81. android:textColor="@color/black"
  82. android:paddingStart="15dp"
  83. android:paddingEnd="15dp"
  84. android:paddingTop="20dp"
  85. android:paddingBottom="20dp"
  86. android:text="小猪佩奇"
  87. android:textIsSelectable="true"/>
  88. <ImageView
  89. android:id="@+id/respImage"
  90. android:layout_width="220dp"
  91. android:layout_height="160dp"
  92. android:layout_below="@+id/respMessage"
  93. android:scaleType="center"
  94. android:layout_marginStart="20dp"
  95. android:layout_marginEnd="20dp"
  96. android:layout_marginBottom="20dp"
  97. android:visibility="gone"/>
  98. </RelativeLayout>
  99. <TextView
  100. android:id="@+id/respTime"
  101. android:layout_width="wrap_content"
  102. android:layout_height="wrap_content"
  103. android:text="22:32"
  104. android:textColor="#B1B1B1"
  105. android:textSize="14sp"
  106. android:layout_marginTop="8dp"
  107. app:layout_constraintEnd_toEndOf="parent"
  108. app:layout_constraintTop_toBottomOf="@+id/respMessageLayout"/>
  109. </androidx.constraintlayout.widget.ConstraintLayout>
  110. </RelativeLayout>
  111. </RelativeLayout>
  1. package com.example.fechat.adapter
  2. import android.view.LayoutInflater
  3. import android.view.View
  4. import android.view.ViewGroup
  5. import android.widget.ImageView
  6. import android.widget.RelativeLayout
  7. import android.widget.TextView
  8. import androidx.recyclerview.widget.RecyclerView
  9. import androidx.recyclerview.widget.RecyclerView.Adapter
  10. import com.example.fechat.R
  11. import com.example.fechat.bean.MessageBean
  12. import com.example.fechat.view.CircleImageView
  13. import java.text.SimpleDateFormat
  14. import java.util.*
  15. class ChatAdapter(private val data: List<MessageBean>) : Adapter<ChatAdapter.BaseHolder>() {
  16. private fun getTime(time: Long): String {
  17. val sDateFormat = SimpleDateFormat("MM-dd HH:mm", Locale.getDefault())
  18. return sDateFormat.format(time)
  19. }
  20. class BaseHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
  21. val userLayout: RelativeLayout = itemView.findViewById(R.id.userLayout)
  22. val userHead: CircleImageView = itemView.findViewById(R.id.userHead)
  23. val userMessage: TextView = itemView.findViewById(R.id.userMessage)
  24. val userTime: TextView = itemView.findViewById(R.id.userTime)
  25. val respLayout: RelativeLayout = itemView.findViewById(R.id.respLayout)
  26. val respHead: CircleImageView = itemView.findViewById(R.id.respHead)
  27. val respMessage: TextView = itemView.findViewById(R.id.respMessage)
  28. val respTime: TextView = itemView.findViewById(R.id.respTime)
  29. val respImage: ImageView = itemView.findViewById(R.id.respImage)
  30. }
  31. override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseHolder {
  32. val view = LayoutInflater.from(parent.context).inflate(R.layout.item_message, null, false);
  33. return BaseHolder(view)
  34. }
  35. override fun getItemCount(): Int {
  36. return data.size
  37. }
  38. override fun onBindViewHolder(holder: BaseHolder, position: Int) {
  39. val item = data[position]
  40. if (item.isResponse) {
  41. holder.respLayout.visibility = View.VISIBLE
  42. holder.userLayout.visibility = View.GONE
  43. holder.respMessage.text = item.message
  44. holder.respTime.text = getTime(item.time)
  45. } else {
  46. holder.userLayout.visibility = View.VISIBLE
  47. holder.respLayout.visibility = View.GONE
  48. holder.userMessage.text = item.message
  49. holder.userTime.text = getTime(item.time)
  50. }
  51. }
  52. }

聊天内容适配器中的data数据结构如下:

  1. package com.example.fechat.bean
  2. data class MessageBean(
  3. var message: String,
  4. var userName: String,
  5. var isResponse: Boolean = false,
  6. var time: Long,
  7. var isSuccess: Boolean = true
  8. )

其中首页用户聊天列表中的data修改,主要是data转化为string方便intent传输,如下:

  1. package com.example.fechat.bean
  2. data class ChatBean(
  3. val head: String, val nick: String,
  4. val newest: String, val date: String
  5. ) {
  6. override fun toString(): String {
  7. return "{head:$head,nick:$nick,newest:$newest,date:$date}"
  8. }
  9. }

首页用户聊天记录的适配器作如下修改,主要是增加了适配器点击事件监听器:

  1. package com.example.fechat.base
  2. import android.view.LayoutInflater
  3. import android.view.View
  4. import android.view.ViewGroup
  5. import android.widget.TextView
  6. import androidx.recyclerview.widget.RecyclerView
  7. import com.example.fechat.R
  8. import com.example.fechat.bean.ChatBean
  9. class BaseAdapter(private val data: List<ChatBean>) :
  10. RecyclerView.Adapter<BaseAdapter.BaseHolder>() {
  11. private lateinit var onItemClickListener: OnItemClickListener
  12. override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseHolder {
  13. val view = LayoutInflater.from(parent.context).inflate(R.layout.base_item, null, false);
  14. return BaseHolder(view)
  15. }
  16. override fun getItemCount(): Int {
  17. return data.size
  18. }
  19. override fun onBindViewHolder(holder: BaseHolder, position: Int) {
  20. holder.headTv.visibility = if (data[position].head.isEmpty()) View.GONE else View.VISIBLE
  21. holder.nickTv.visibility = if (data[position].nick.isEmpty()) View.GONE else View.VISIBLE
  22. holder.newestTv.visibility =
  23. if (data[position].newest.isEmpty()) View.GONE else View.VISIBLE
  24. holder.dateTv.visibility = if (data[position].date.isEmpty()) View.GONE else View.VISIBLE
  25. holder.headTv.text = data[position].head
  26. holder.nickTv.text = data[position].nick
  27. holder.newestTv.text = data[position].newest
  28. holder.dateTv.text = data[position].date
  29. holder.itemView.setOnClickListener {
  30. onItemClickListener.onItemClick(holder.itemView, position)
  31. }
  32. }
  33. class BaseHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
  34. val headTv: TextView = itemView.findViewById(R.id.headTv)
  35. val nickTv: TextView = itemView.findViewById(R.id.nickTv)
  36. val newestTv: TextView = itemView.findViewById(R.id.newestTv)
  37. val dateTv: TextView = itemView.findViewById(R.id.dateTv)
  38. }
  39. fun setOnItemClickListener(onItemClickListener: OnItemClickListener) {
  40. this.onItemClickListener = onItemClickListener
  41. }
  42. interface OnItemClickListener {
  43. fun onItemClick(view: View, position: Int)
  44. }
  45. }

点击跳转到聊天页面

  1. package com.example.fechat.fragment
  2. import android.content.Intent
  3. import android.os.Bundle
  4. import android.view.LayoutInflater
  5. import android.view.View
  6. import android.view.ViewGroup
  7. import androidx.fragment.app.Fragment
  8. import androidx.recyclerview.widget.LinearLayoutManager
  9. import androidx.recyclerview.widget.RecyclerView
  10. import com.example.fechat.R
  11. import com.example.fechat.activity.MessageActivity
  12. import com.example.fechat.base.BaseAdapter
  13. import com.example.fechat.bean.ChatBean
  14. class ChatFragment : Fragment() {
  15. private lateinit var recyclerView: RecyclerView
  16. override fun onCreateView(
  17. inflater: LayoutInflater, container: ViewGroup?,
  18. savedInstanceState: Bundle?
  19. ): View? {
  20. val view = inflater.inflate(R.layout.fragment_chat, container, false)
  21. recyclerView = view.findViewById(R.id.recyclerView)
  22. val data = ArrayList<ChatBean>()
  23. data.add(ChatBean("头像0", "用户0", "聊天记录0", "4月25日"))
  24. data.add(ChatBean("头像1", "用户1", "聊天记录1", "4月24日"))
  25. data.add(ChatBean("头像2", "用户2", "聊天记录2", "4月23日"))
  26. data.add(ChatBean("头像3", "用户3", "聊天记录3", "4月22日"))
  27. data.add(ChatBean("头像4", "用户4", "聊天记录4", "4月21日"))
  28. data.add(ChatBean("头像5", "用户5", "聊天记录5", "4月20日"))
  29. data.add(ChatBean("头像6", "用户6", "聊天记录6", "4月19日"))
  30. data.add(ChatBean("头像7", "用户7", "聊天记录7", "4月18日"))
  31. data.add(ChatBean("头像8", "用户8", "聊天记录8", "4月17日"))
  32. data.add(ChatBean("头像9", "用户9", "聊天记录9", "4月16日"))
  33. recyclerView.layoutManager = LinearLayoutManager(context)
  34. val baseAdapter = BaseAdapter(data)
  35. recyclerView.adapter = baseAdapter
  36. baseAdapter.setOnItemClickListener(object : BaseAdapter.OnItemClickListener {
  37. override fun onItemClick(view: View, position: Int) {
  38. val intent = Intent(context, MessageActivity::class.java)
  39. intent.putExtra("UserInfo", data[position].toString())
  40. startActivity(intent)
  41. }
  42. })
  43. return view
  44. }
  45. }

开源地址

FeChat: 模仿微信

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/676319
推荐阅读
相关标签
  

闽ICP备14008679号