此标记应用于有关专门针对移动环境但不针对特定移动环境(如iOS或Android)的软件开发的问题。
我正在尝试更改弹出窗口的主题,如果我使用 AppCompat 作为主题,它会发生变化,但我想使用 Material3,遗憾的是它不会随之改变。 我尝试了很多事情,比如创建自定义背景、创建...
在 Spring Boot 应用程序中集成多个 API 的更好方法是什么,API 之间的直接通信还是间接通信?
我们正在使用 Spring Boot 为一家航空公司开发后端系统。我们的项目要求我们集成来自多个 API 的数据来生成航班名册。这是当前的结构...
我想问一下如何让导航栏变得完全透明,我已经尝试了很多解决方案,但到目前为止我所能得到的只是我的导航栏变成白色并且仍然裁剪了一小部分...
用于移动开发的 Zed 编辑器(React Native 和 Swift)
我是本地反应新手,我想知道是否有人将它用于移动开发?我目前正在使用 Zed IDE,它对于 Web 开发来说绝对是令人难以置信的。然而,移动开发需要一个屏幕......
更新 Firebase Analytics for Flutter 以避免隐私清单政策问题(2024 年 5 月 1 日之后)
我最近收到了有关 Firebase 的通知,建议更新 Google Analytics for Firebase (GA4F) iOS SDK(版本 10.24.0 或更高版本),以避免与隐私人相关的潜在问题...
我有一个非常基本的嵌套 for 循环迭代 80K 长字符串。这个循环最多需要 2-3 毫秒,但在我的 iPhone 上需要 10 秒。对于智能手机来说,这是一个莫名其妙的时代……
希望 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 设计模式以获取更多代码结构。
致命异常:java.lang.UnsupportedOperationException:无法解析索引 5 处的属性:TypedValue{t=0x2/d=0x7f040109 a=23}
我遇到一条错误消息,每当我单击 MaterialDatePicker 时就会触发该消息。我认为它与 ThemeOverlay 有关,但我不知道如何摆脱它。 这是错误消息...
获取 java.lang.IndexOutOfBoundsException:对于我的适配器代码,索引 8 超出长度 8 的范围
我的 logcat 看起来像: logcat 应用程序崩溃 类 ChatAdapter(private val currentUserId: Int) : RecyclerView.Adapter() { 私有 val 消息 = mutableListO...
谁能告诉我美国亚马逊Android App的包名吗?因为不同国家的Amazon app的包名是不一样的
我需要使用亚马逊应用程序的包名称触发一个意图。但我正在构建的功能需要仅针对美国地区的亚马逊应用程序。 我尝试了 VPN 并分享了来自 Google Play 的应用程序链接
我目前正在开发一个 .NET MAUI 应用程序作为新手,我正在尝试实现一个可以计算行驶距离的实时 GPS 跟踪器。我已经成功检索实时坐标...
我收到错误“_RenderInkFeatures 对象在布局期间被赋予无限大小。”在颤振中
我正在尝试在我的代码中实现滑块功能。尽管我预定义了滑块的最大值,但它仍然表示滑块具有无限值 我给出了下面的代码: 错误...
每当我从广播接收器启动透明活动时,如果应用程序在最近的应用程序中已经有一个活动,而不是在当前应用程序上透明,则其透明...
我正在使用VSCode,并且我尝试使用传感器加包,如文档中所示: 我试图找到解决方案,但找不到任何解决方案,如果有人可以帮助我,我会很高兴.. 我正在尝试...
我正在尝试为 Jetpack Compose 中的 ModalBottomSheet 创建 @Preview 函数,但我只看到白屏。这是我的 SomeModalBottomSheet 可组合项: @OptIn(ExperimentalMaterial3Api::c...
react-native-qrcode-scanner 位于空二维码
我正在开发React Native应用程序,有一个QR码扫描仪屏幕,如果我尝试扫描的QR码为空,我想触发警报。带数据的二维码工作正常。 我正在使用版本: “……
将 Arryaylist 作为共享首选项保存到 json 后,在 Fragment 中实现 RecyclerView 时遇到问题
我无法显示片段,但我的活动中没有显示任何内容。我的目标是将sharedpreference保存为gson,因为arraylist无法保存到sharedpreference中然后使用gson...
setState 在 ConsumerStatefulWidget (Riverpod) 中未按预期工作
我有一个自定义的 appbar 类,我将标题作为其构造函数传递。 类 MyAppBar 扩展 StatelessWidget 实现 PreferredSizeWidget { 最终字符串?标题; @覆盖 尺寸更喜欢...
Android Studio Bumblebee AAPT2 进程意外退出
我已经安装了最新版本的android studio,但是当我开始执行我的项目时出现此错误,模拟器无法工作。 我尝试了很多解决方案,但没有一个适合我。
博览会错误:未捕获错误:java.lang.Exception:无法加载所有资源
当我使用 npx expo start -c 服务器启动 expo 服务器时。我的手机和笔记本电脑也连接在同一网络上。现在,当我在手机中通过 expo go 扫描 expo 二维码时,会显示错误