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:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/wc_base_bg"> <androidx.appcompat.widget.AppCompatEditText android:id="@+id/contacts_search_phone" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="10dp" android:layout_marginTop="10dp" android:paddingLeft="12dp" android:drawableLeft="@android:drawable/ic_search_category_default" android:layout_width="300dp" android:layout_height="48dp" android:background="@color/white" android:hint="账户/手机号"/> <TextView android:id="@+id/contacts_search_cancel" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="@+id/contacts_search_phone" app:layout_constraintBottom_toBottomOf="@+id/contacts_search_phone" app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="10dp" android:padding="12dp" android:textColor="@color/blue" android:textSize="18sp" android:text="取消"/> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/contacts_search_result_layout" app:layout_constraintTop_toBottomOf="@+id/contacts_search_phone" app:layout_constraintStart_toStartOf="parent" android:layout_margin="20dp" android:visibility="gone" android:background="@color/white" android:layout_width="match_parent" android:layout_height="wrap_content"> <androidx.appcompat.widget.AppCompatImageView android:id="@+id/contacts_search_result_icon" app:layout_constraintTop_toTopOf="@+id/contacts_search_result_layout" app:layout_constraintStart_toStartOf="parent" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/contacts_default_icon"/> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/contacts_search_result_txt" app:layout_constraintStart_toEndOf="@+id/contacts_search_result_icon" app:layout_constraintTop_toTopOf="@+id/contacts_search_result_icon" app:layout_constraintBottom_toBottomOf="@+id/contacts_search_result_icon" android:layout_marginLeft="20dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/black" android:textSize="16sp" android:text="搜索:185xxxxxxxxx"/> </androidx.constraintlayout.widget.ConstraintLayout> <androidx.recyclerview.widget.RecyclerView android:id="@+id/contacts_search_recycler_view" app:layout_constraintTop_toBottomOf="@+id/contacts_search_result_layout" app:layout_constraintBottom_toBottomOf="parent" android:layout_width="match_parent" android:layout_margin="10dp" android:layout_height="0dp"/> </androidx.constraintlayout.widget.ConstraintLayout> </layout>
/** * Author : wangning * Email : maoning20080809@163.com * Date : 2022/4/21 21:18 * Description : 根据账户搜索用户 */ class SearchFriendsFragment : BaseDataBindingFragment<WcFragmentContactsSearchBinding>() { override fun getLayoutRes() = R.layout.wc_fragment_contacts_search private val xmppViewModel : XmppViewModel by viewModels() private val userViewModel : UserViewModel by viewModels() private val contactViewModel : ContactsViewModel by viewModels() private var adapter : SearchContactsAdapter? = null //好友列表 private var contactsList : MutableList<ContactsBean>? = null private var navController : NavController? = null override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) super.builder().setTitleContent("") navController = findNavController() contacts_search_cancel.setOnClickListener { Navigation.findNavController(it).popBackStack() } var account = DataStoreUtils.getAccount() contacts_search_result_layout.setOnClickListener { TagUtils.d("搜索查询:${contacts_search_phone.text.toString()}") //xmppViewModel.searchUserByName(contacts_search_phone.text.toString()) userViewModel.getUserLikeAccount(account, contacts_search_phone.text.toString()) } contacts_search_phone.addTextChangedListener(object : TextWatcher{ override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { } override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { //TagUtils.d("onTextChanged ${s}, , count = ${count}, length = ${s?.length}") if(s?.length!! > 0){ var result = getString(R.string.wc_search_friend_tips, s) contacts_search_result_layout.visibility = View.VISIBLE contacts_search_result_txt.text = result } else { contacts_search_result_layout.visibility = View.GONE contacts_search_recycler_view.visibility = View.GONE } } override fun afterTextChanged(s: Editable?) { } }) userViewModel.getUserListLiveData.observe(viewLifecycleOwner){ if(it == null || it.size < 1){ ToastUtils.makeText(R.string.search_list_empty) } else { contacts_search_recycler_view.visibility = View.VISIBLE adapter?.refresh(it) } } contactViewModel.getContactsList(account) contactViewModel.contactsListLiveData.observe(viewLifecycleOwner){ contactsList = it } /*xmppViewModel.userListDataLiveData.observe(viewLifecycleOwner){ contacts_search_recycler_view.visibility = View.VISIBLE adapter?.refresh(it) }*/ adapter = SearchContactsAdapter() var linearLayoutManager = LinearLayoutManager(activity) linearLayoutManager.orientation = LinearLayoutManager.VERTICAL contacts_search_recycler_view.layoutManager = linearLayoutManager contacts_search_recycler_view.adapter = adapter adapter?.setOnItemClickInterface(object : SearchContactsAdapter.OnItemClickInterface{ override fun onItemClick(userBean: UserBean) { SoftInputUtils.hideSoftInput(contacts_search_result_layout) navController?.popBackStack(R.id.nav_contacts_add_friends, true) if(isFriend(userBean.account)) { //如果是好友,直接跳转到聊天页面 var bundle = bundleOf(ChatFragment.USER_ID to userBean.account) navController?.navigate(R.id.nav_chat, bundle) } else { val bundle = bundleOf("userbean" to userBean) navController?.navigate(R.id.action_contacts_search_friends_details, bundle) } } }) } private fun isFriend(searchAccount : String) : Boolean{ var resultList = contactsList?.filter { it.toAccount.equals(searchAccount) } return resultList?.size!! > 0 } }
/** * Author : wangning * Email : maoning20080809@163.com * Date : 2022/4/22 17:51 * Description : */ class SearchContactsAdapter : RecyclerView.Adapter<SearchContactsAdapter.SearchViewHolder>(){ private var userList = ArrayList<UserBean>() private var onItemClickInterface :OnItemClickInterface? = null fun setOnItemClickInterface(onItemClickInterface :OnItemClickInterface?){ this.onItemClickInterface = onItemClickInterface } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchViewHolder { var view = LayoutInflater.from(parent.context).inflate(R.layout.wc_fragment_contacts_search_item, parent, false) return SearchViewHolder(view) } override fun onBindViewHolder(holder: SearchViewHolder, position: Int) { var userBean = userList.get(position) holder.account.text = BaseUtils.getString(R.string.wc_search_friend_account, userBean.account) holder.account.setOnClickListener { onItemClickInterface?.onItemClick(userBean) } } fun refresh(userList : ArrayList<UserBean>) { if(userList == null || userList.size == 0){ this.userList = ArrayList<UserBean>() } else { this.userList = userList } notifyDataSetChanged() } override fun getItemCount(): Int = userList?.size class SearchViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) { var account = itemView.findViewById<TextView>(R.id.contacts_search_item_account) } interface OnItemClickInterface{ abstract fun onItemClick(userBean: UserBean) } }