Kotlin高仿微信-第29篇-朋友圈-发布作品(图片)

news2024/12/23 18:53:29

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

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

效果图:

实现代码:

<?xml version="1.0" encoding="utf-8"?>
<layout>

    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/moment_publish_root"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/wc_base_bg">


        <include layout="@layout/wc_base_top_title"/>

        <androidx.appcompat.widget.AppCompatEditText
            android:id="@+id/moment_publish_content"
            app:layout_constraintTop_toBottomOf="@+id/base_top_root_layout"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="12dp"
            android:maxLines="8"
            android:minLines="4"
            android:gravity="top"
            android:hint="这一刻的想法..."/>

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/moment_publish_recyclerview"
            app:layout_constraintTop_toBottomOf="@+id/moment_publish_content"
            app:layout_constraintStart_toStartOf="parent"
            android:layout_margin="10dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/moment_publish_video"
            app:layout_constraintTop_toBottomOf="@+id/moment_publish_content"
            app:layout_constraintStart_toStartOf="parent"
            android:layout_width="180dp"
            android:layout_height="180dp"
            android:layout_marginLeft="10dp"
            android:scaleType="centerCrop"/>

        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/moment_publish_play"
            app:layout_constraintTop_toTopOf="@+id/moment_publish_video"
            app:layout_constraintBottom_toBottomOf="@+id/moment_publish_video"
            app:layout_constraintStart_toStartOf="@+id/moment_publish_video"
            app:layout_constraintEnd_toEndOf="@+id/moment_publish_video"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:visibility="gone"
            android:src="@android:drawable/ic_media_play"/>


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

/**
 * Author : wangning
 * Email : maoning20080809@163.com
 * Date : 2022/5/24 14:13
 * Description : 发布朋友圈信息
 */
class MomentsPublishFragment : BaseDataBindingFragment<WcMomentsPublishBinding>() {

    override fun getLayoutRes() = R.layout.wc_moments_publish

    var type : Int = CommonUtils.Moments.TYPE_PICTURE
    //多张图片
    var imageList = ArrayList<String>()
    //小视频地址
    var videoFilePath = ""
    private var loadingUtils: BaseDialogUtils? = null
    private var navController: NavController? = null

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        navController = findNavController()

        super.builder().showRightButton().hideTitleContent().setOnRightItemClick(object : WcOnItemClickInterface{
            override fun onItemClick(obj: Any) {
                if(!NetWorkUtils.isNetworkConnected()) {
                    ToastUtils.makeText(requireActivity(), BaseUtils.getString(R.string.wc_base_network_tip))
                    return
                }

                SoftInputUtils.hideSoftInput(moment_publish_content)
                showLoadingDialog()

                //点击右上角发表按钮
                CoroutineScope(Dispatchers.IO).launch {
                    when(type){
                        CommonUtils.Moments.TYPE_PICTURE -> {
                            var result = UploadFileUtils.uploadImages(type, moment_publish_content.text.toString(), imageList)
                            publishResult(result)
                        }
                        CommonUtils.Moments.TYPE_VIDEO -> {
                            var result = UploadFileUtils.uploadVideo(type, moment_publish_content.text.toString(), videoFilePath)
                            publishResult(result)
                        }
                    }
                }
            }
        })

        type = arguments?.get(CommonUtils.Moments.TYPE_NAME) as Int
        videoFilePath = arguments?.get(CommonUtils.Moments.TYPE_VIDEO_PATH).toString()
        var images = arguments?.get(CommonUtils.Moments.TYPE_IMAGE_PATH)
        TagUtils.d("朋友圈:${type}, ${videoFilePath} , ${images}")
        if(images != null && !"null".equals(images)){
            if(images is String){
                imageList.add(images)
            } else {
                imageList = images as ArrayList<String>
            }
        }

        when(type){
            CommonUtils.Moments.TYPE_PICTURE -> showImage()
            CommonUtils.Moments.TYPE_VIDEO -> showVideo()
        }

    }

    //显示图片
    fun showImage(){
        moment_publish_video.visibility = View.GONE
        moment_publish_play.visibility = View.GONE
        moment_publish_recyclerview.visibility = View.VISIBLE

        var adapter = MomentsPublishAdapter(1, imageList, object : WcOnItemClickInterface{
            override fun onItemClick(obj: Any) {
                var iamgeFilePath = obj as String
                var bundle = bundleOf(CommonUtils.Moments.TYPE_NAME to type, CommonUtils.Moments.TYPE_IMAGE_PATH to iamgeFilePath)
                Navigation.findNavController(moment_publish_recyclerview).navigate(R.id.action_publish_preview, bundle)
            }
        })
        var linearLayoutManager = GridLayoutManager(requireActivity() , 3)
        moment_publish_recyclerview.layoutManager = linearLayoutManager
        moment_publish_recyclerview.adapter = adapter
    }

    //显示小视频
    fun showVideo(){
        TagUtils.d("显示视频路径:$videoFilePath")
        moment_publish_video.visibility = View.VISIBLE
        moment_publish_play.visibility = View.VISIBLE
        moment_publish_recyclerview.visibility = View.GONE
        //var videoFilePath = "/mnt/sdcard/image/1.mp4"
        val retriever = MediaMetadataRetriever()

        var path :String? = videoFilePath
        val uri = Uri.parse(path)
        val scheme = uri.scheme
        if ("file" == scheme) {
            path = uri.getPath()
            TagUtils.d("显示视频路径path = :$path")
            retriever.setDataSource(path)
        } else {
            retriever.setDataSource(videoFilePath)
        }
        val bmp = retriever.getFrameAtTime(0, MediaMetadataRetriever.OPTION_CLOSEST_SYNC)
        moment_publish_video.setImageBitmap(bmp)

        moment_publish_video.setOnClickListener {
            var bundle = bundleOf(CommonUtils.Moments.TYPE_NAME to type, CommonUtils.Moments.TYPE_IMAGE_PATH to videoFilePath)
            Navigation.findNavController(it).navigate(R.id.action_publish_preview, bundle)
        }

    }

    //显示加载对话框
    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 publishResult(any: Any?){
        CoroutineScope(Dispatchers.Main).launch {
            dismissLoadingDialog()
            if(any == null){
                ToastUtils.makeText(R.string.wc_publish_failure)
                Navigation.findNavController(moment_publish_video).popBackStack()
            } else {
                var momentsBean = any as MomentsBean
                CoroutineScope(Dispatchers.IO).launch {
                    MomentsRepository.insertMomentLocal(momentsBean)
                    CoroutineScope(Dispatchers.Main).launch {
                        ToastUtils.makeText(R.string.wc_publish_success)
                        navController?.previousBackStackEntry?.savedStateHandle?.set(CommonUtils.Moments.PUBLISH_SUCCESS, true)
                        navController?.popBackStack()
                    }
                }
            }
        }
    }

    //隐藏加载对话框
    private fun dismissLoadingDialog(){
        loadingUtils?.dismiss()
    }

}

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

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

相关文章

GmNAC181促进结瘤并提高根瘤的耐盐性

文章信息 题目&#xff1a;GmNAC181 promotes symbiotic nodulation and salt tolerance of nodulation by directly regulating GmNINa expression in soybean 刊名&#xff1a;New Phytologist 作者&#xff1a;Xiaodi Wang&#xff0c;Youning Wang, Xia Li et al. 单位…

2022年NPDP新版教材知识集锦--【第四章节】(5)

《产品经理认证(NPDP)知识体系指南(第2版)》已于2022年4月正式上架发行&#xff0c;新版教材自2022年11月NPDP考试起使用。将新版NPDP教材中的相关知识点进行了整理汇总&#xff0c;包括详细设计与规格阶段相关内容&#xff0c;快来看看吧。 【详细设计与规格阶段】(全部获取文…

HCIP-路由01:路由基础

路由基础一 自治系统&#xff08;AS&#xff09;二. 入表&#xff08;路由表&#xff09;规则2.1 priority2.2 metric三. 选路规则&#xff08;掩码最长匹配原则&#xff09;四. 路由的负载分担五. 路由备份&#xff08;浮动路由&#xff09;六. 路由黑洞七. 路由黑洞的解决方法…

export default 和 export之间的区别

&#x1f388; export default 和 export 有什么区别&#xff1a; export 、export default&#xff0c;都属于ES6里面的语法 1. export与export default均可用于导出常量、函数、文件、模块等 2. 你可以在其它文件或模块中通过import(常量 | 函数 | 文件 | 模块)名的方式&a…

03【Controller方法返回值详解】

文章目录三、Controller方法返回值详解3.1 返回普通字符串3.1.1 跳转3.1.2 设置视图解析器3.2 返回ModelAndView3.2.1 普通视图3.2.2 RedirectView3.3 返回特殊字符串3.4 返回void三、Controller方法返回值详解 3.1 返回普通字符串 3.1.1 跳转 package com.dfbz.controller;…

美颜预览卡顿问题跟踪

预览卡顿的问题&#xff0c;首先第一想法就是看下帧率&#xff0c;帧率小&#xff0c;自然会卡顿。根据人眼视觉暂留原理&#xff0c;帧率小于24帧&#xff0c;人脸就会感知到卡顿。 帧率的概念在Camera中我们经常会提到&#xff0c;其实有3个帧率概念&#xff0c;从下往常看&a…

1-5-10 快恢在数字化安全生产平台 DPS 中的设计与落地

作者&#xff1a;银桑 背景 11 月 5 日&#xff0c;在 2022 杭州 云栖大会上&#xff0c;数字化安全生产平台 DPS 重磅发布&#xff0c;助力传统运维向 SRE 转型&#xff0c;在数字化安全生产平台 DPS 重磅发布中提到了 DPS 诞生的背景&#xff0c;希望解决的企业问题以及核…

ICC2: secondary pg pin的作用与连接

1.secondary pg pin的作用 1&#xff09; 作为备用电源&#xff08;backup power&#xff09;&#xff0c;当主供电&#xff08;primary power&#xff09;断电后&#xff0c;让standard cell仍能保持正常运行或者至少保持输出不变&#xff0c;比如always on buf和retention r…

【矩阵论】4. 矩阵运算——广义逆——加号逆应用

4.4.3 矩阵方程求解 前置&#xff1a;正规方程 a. 有解情况 若矩阵方程 AXBDAXBDAXBD 有解相容&#xff0c;则有特解 X0ADBX_0A^DB^X0​ADB 无解定理&#xff1a;若 X0ADBX_0A^DB^X0​ADB &#xff0c;使 AX0B≠DAX_0B\neq DAX0​B​D &#xff0c;则矩阵方程无解 齐次方程…

【学习笔记】深度学习入门:基于Python的理论与实现-神经网络

CONTENTS三、神经网络3.1 从感知机到神经网络3.2 Activation function3.3 多维数组的运算3.4 三层神经网络的实现3.5 输出层的设计3.6 手写数字识别三、神经网络 3.1 从感知机到神经网络 用图来表示神经网络的话&#xff0c;如下图所示&#xff0c;我们把最左边的一列称为输入…

Open WebRTC Toolkit Native SDK Windows环境编译

1、首先按照编译webrtc原生代码环境&#xff0c;配置系统环境 https://chromium.googlesource.com/chromium/src//main/docs/windows_build_instructions.mdhttps://chromium.googlesource.com/chromium/src//main/docs/windows_build_instructions.md 安装openssl软件/s…

MODBUS协议下,能否实现MCGS触摸屏与FX5U之间无线通讯?

在工厂里&#xff0c;触摸屏往往位于程控室内&#xff0c;作为控制多个不同位置PLC的主站设备。因为触摸屏和plc所处位置距离较为分散&#xff0c;重新铺设电缆线工期长&#xff0c;成本高&#xff0c;故采用无线方式解决触摸屏与PLC之间的通讯问题。 一、方案概述 本方案是M…

年底了,准备跳槽的可以看看

前两天跟朋友感慨&#xff0c;今年的铜九铁十、裁员、疫情导致好多人都没拿到offer!现在已经12月了&#xff0c;具体明年的金三银四只剩下两个月。 对于想跳槽的职场人来说&#xff0c;绝对要从现在开始做准备了。这时候&#xff0c;很多高薪技术岗、管理岗的缺口和市场需求也…

【Linux03-基本工具之VIM】Linux下的强大编辑器(附软件生态与yum)

前言 本期分享6个Linux中常用的基本工具&#xff0c;以确保后续的学习能够进行。 零、软件生态与yum 抛出一个问题&#xff1a;软件的下载&#xff1f; 具体拆分 软件从哪里下&#xff1f;软件由谁提供&#xff1f;怎么下载&#xff1f; 软件&#xff0c;肯定不在本地&am…

RabbitMQ死信队列、延时队列

介绍&#xff1a; 消息被消费⽅否定确认&#xff0c;使⽤ channel.basicNack 或 channel.basicReject &#xff0c;并且此时 requeue 属性被设置为 false 。消息在队列的存活时间超过设置的TTL时间。消息队列的消息数量已经超过最⼤队列⻓度。那么该消息将成为“死信”。“死信…

Espresso Sequencer:去中心化Rollups

1. 引言 前序博客有&#xff1a; HyperPlonk——实现zkEVM的一种zk-proof system Espresso Systems团队致力于为Web3世界开发工具和基础设施。 Espresso Sequencer&#xff1a;为在不牺牲扩展性和速度的情况下&#xff0c;实现的去中心化rollups系统&#xff0c;兼具Web2的性…

[附源码]计算机毕业设计springboot软考刷题小程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

MAC层协议总结

一、现存问题 广播网络存在问题 当信道的使用存在竞争时&#xff0c;如何分配信道的使用权----->如一个人停止讲话&#xff0c;另外可能两个或多个人同时讲话&#xff0c;当只有单个信道时&#xff0c;怎么决定下一个讲话的人&#xff1f;------>为了解决这个问题&#…

JavaCV音视频开发宝典:rtsp转推到rtp(非TS流方式),及使用TS流发送解决sdp缺失问题

《JavaCV音视频开发宝典》专栏目录导航 《JavaCV音视频开发宝典》专栏介绍和目录 前言 在之前的文章中,由于忘记介绍使用的rtp推流方式都是TS流方式,RTP方式推流没讲,本章作为之前文章(JavaCV音视频开发宝典:rtsp拉流并使用转码方式转推到rtp)的补充。 注意:本文不需要…

Spring MVC Formatter(数据格式化)详解

Spring MVC 框架的 Formatter 与 Converter 一样&#xff0c;也是一个可以将一种数据类型转换成另一种数据类型的接口。不同的是&#xff0c;Formatter 的源数据类型必须是 String 类型&#xff0c;而 Converter 的源数据类型是任意数据类型。 在 Web 应用中由 HTTP 发送的请求…