Kotlin高仿微信-第17篇-单聊-转账

news2024/11/26 10:43:50

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

Kotlin高仿微信-项目实践58篇,点击查看详情

效果图:

 

 

实现代码:

我的转账页面

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="right">


    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/transfer_me_root_layout"
        android:layout_width="240dp"
        android:layout_height="90dp"
        android:background="@drawable/wc_redpacket_right_normal">

        <TextView
            android:id="@+id/transfer_me_balance"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:text="0.01"
            android:textColor="#ffffff"
            android:textSize="16sp"
            android:textStyle="bold"
            android:layout_marginTop="2dp"
            android:maxLines="1"
            android:ellipsize="end"
            android:singleLine="true"
            app:layout_constraintTop_toTopOf="@+id/transfer_me_icon"
            app:layout_constraintStart_toEndOf="@+id/transfer_me_icon"/>

        <TextView
            android:id="@+id/transfer_me_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:text="你发起了一笔转账"
            android:textColor="#ffffff"
            android:textSize="12sp"
            app:layout_constraintTop_toBottomOf="@+id/transfer_me_balance"
            app:layout_constraintStart_toEndOf="@+id/transfer_me_icon"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="0.2dp"
            android:layout_marginLeft="20dp"
            android:layout_marginRight="10dp"
            android:background="#ffffff"
            app:layout_constraintBottom_toTopOf="@+id/redpacket_tip"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/transfer_me_icon" />

        <TextView
            android:id="@+id/redpacket_tip"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:layout_marginBottom="6dp"
            android:text="@string/wc_chat_transfer_tip"
            android:textColor="#d9d6c3"
            android:textSize="10sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent" />

        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/transfer_me_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="20dp"
            android:layout_marginTop="12dp"
            android:src="@drawable/wc_chat_transfer_icon"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</RelativeLayout>

好友的转账页面:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto">

    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/transfer_other_root_layout"
        android:layout_width="240dp"
        android:layout_height="90dp"
        android:background="@drawable/wc_redpacket_left_normal">


        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/other_transfer_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="18dp"
            android:layout_marginTop="10dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:background="@drawable/wc_chat_transfer_icon"/>

        <TextView
            android:id="@+id/transfer_other_balance"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="0.01"
            android:textSize="16sp"
            android:textColor="#ffffff"
            android:textStyle="bold"
            android:layout_marginTop="2dp"
            android:layout_marginLeft="10dp"
            app:layout_constraintStart_toEndOf="@+id/other_transfer_icon"
            app:layout_constraintTop_toTopOf="@+id/other_transfer_icon"/>

        <TextView
            android:id="@+id/transfer_other_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="请收款"
            android:textSize="12sp"
            android:textColor="#ffffff"
            android:textStyle="bold"
            android:layout_marginLeft="10dp"
            app:layout_constraintStart_toEndOf="@+id/other_transfer_icon"
            app:layout_constraintTop_toBottomOf="@+id/transfer_other_balance"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="0.2dp"
            android:background="#ffffff"
            android:layout_marginLeft="20dp"
            android:layout_marginRight="10dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/other_transfer_icon"
            app:layout_constraintBottom_toTopOf="@+id/transfer_tip"/>

        <TextView
            android:id="@+id/transfer_tip"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            android:layout_marginBottom="6dp"
            android:layout_marginLeft="20dp"
            android:text="@string/wc_chat_transfer_tip"
            android:textSize="10sp"
            android:textColor="#d9d6c3"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

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<WcTransferMainBinding>(){

    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<WcPaymentTransferBinding>(), 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)
    }
}

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/48271.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习基础知识回顾

1. Dataset调用了什么接口&#xff1f; 回答应该是__len__方法和__getitem__方法。 之前写过一篇关于Dataset和Dataloader的介绍&#xff1a; http://t.csdn.cn/b4x0hhttp://t.csdn.cn/b4x0h 2. 目标检测里面用了哪些损失函数&#xff1f; 我的回答是Focal Lo…

【Linux】权限讲解

一、什么是权限 1、权限概念 权限随处可见&#xff0c;在生活中&#xff0c;腾讯非VIP用户不能观看VIP视频&#xff0c;看小说也需要会员&#xff0c;所以权限是限制人的&#xff0c;一件事是否允许被谁做。在Linux系统中也有许多权限&#xff0c;访问文件需要权限&#xff0c…

Kafka: Windows环境-单机部署和伪集群、集群部署

1. kafka 单机版部署 1.1 zookeeper 安装 &#xff08;1&#xff09;下载安装包 官网&#xff1a;Apache ZooKeeper 我用的是 apache-zookeeper-3.7.1-bin.tar.gz 注意&#xff1a;zookeeper的安装路径不要有中文&#xff0c;建议也不要有空格,比如Program Files这样的路径…

移动跨平台技术方案浅析

随着互联网产品逐渐兴起&#xff0c;越来越多产品体验从线下搬到了线上&#xff0c;尤其是移动互联网产品相关&#xff0c;所以很多企业就会更加重视降本增效&#xff0c;以最快的速度推出质量满意度高、用户体验性好的产品&#xff0c;那么就顺势催生了很多跨端跨平台方案。 …

并发编程九 线程池Executor框架

一 线程 线程是调度CPU资源的最小单位&#xff0c;线程模型分为KLT模型与ULT模型&#xff0c;JVM使用的KLT模型&#xff1b; Java线程与OS线程保持1:1的映射关系&#xff0c;也就是说有一个java线程也会在操作系统里有一个对应的线程。Java线程有多种生命状态 NEW,新建 RUNN…

一文带你深入了解Linux IIO 子系统

【推荐阅读】 一文剖析Linux内核中内存管理 分析linux启动内核源码 关于如何快速学好&#xff0c;学懂Linux内核。内含学习路线 工业场合里面也有大量的模拟量和数字量之间的转换&#xff0c;也就是我们常说的 ADC 和 DAC。而且随着手机、物联网、工业物联网和可穿戴设备的…

[第二十二篇]——Docker 安装 MongoDB

Docker 安装 MongoDB MongoDB 是一个免费的开源跨平台面向文档的 NoSQL 数据库程序。 1、查看可用的 MongoDB 版本 访问 MongoDB 镜像库地址&#xff1a; 。 可以通过 Sort by 查看其他版本的 MongoDB&#xff0c;默认是最新版本 mongo:latest。 你也可以在下拉列表中找到…

高校社团管理系统的设计与实现

摘要 随着互联网技术的高速发展&#xff0c;人们生活的各方面都受到互联网技术的影响。现在的社团成员可以通过互联网技术就能实现不在学校&#xff0c;在家也可以查看社团信息并能进行申请加入&#xff0c;简单、快捷的方便了社团成员的社交生活。同样的&#xff0c;在人们的工…

【Spring项目中的统一处理异常】

目录 1. 统一处理异常的机制 2. 关于统一处理异常的方法 3. 关于处理异常的方法的执行特点 1. 统一处理异常的机制 Spring MVC框架提供了统一处理异常的机制&#xff01;表现为每种类型的异常只需要写一段&#xff08;写一次&#xff09;处理此异常的代码即可&#xff0c;项…

需求:针对同一个表格多次导入是否要做判断(此项目是用得若依)

每次上传表时&#xff0c;将上传的表名与以往上传的表名做对比&#xff0c;如果相同&#xff0c;则提示表已经有记录&#xff0c;是否上传相同表并结束此方法。 实现思路&#xff1a; 首先&#xff0c;每次上传表都要把表明记录一下&#xff0c;可以新建一个表&#xff08;数…

天宇优配|离岸人民币狂拉逾千点!中概股暴涨!B站涨22%

当地时间周二&#xff0c;美股三大指数收盘涨跌纷歧。道指涨0.01%&#xff0c;标普500指数跌0.16%&#xff0c;纳指跌0.59%。 抢手中概股领涨&#xff0c;纳斯达克我国金龙指数大涨5.04%&#xff0c;哔哩哔哩&#xff08;B站&#xff09;涨超22%。大型科技股多数跌落&#xff0…

小程序中的confirm-type设置键盘的确认按钮

详情&#xff1a; confirm-type是很多小程序组件中的一种设置&#xff0c;用于改变输入键盘右下角的确认按钮。比如说&#xff0c;正常情况下&#xff0c;键盘上的默认提示可能是完成&#xff0c;但是你可以通过confirm-type将其设置为发送&#xff0c;搜索等&#xff0c;在特…

间隔不到一年开两店,温州鸿雁全屋智能经销商透露了他的生意经

作者 | 牧之 编辑 | 小沐 出品 | 智哪儿 zhinaer.cn编者按&#xff1a;间隔不到一年&#xff0c;连续开设了两家全屋智能体验店。这是发生在温州的渠道商故事。本期专访&#xff0c;「智哪儿」对话浙江林上智能科技有限公司总经理朱飞隆先生。他为何做智能家居&#xff1f;为何…

翻转单词序列、按之字形顺序打印二叉树、二叉搜索树的第k个节点

1、翻转单词序列 本题考点&#xff1a;子串划分&#xff0c;子串逆置 牛客链接 题目描述&#xff1a; 牛客最近来了一个新员工Fish&#xff0c;每天早晨总是会拿着一本英文杂志&#xff0c;写些句子在本子上。同事Cat对Fish写的内容颇感兴趣&#xff0c;有一天他向Fish借来翻…

Python数据库编程之关系数据库API规范

Python关系数据库API规范 对于关系数据库的访问&#xff0c;Python社区已经制定出一个标准&#xff0c;称为Python Database API Specification。Mysql&#xff0c;Oracal等特定数据库模块遵从这一规范&#xff0c;而且可以添加更多特性。 高级数据库API定义了一组用于连接数…

三十六、Java 泛型

Java 泛型 Java 泛型&#xff08;generics&#xff09;是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制&#xff0c;该机制允许程序员在编译时检测到非法的类型。 泛型的本质是参数化类型&#xff0c;也就是说所操作的数据类型被指定为一个参数。 假定我们有这…

火山引擎 DataLeap 的 Data Catalog 系统公有云实践

Data Catalog 通过汇总技术和业务元数据&#xff0c;解决大数据生产者组织梳理数据、数据消费者找数和理解数的业务场景。本篇内容源自于火山引擎大数据研发治理套件 DataLeap 中的 Data Catalog 功能模块的实践&#xff0c;主要介绍 Data Catalog 在公有云部署和发布中遇到挑战…

5. LSTM的C++实现

[C 基于Eigen库实现CRN前向推理] 第三部分&#xff1a;TransposedConv2d实现 &#xff08;含dilation&#xff09; 前言&#xff1a;(Eigen库使用记录)第一部分&#xff1a;WavFile.class (实现读取wav/pcm,实现STFT)第二部分&#xff1a;Conv2d实现第三部分&#xff1a;Tran…

你知道不同U盘在ARM+Linux下的读写速率吗?

优秀的产品离不开完善的测试&#xff0c;即使一个简单的USB接口也要确保稳定性及兼容性。不同的U盘在ARMLinux板卡下的兼容性、速率怎么样呢&#xff1f;本文将为大家提供测试参考数据及详细测试步骤&#xff01; 1. 测试准备 主控选用最近发布的64位Cortex-A55核心板&#xff…

设计模式-day01

1&#xff0c;设计模式概述 1.1 软件设计模式的产生背景 "设计模式"最初并不是出现在软件设计中&#xff0c;而是被用于建筑领域的设计中。 1977年美国著名建筑大师、加利福尼亚大学伯克利分校环境结构中心主任克里斯托夫亚历山大&#xff08;Christopher Alexand…