Kotlin高仿微信-项目实践58篇详细讲解了各个功能点,包括:注册、登录、主页、单聊(文本、表情、语音、图片、小视频、视频通话、语音通话、红包、转账)、群聊、个人信息、朋友圈、支付服务、扫一扫、搜索好友、添加好友、开通VIP等众多功能。
效果图:
实现代码:
<?xml version="1.0" encoding="utf-8"?> <layout> <androidx.core.widget.NestedScrollView 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:layout_width="match_parent" android:layout_height="match_parent" > <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="100dp"> <TextView android:layout_width="match_parent" android:layout_height="0.5dp" android:layout_marginStart="80dp" android:layout_marginTop="10dp" android:layout_marginEnd="20dp" android:background="@color/gray" android:text="-" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/me_personal_avatar" /> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/me_personal_avatar" android:layout_width="match_parent" android:layout_height="wrap_content" android:foreground="?selectableItemBackground" android:layout_marginTop="36dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> <androidx.appcompat.widget.AppCompatImageView android:id="@+id/me_personal_img" android:layout_width="80dp" android:layout_height="80dp" android:layout_marginStart="22dp" android:scaleType="center" android:src="@drawable/contacts_default_icon" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.appcompat.widget.AppCompatImageView android:id="@+id/me_personal_right" android:layout_width="20dp" android:layout_height="20dp" android:layout_marginRight="10dp" android:src="@drawable/me_base_arrowright" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="@+id/me_personal_account" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/me_personal_account" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginBottom="10dp" android:text="账号:" android:textColor="@color/gray" android:textSize="18sp" app:layout_constraintBottom_toBottomOf="@+id/me_personal_img" app:layout_constraintStart_toEndOf="@+id/me_personal_img" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/me_personal_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginTop="10dp" android:text="昵称" android:textColor="@color/black" android:textSize="22sp" android:textStyle="bold" app:layout_constraintStart_toEndOf="@+id/me_personal_img" app:layout_constraintTop_toTopOf="@+id/me_personal_img" /> </androidx.constraintlayout.widget.ConstraintLayout> <com.wn.wechatclientdemo.view.LineBaseView android:id="@+id/me_payment" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/me_personal_avatar" android:layout_marginTop="22dp" android:layout_width="match_parent" android:layout_height="wrap_content"/> <com.wn.wechatclientdemo.view.LineBaseView android:id="@+id/me_scan" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/me_payment" android:layout_marginTop="6dp" android:layout_width="match_parent" android:layout_height="wrap_content"/> <com.wn.wechatclientdemo.view.LineBaseView android:id="@+id/me_moments" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/me_scan" android:layout_marginTop="6dp" android:layout_width="match_parent" android:layout_height="wrap_content"/> <com.wn.wechatclientdemo.view.LineBaseView android:id="@+id/me_setting" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/me_moments" android:layout_marginTop="6dp" android:layout_width="match_parent" android:layout_height="wrap_content"/> </androidx.constraintlayout.widget.ConstraintLayout> </androidx.core.widget.NestedScrollView> </layout>
/** * Author : wangning * Email : maoning20080809@163.com * Date : 2022/4/21 12:24 * Description : 一行通用控件, 左边一个图标, 右边一个箭头, 中间有标题和描述 */ class LineBaseView : LinearLayout { constructor(context:Context) : this(context, null) constructor(context: Context, attributeSet: AttributeSet?) : this(context, attributeSet, 0) constructor(context: Context, attributeSet: AttributeSet? , defStyleAttr : Int) : super(context, attributeSet, defStyleAttr){ } var baseView : View? = null init { baseView = LayoutInflater.from(context).inflate(R.layout.wc_line_base_view, this) } fun builder() : Builder{ return Builder(line_base_left, line_base_right, line_base_title, line_base_content, line_base_root, line_base_dividing) } class Builder(leftImageView : ImageView, rightImageView : ImageView, titleTextView : TextView, contentTextView : TextView, rootView : ConstraintLayout, dividingView : TextView) { private var leftImageView : ImageView = leftImageView private var rightImageView = rightImageView private var titleTextView = titleTextView private var contentTextView = contentTextView private var rootView = rootView private var dividingView = dividingView fun setLeftImage(resId : Int) : Builder{ leftImageView.setImageResource(resId) return this } fun setLeftClick(onClickListener: OnClickListener) : Builder{ leftImageView.setOnClickListener(onClickListener) return this } fun hideLeftImage() : Builder { leftImageView.visibility = GONE return this } fun setTitle(resId: Int) : Builder { titleTextView.text = WcApp.getContext().resources.getString(resId) return this } fun setTitle(title: String) : Builder { titleTextView.text = title return this } fun setTitleColor(colorId : Int) : Builder { titleTextView.setTextColor(WcApp.getContext().resources.getColor(colorId)) return this } fun setTitleSize(size : Float) : Builder{ titleTextView.setTextSize(size) return this } fun setContentSize(size : Float) : Builder{ contentTextView.setTextSize(size) return this } fun setContentColor(colorId : Int) : Builder { contentTextView.setTextColor(WcApp.getContext().resources.getColor(colorId)) return this } fun setContent(resId : Int) : Builder { contentTextView.text = WcApp.getContext().resources.getString(resId) return this } fun setContent(content : String) : Builder { contentTextView.text = content return this } fun hideContent() : Builder{ contentTextView.visibility = GONE return this } fun showContent() : Builder{ contentTextView.visibility = VISIBLE return this } fun setRightImage(resId : Int) : Builder{ rightImageView.setImageResource(resId) return this } fun setRightClick(onClickListener: OnClickListener) : Builder { rightImageView.setOnClickListener(onClickListener) return this } fun hideRightImage() : Builder { rightImageView.visibility = GONE return this } fun setRootClick(onClickListener: OnClickListener) : Builder { rootView.setOnClickListener(onClickListener) return this } fun hideDevideingView() : Builder{ dividingView.visibility = View.GONE return this } } }
/** * author : wangning * email : maoning20080809@163.com * Date : 2022/4/7 13:12 * description : 我的页面 */ class MeFragment : BaseDataBindingFragment<WcFragmentMeBinding>() { override fun getLayoutRes()= R.layout.wc_fragment_me //文件存储权限 private val REQ_CODE_STORAGE = 1 private val userViewModel : UserViewModel by viewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initView() me_personal_avatar.setOnClickListener { Navigation.findNavController(it).navigate(R.id.action_me_personal) } //handlePermission() initData() //先判断是否已经注册 if(!EventBus.getDefault().isRegistered(this)){ EventBus.getDefault().register(this) } } @Subscribe(threadMode = ThreadMode.MAIN) fun onMessageCallback(obj: Any) { if(obj == null){ return } if(obj is EventMsgBean){ if(obj.type == EventMsgBean.TYPE_REFRESH_USER_NAME){ //刷新昵称 me_personal_name.text = obj.obj as String } else if(obj.type == EventMsgBean.TYPE_REFRESH_AVATAR){ //刷新头像 GlideUtils.load(me_personal_img, obj.obj as String) } } } override fun onDestroy() { super.onDestroy() EventBus.getDefault().unregister(this) } fun initView() { //支付 me_payment.builder() .setLeftImage(R.drawable.me_base_payment) .setTitle(BaseUtils.getString(R.string.me_base_payment)) .hideContent() .setRootClick { Navigation.findNavController(it).navigate(R.id.action_me_payment) } /*//收藏 me_collection.builder() .setLeftImage(R.drawable.me_base_collection) .setTitle(BaseUtils.getString(R.string.me_base_collection)) .hideContent() .setRootClick { Navigation.findNavController(it).navigate(R.id.action_me_collection) }*/ //朋友圈 me_moments.builder() .setLeftImage(R.drawable.me_base_moments) .setTitle(BaseUtils.getString(R.string.me_base_moments)) .hideContent() .setRootClick { //旧的没实现 navCollection?.navigate(R.id.action_me_moments) Navigation.findNavController(it).navigate(R.id.action_discover_moments) } //扫一扫 me_scan.builder() .setLeftImage(R.drawable.wc_moments_scan) .setTitle(BaseUtils.getString(R.string.me_moments_sanc)) .hideContent() .setRootClick { Navigation.findNavController(it).navigate(R.id.nav_qrcode_scan) } /*//视频号 me_video.builder() .setLeftImage(R.drawable.me_base_video) .setTitle(BaseUtils.getString(R.string.me_base_video)) .hideContent() .setRootClick { Navigation.findNavController(it).navigate(R.id.action_me_video) }*/ //卡包 /*me_card_bag.builder() .setLeftImage(R.drawable.me_base_card_bag) .setTitle(BaseUtils.getString(R.string.me_base_card_bag)) .hideContent() .setRootClick { Navigation.findNavController(it).navigate(R.id.action_me_card_bag) }*/ /*//表情 me_expression.builder() .setLeftImage(R.drawable.me_base_expression) .setTitle(BaseUtils.getString(R.string.me_base_expression)) .hideContent() .setRootClick { Navigation.findNavController(it).navigate(R.id.action_me_expression) }*/ //设置 me_setting.builder() .setLeftImage(R.drawable.me_base_setting) .setTitle(BaseUtils.getString(R.string.me_base_setting)) .hideContent() .setRootClick { Navigation.findNavController(it).navigate(R.id.action_me_setting) } } fun initData(){ var account = DataStoreUtils.getAccount() userViewModel.getUserLocal(account) userViewModel.userBeanLocal.observe(viewLifecycleOwner){ if(it == null) return@observe me_personal_name.text = it.nickName var accountResult = getString(R.string.wc_me_show_account, it.account) me_personal_account.text = accountResult GlideUtils.load(me_personal_img, it.getReallyAvatar(), R.drawable.contacts_default_icon) } userViewModel.avatarFilePathLiveData.observe(viewLifecycleOwner){ if(!TextUtils.isEmpty(it)){ GlideUtils.load(me_personal_img, it) } } } /*private fun handlePermission(){ if(ContextCompat.checkSelfPermission(requireActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQ_CODE_STORAGE) TagUtils.d("我的 权限if ") } else { TagUtils.d("我的 权限 else ") initData() } } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if(requestCode == REQ_CODE_STORAGE && grantResults != null && grantResults.size > 0){ initData() } }*/ //授权成功,刷新页面 fun refresh(){ initData() } }
版权声明:本文为maoning20080808原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。