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