Kotlin高仿微信-项目实践58篇详细讲解了各个功能点,包括:注册、登录、主页、单聊(文本、表情、语音、图片、小视频、视频通话、语音通话、红包、转账)、群聊、个人信息、朋友圈、支付服务、扫一扫、搜索好友、添加好友、开通VIP等众多功能。
效果图:

实现代码:
我的转账页面
好友的转账页面:
package com.wn.wechatclientdemo.fragment.me.payment import android.os.Bundle import android.view.View import androidx.fragment.app.viewModels import androidx.navigation.NavController import androidx.navigation.fragment.findNavController import com.wn.wechatclientdemo.R import com.wn.wechatclientdemo.databinding.WcTransferMainBinding import com.wn.wechatclientdemo.fragment.base.BaseDataBindingFragment import com.wn.wechatclientdemo.utils.* import com.wn.wechatclientdemo.view.BaseDialogUtils import com.wn.wechatclientdemo.viewmodel.ChatViewModel import com.wn.wechatclientdemo.viewmodel.UserViewModel import kotlinx.android.synthetic.main.wc_transfer_main.* /** * Author : wangning * Email : maoning20080809@163.com * Date : 2022/5/22 16:43 * Description : 查看转账详情 */ class TransferDetailsFragment : BaseDataBindingFragment(){ override fun getLayoutRes() = R.layout.wc_transfer_main private val userViewModel: UserViewModel by viewModels() private val chatViewModel: ChatViewModel by viewModels() private var navController : NavController? = null private var balance: Float = 0.0f private var messageId = "" private var toUser = "" override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) super.builder().setTitleContent(R.string.wc_base_top_transfer) arguments?.let { toUser = it.get(CommonUtils.QRCommon.TO_USER) as String messageId = it.get(CommonUtils.Chat.MESSAGE_ID) as String var balanceStr = it.get(CommonUtils.QRCommon.TRANSFER_BALANCE) as String TagUtils.d("转账:${toUser}, ${messageId}, ${balanceStr}") balance = balanceStr.toFloat() trans_main_balance.text = CommonUtils.Base.getFormatBalanceUnit(balance) } navController = findNavController() var account = DataStoreUtils.getAccount() var userBean = userViewModel.getUserLocalAsync(toUser) var chatBean = chatViewModel.getChatByMessageIdAsync(messageId) trans_main_time.text = CommonUtils.Date.getCurrentDate(chatBean.addTime) if(account.equals(toUser)){ if(chatBean.isClick == 1){ //已经领取 trans_main_icon.setImageResource(R.drawable.wc_transfer_time_complete) trans_main_name.text = BaseUtils.getString(R.string.wc_transfer_receive_other) trans_main_receive.visibility = View.GONE } else { //待收款 trans_main_name.text = BaseUtils.getString(R.string.wc_transfer_waitfor_other) trans_main_receive.visibility = View.VISIBLE } } else { trans_main_name.text = BaseUtils.getString(R.string.wc_transfer_name_me, userBean.nickName) trans_main_receive.visibility = View.GONE } userViewModel.balanceLiveData.observe(viewLifecycleOwner){ dismissLoadingDialog() if(it >0){ chatViewModel.updateChatClickByMessageIdLocal(1, messageId) navController?.popBackStack() } else { TagUtils.d("收款失败!") } } trans_main_receive.setOnClickListener { if(balance < 0){ ToastUtils.makeText("转账金额不能小于0") } else { showLoadingDialog() userViewModel.updateBalanceServer(toUser, CommonUtils.User.OPERATOR_PLUS, balance) } } } override fun onDestroy() { super.onDestroy() } private var loadingUtils : BaseDialogUtils? = null //显示加载对话框 private fun showLoadingDialog(){ loadingUtils = BaseDialogUtils(requireActivity()) loadingUtils!!.builder() .hideCancel() .hideConfirm() .setCancelable(true) .setOnLoadingClick(object : BaseDialogUtils.OnLoadingClick{ override fun onClickCancel() { ToastUtils.makeText(requireActivity(), "对话框取消按钮") } override fun onClickConfirm() { ToastUtils.makeText(requireActivity(), "对话框确定按钮") } }) loadingUtils?.show() } //隐藏加载对话框 private fun dismissLoadingDialog(){ loadingUtils?.dismiss() } }
/** * Author : wangning * Email : maoning20080809@163.com * Date : 2022/5/22 16:43 * Description : 转账 */ class PaymentTransferFragment : BaseDataBindingFragment(), MyDispatchTouchEventListener { override fun getLayoutRes() = R.layout.wc_payment_transfer private val userViewModel : UserViewModel by viewModels() private var navController : NavController? = null override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) super.builder().setTitleContent("") var toUser = arguments?.get(CommonUtils.QRCommon.TO_USER) as String BaseUtils.showAvatarRounded(toUser, transfer_icon, transfer_name, BaseUtils.getDimension(R.dimen.distance_10)) DispatchTouchEventUtils.registerDispatchTouchListener(this) navController = findNavController() transfer_balance.showSoftInputOnFocus = false num_keyboard_view.initEditText(transfer_balance) num_keyboard_view.setValue(R.string.wc_transfer_txt) transfer_balance.setOnClickListener { num_keyboard_view.visibility = View.VISIBLE } num_keyboard_item_recharge.setOnClickListener { TagUtils.d("转账金额:${transfer_balance.text}") var result = transfer_balance.text.toString() if(TextUtils.isEmpty(result)){ ToastUtils.makeText(requireActivity(), "请输入金额") return@setOnClickListener } //减掉服务器金额 userViewModel.updateBalanceServer(toUser, CommonUtils.User.OPERATOR_MINUS, transfer_balance.text.toString().toFloat()) navController?.previousBackStackEntry?.savedStateHandle?.set(CommonUtils.QRCommon.TRANSFER_BALANCE, transfer_balance.text.toString().toFloat()) //弹出的id为fragment,不能为action navController?.popBackStack() } } override fun onDestroy() { super.onDestroy() DispatchTouchEventUtils.unregisterDispatchTouchListener(this) } override fun dispatchTouchEvent(ev: MotionEvent) { if (ev.action == MotionEvent.ACTION_DOWN) { if (SoftInputUtils.isInput(transfer_balance, ev)) { num_keyboard_view?.visibility = View.GONE } } } override fun onResume() { super.onResume() transfer_balance.isFocusableInTouchMode = true transfer_balance.requestFocus() transfer_balance.setOnKeyListener { view, i, keyEvent -> if (i == KeyEvent.KEYCODE_BACK && keyEvent.getAction() == KeyEvent.ACTION_DOWN) { if(num_keyboard_view.visibility == View.VISIBLE){ hideNumKeyboardView() true } else { false } } else { false } } } private fun hideNumKeyboardView(){ num_keyboard_view.visibility = View.GONE } private fun showNumKeyboardView(){ num_keyboard_view.visibility = View.VISIBLE } }
//发送文本、红包、表情
private fun sendMessage(chatBean: ChatBean){
if(chatBean == null){
ToastUtils.makeText(requireActivity(), "发送信息不能为空")
return
}
var content = chatBean.content
if(TextUtils.isEmpty(content)){
ToastUtils.makeText(requireActivity(), "发送信息不能为空")
} else {
ChatManagerUtils.getInstance().sendMessage(toUserId, content)
chat_content.setText("")
CoroutineScope(Dispatchers.IO).launch {
if(chatBean.contentType == ChatBean.CONTENT_TYPE_REDPACKET){
var content = chatBean.content
chatBean.content = CommonUtils.Chat.getRedpacket(content).toString()
} else if(chatBean.contentType == ChatBean.CONTENT_TYPE_TRANSFER){
var content = chatBean.content
chatBean.content = CommonUtils.Chat.getTransfer(content).toString()
}
ChatRepository.insertChat(chatBean)
}
refreshBase(chatBean)
}
}
/**
* 刷新发送、接收聊天信息
* @param chatBean ChatBean
*/
private fun refreshBase(chatBean: ChatBean){
CoroutineScope(Dispatchers.Main).launch {
//chatViewModel.insertChat(chatBean)
TagUtils.d("ChatFragment refreshBase 刷新聊天信息 ")
adapter.refresh(chatBean)
if(chatBean.contentType == ChatBean.CONTENT_TYPE_LOCATION){
delay(200)
}
swipe_target.scrollToPosition(adapter.itemCount -1)
}
}