RecyclerView小部件是ListView和GridView的更高级和灵活的版本。
在此输入图像描述 如何使用此视图更改我的项目,例如这张照片。 是图书馆视图还是回收视图? 我想要一份像这张照片一样的物品或回收商列表。 请帮帮我! 我们如何...
NotifyItemRemoved() 无法正常工作。删除错误的元素
我有 8 个国家/地区的列表,我希望当单击第一个国家/地区的箭头图像时,应从列表中删除第二个国家/地区名称(中国)。但第三个国家却得到了
具有多种视图类型和 ItemTouchHelper 的 Android RecyclerView
我正在尝试让 ItemTouchHelper 与具有多种视图类型的 RecyclerView 一起使用。我看到一些答案说为了让它工作,recyclerView 适配器必须有
如何在不使用nestedscrollview的情况下滚动具有recyclerview的屏幕?
我有一个视图,其中包含 RecyclerView 和放置在 NestedScrollView 中的其他元素。我的问题是,当 RecyclerView 中的项目太多时,界面会冻结几秒钟。 我...
Android Studio(Java)最新版本,。我创建了一个带有布局的“基本”片段(回收器视图)。当我尝试从派生片段访问它时,我得到: E/RecyclerView:没有布局管理...
RecyclerView ItemTouchHelper 滑动时两个按钮
关注这个问题 RecyclerView ItemTouchHelper 滑动按钮 (不一样)。我想在每一侧添加按钮。 该链接的官方答案仅适用于一侧。 我有什么...
如何使用 StaggeredGridLayoutManager 将文本分隔线放入 Recyclerview 中?
我试图在带有 StaggeredGridLayoutManager 的 RecyclerView 的项目之间放置一些包含时间戳的文本分隔符。 我尝试使用 ItemDecoration 类,但我认为它不能做到...
我查看了无数关于此问题的stackoverflow线程,但找不到解决方案。所以我的问题是,当我滚动回收器视图时,数据会在一瞬间混合在一起......
我的recylerview行为不当,即不同适配器的数据不占用前一个适配器的空间,即使在调用notify datsetchange之后,数据也会向下跳过,即: 如果(我...
我正在将图片和字符串加载到 Recyclerview 中。我曾经发现 setStackfrombottom 正在工作。但现在不是了。我不知道为什么。这是我的代码: 消息适配器消息适配器 = ...
我正在尝试创建一个类似于默认设置应用程序中的 WearableListView 。我有一个可滚动的 WearableListView,并对每个元素进行动画处理。我现在需要的只是......顶部的标题
应用过滤后,我在 RecyclerView 中选择项目时遇到问题。这是场景: 我有一个 RecyclerView 使用自定义适配器显示项目列表(PayloadAdapte...
`我有一个回收器视图,我想从中删除一个项目,但删除后我的应用程序崩溃了。我正在使用 firebase 来存储数据,我也使用 onDeleteClickListener 但我没有工作。 每个...
我在使用导航栏时遇到回收站视图不起作用的问题。 最初我编写了代码,将我的 4 个片段添加到导航栏配置中,并且导航工作正常...
当视图离开屏幕时,Android 动画在 RecyclerView 中停止工作
我这样设置动画: @覆盖 公共无效onBindViewHolder(ViewHolder持有者,int位置){ 动画 anim = AnimationUtils.loadAnimation(context, R.anim.rotate); ...
HorizontalScrollView 内的 RecyclerView 未显示所有项目
我在 HorizontalScrollView 中有一个 RecyclerView。我没有在 RecyclerView 中看到所有项目。我看过,即使适配器中的列表有 7 个项目,onBindViewHolder 也只会调用 4 个...
如何将 SpanSizeLookup 逻辑添加到 VerticalGridView?
我正在开发一个用于电视平台的应用程序,当带有 GridLayoutManager 的默认 RecyclerView 无法正确处理 DPAD 的焦点控制时,我遇到了一个问题。它有以下问题: 重点是
目前我正在试验视图模型,想知道将视图模型传递给 recyclerview 适配器是否会导致内存泄漏?适配器中视图模型的唯一目的是提供...
RecyclerView 移动到 ListFragment 时会无限期加载
我已经按照本教程进行操作:https://developer.android.com/codelabs/android-room-with-a-view-kotlin。 代码工作完美,但我想将 RecyclerView 移动到片段。 现在列表已加载
希望 recyclerview 在创建活动时从下到上开始,并在添加新项目时再次在底部滚动
我的 Android 应用程序中有一个名为 ChatActivity 的活动。这是 xml 布局: 我的 Android 应用程序中有一个名为 ChatActivity 的活动。这是 xml 布局: <?xml version="1.0" encoding="utf-8"?> <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/main" android:layout_width="match_parent" android:layout_height="match_parent" android:windowSoftInputMode="adjustResize" tools:context=".ui.home.ui.chat.ChatActivity"> <com.google.android.material.appbar.MaterialToolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:navigationIcon="?attr/homeAsUpIndicator" app:navigationIconTint="@color/black" app:title="@string/chat" app:titleCentered="true" > <de.hdodenhof.circleimageview.CircleImageView android:id="@+id/ivProfile" android:layout_width="@dimen/_30sdp" android:layout_height="@dimen/_30sdp" android:src="@drawable/ic_dummy_user" android:layout_marginHorizontal="@dimen/_10sdp" android:layout_gravity="end" /> </com.google.android.material.appbar.MaterialToolbar> <androidx.recyclerview.widget.RecyclerView android:id="@+id/rvMessages" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintTop_toBottomOf="@id/toolbar" android:paddingBottom="@dimen/_95sdp" app:layout_constraintHorizontal_bias="1.0" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintVertical_bias="1.0" tools:listitem="@layout/item_message_sent" /> <com.google.android.material.textfield.TextInputLayout android:id="@+id/tiMessage" style="@style/textInputLayout" android:layout_width="0dp" android:layout_height="wrap_content" android:maxHeight="@dimen/_200sdp" android:layout_marginLeft="@dimen/_5sdp" android:layout_marginRight="@dimen/_35sdp" android:layout_marginTop="5dp" android:layout_marginBottom="5dp" app:errorEnabled="false" android:layout_marginVertical="@dimen/_5sdp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" > <com.google.android.material.textfield.TextInputEditText android:layout_width="match_parent" android:layout_height="wrap_content" android:maxHeight="@dimen/_200sdp" android:autofillHints="name" android:hint="@string/message" android:inputType="textMultiLine" /> </com.google.android.material.textfield.TextInputLayout> <ImageView android:id="@+id/ivSend" android:layout_width="@dimen/_25sdp" android:layout_height="@dimen/_25sdp" android:src="@drawable/ic_send_message" app:layout_constraintRight_toRightOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="@dimen/_12sdp" app:layout_constraintLeft_toRightOf="@id/tiMessage" app:tint="@color/blue" /> </androidx.constraintlayout.widget.ConstraintLayout> 当我打开 textInput 字段时,布局不适应它,它仅显示要打开的键盘,但是当我在键盘中键入时,它确实会在文本输入布局中键入,但在键入时用户无法看到文本输入布局。关闭键盘 + 回收视图开始从上到下滚动,但我希望它像聊天一样,从下到上。在添加的新消息上,它确实滚动到底部,但在现有列表的最后一项上,而不是在新项目上。 我尝试过使用 android:windowSoftInputMode="adjustResize" 作为键盘和 private fun scrollToBottom() { binding.rvMessages.scrollToPosition(adapter.itemCount -1) } 用于回收视图。 欢迎任何优化代码/改进的建议。我的活动代码是: @AndroidEntryPoint class ChatActivity : AppCompatActivity() { private lateinit var binding: ActivityChatBinding private lateinit var database: DatabaseReference private lateinit var adapter: ChatAdapter private var currentUserId: Int = 0 private var otherUserId: Int = 0 private lateinit var conversationId: String private var convoId = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() binding = ActivityChatBinding.inflate(layoutInflater) setContentView(binding.root) ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) insets } binding.toolbar.setNavigationOnClickListener { onBackPressedDispatcher.onBackPressed() } val userDetails = intent.getParcelableExtra<ConnectionDetailDTO>("USER_DETAILS") val currentUser = Paper.book().read<User>(Constant.k_user) currentUserId = currentUser?.id!! otherUserId = userDetails?.id!! binding.toolbar.title = userDetails.name Glide.with(this).load(userDetails.profileUrl).placeholder(R.drawable.ic_dummy_user).into(binding.ivProfile) binding.ivProfile.setOnClickListener{showProfile()} adapter = ChatAdapter(currentUserId) binding.rvMessages.layoutManager = LinearLayoutManager(this) binding.rvMessages.adapter = adapter scrollToBottom() val database = FirebaseDatabase.getInstance() val reference = database.getReference("Conversations") reference.addValueEventListener(object : ValueEventListener { override fun onDataChange(dataSnapshot: DataSnapshot) { val messages = mutableListOf<Message>() for (conversationSnapshot in dataSnapshot.children) { val conversationIdParts = conversationSnapshot.key?.split("_") if (conversationIdParts?.size == 3) { val firstUserId = conversationIdParts[1] val secondUserId = conversationIdParts[2] convoId = "conversation_${firstUserId}_${secondUserId}" if (firstUserId == currentUserId.toString() && secondUserId == otherUserId.toString() || firstUserId == otherUserId.toString() && secondUserId == currentUserId.toString()) { val conversationMessages = mutableListOf<Message>() for (messageSnapshot in conversationSnapshot.child("messages").children) { val content = messageSnapshot.child("content").value.toString() val date = messageSnapshot.child("date").value.toString() val messageId = messageSnapshot?.child("id")?.value.toString() val isRead = messageSnapshot.child("isRead").value as? Boolean ?: false val name = messageSnapshot.child("name").value.toString() val senderEmail = messageSnapshot.child("senderEmail").value.toString() val type = messageSnapshot.child("type").value.toString() val message = Message(content, date, messageId, isRead, name, senderEmail, type) conversationMessages.add(message) Log.d(TAG, "onDataChange: $message") } messages.addAll(conversationMessages) } } } Log.d(TAG, "onDataChange: $messages") adapter.updateMessages(messages) } override fun onCancelled(databaseError: DatabaseError) { println("Error: ${databaseError.message}") } }) binding.ivSend.setOnClickListener { val messageText = binding.tiMessage.editText?.text.toString().trim() if (messageText.isNotEmpty()) { val conversationId1 = "conversation_${currentUserId}_${otherUserId}" val conversationId2 = "conversation_${otherUserId}_${currentUserId}" reference.child(conversationId1).get().addOnCompleteListener { task -> if (task.isSuccessful) { val data = task.result?.value val conversationId = if (data != null) { conversationId1 } else { conversationId2 } val messageReference = reference.child(conversationId).child("messages").push() val message = Message( content = messageText, date = SimpleDateFormat( "yyyy-MM-dd HH:mm:ss", Locale.getDefault() ).format(Date()), id = messageReference.key!!, isRead = false, name = currentUser?.name ?: "", senderEmail = currentUserId.toString(), type = "text" ) messageReference.setValue(message) binding.tiMessage.editText?.setText("") scrollToBottom() } } addUser(currentUserId.toString()) } } } private fun scrollToBottom() { binding.rvMessages.scrollToPosition(adapter.itemCount -1) } } 我尝试了 StackOverFLow 和 Chat GPT 的回收器视图解决方案 回收视图开始从上到下滚动,但我希望它是 就像聊天一样,从下到上。添加新消息后,它会滚动到 底部,但在现有列表的最后一项上,而不是在新项目上。 我尝试过使用.. recyclerView 从顶部开始并且不会在新项目上滚动到底部的原因是因为您在将项目添加到适配器之前调用了scrollToBottom()。 删除scrollToBottom()中的binding.ivSend.setOnClickListener{}并将其添加到adapter.updateMessages(messages)下面 Log.d(TAG, "onDataChange: $messages") adapter.updateMessages(messages) scrollToBottom() 这样,当首次从数据库加载项目以及添加新项目时,回收器视图将向下滚动。 为了更容易阅读代码,我建议您将代码排序到方法中,而不是将所有内容都放在 override fun onCreate(savedInstanceState: Bundle?) {} 中。 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() binding = ActivityChatBinding.inflate(layoutInflater) setContentView(binding.root) ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) insets } setArgs() setupUI() setupDatabase() setupListeners() } private fun setArgs(){ userDetails = intent.getParcelableExtra<ConnectionDetailDTO>("USER_DETAILS") currentUser = Paper.book().read<User>(Constant.k_user) } private fun setupUI(){ //toolbar binding.toolbar.setNavigationOnClickListener { onBackPressedDispatcher.onBackPressed() } binding.toolbar.title = userDetails.name Glide.with(this).load(userDetails.profileUrl).placeholder(R.drawable.ic_dummy_user).into(binding.ivProfile) binding.ivProfile.setOnClickListener{showProfile()} //recycler view adapter = ChatAdapter(currentUser.id) binding.rvMessages.layoutManager = LinearLayoutManager(this) binding.rvMessages.adapter = adapter } private fun setupDatabase(){ database = FirebaseDatabase.getInstance() reference = database.getReference("Conversations") } private fun setupListeners(){ reference.addValueEventListener(object : ValueEventListener { override fun onDataChange(dataSnapshot: DataSnapshot) { val messages = mutableListOf<Message>() for (conversationSnapshot in dataSnapshot.children) { val conversationIdParts = conversationSnapshot.key?.split("_") if (conversationIdParts?.size == 3) { val firstUserId = conversationIdParts[1] val secondUserId = conversationIdParts[2] convoId = "conversation_${firstUserId}_${secondUserId}" if (firstUserId == currentUser.id.toString() && secondUserId == currentUser.id.toString() || firstUserId == userDetails.id.toString() && secondUserId == currentUser.id.toString()) { val conversationMessages = mutableListOf<Message>() for (messageSnapshot in conversationSnapshot.child("messages").children) { val content = messageSnapshot.child("content").value.toString() val date = messageSnapshot.child("date").value.toString() val messageId = messageSnapshot?.child("id")?.value.toString() val isRead = messageSnapshot.child("isRead").value as? Boolean ?: false val name = messageSnapshot.child("name").value.toString() val senderEmail = messageSnapshot.child("senderEmail").value.toString() val type = messageSnapshot.child("type").value.toString() val message = Message(content, date, messageId, isRead, name, senderEmail, type) conversationMessages.add(message) Log.d(TAG, "onDataChange: $message") } messages.addAll(conversationMessages) } } } Log.d(TAG, "onDataChange: $messages") adapter.updateMessages(messages) } override fun onCancelled(databaseError: DatabaseError) { println("Error: ${databaseError.message}") } }) binding.ivSend.setOnClickListener { val messageText = binding.tiMessage.editText?.text.toString().trim() if (messageText.isNotEmpty()) { val conversationId1 = "conversation_${currentUser.id}_${userDetails.id}" val conversationId2 = "conversation_${userDetails.id}_${currentUser.id}" reference.child(conversationId1).get().addOnCompleteListener { task -> if (task.isSuccessful) { val data = task.result?.value val conversationId = if (data != null) { conversationId1 } else { conversationId2 } val messageReference = reference.child(conversationId).child("messages").push() val message = Message( content = messageText, date = SimpleDateFormat( "yyyy-MM-dd HH:mm:ss", Locale.getDefault() ).format(Date()), id = messageReference.key!!, isRead = false, name = currentUser?.name ?: "", senderEmail = currentUser.id.toString(), type = "text" ) messageReference.setValue(message) binding.tiMessage.editText?.setText("") scrollToBottom() } } addUser(currentUser.id.toString()) } } } 最后我建议您阅读 MVVM 设计模式以获取更多代码结构。