Android 单击ListAdapter时显示对话框

Android 单击ListAdapter时显示对话框,android,kotlin,android-recyclerview,Android,Kotlin,Android Recyclerview,我有一个包含以下列表适配器的活动,用于显示有关github存储库的一些信息。现在我需要实现,当长按列表项时,显示一个对话框,询问是否应该转到存储库html\u url或所有者html\u url,然后在浏览器中打开 实现这一点的最佳方式是什么?逻辑应该在活动中还是在ListAdapater/ViewHolder中 RepositoryListAdapter 让活动将侦听器传递给适配器以执行此操作 在适配器中,创建侦听器接口: class RepositoryListAdapter(val onI

我有一个包含以下列表适配器的活动,用于显示有关github存储库的一些信息。现在我需要实现,当长按列表项时,显示一个对话框,询问是否应该转到存储库html\u url或所有者html\u url,然后在浏览器中打开

实现这一点的最佳方式是什么?逻辑应该在活动中还是在ListAdapater/ViewHolder中

RepositoryListAdapter


让活动将侦听器传递给适配器以执行此操作

在适配器中,创建侦听器接口:

class RepositoryListAdapter(val onItemLongClickListener: OnItemLongClickListener) : ListAdapter<Repo, RepositoryListAdapter.RepositoryViewHolder>(
    RepositoryDiffCallback()
) {
   
    interface OnItemLongClickListener {
        fun onItemLongClick(item: Repo, position: Int)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
        RepositoryViewHolder(
            LayoutInflater.from(parent.context).inflate(
                R.layout.item_repository,
                parent,
                false
            )
        ).also { vh ->
             vh.itemView.setOnLongClickListener { 
                 val position = vh.adapterPosition
                 if (position != RecyclerView.NO_POSITION) {
                     onItemLongClickListener.onItemLongClick(getItem(position), position)
                 }
                 true
             }
         }

}

让活动将侦听器传递给适配器以执行此操作

在适配器中,创建侦听器接口:

class RepositoryListAdapter(val onItemLongClickListener: OnItemLongClickListener) : ListAdapter<Repo, RepositoryListAdapter.RepositoryViewHolder>(
    RepositoryDiffCallback()
) {
   
    interface OnItemLongClickListener {
        fun onItemLongClick(item: Repo, position: Int)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
        RepositoryViewHolder(
            LayoutInflater.from(parent.context).inflate(
                R.layout.item_repository,
                parent,
                false
            )
        ).also { vh ->
             vh.itemView.setOnLongClickListener { 
                 val position = vh.adapterPosition
                 if (position != RecyclerView.NO_POSITION) {
                     onItemLongClickListener.onItemLongClick(getItem(position), position)
                 }
                 true
             }
         }

}

最好的方法是在适配器中处理长时间单击弹出窗口,并在用户单击以分割/活动之后使用操作

    class RepositoryListAdapter : ListAdapter<Repo, RepositoryListAdapter.RepositoryViewHolder>(
        RepositoryDiffCallback()
    ) {
    
    
        adapter.setPopupListener(object : OnPopupClick {
            override fun goToRepository() {
                //Consume action
            }
    
            override fun goToOwner(){
                //Consume action
            }
        })
    
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
            RepositoryViewHolder(
                LayoutInflater.from(parent.context).inflate(
                    R.layout.item_repository,
                    parent,
                    false
                )
            )
    
        override fun onBindViewHolder(holder: RepositoryViewHolder, position: Int) {
            holder.bind(getItem(position))
        }
    
        //WeakReference to prevent un-wanted gc clean of listener
        private var popupListener: WeakReference<OnPopupClick>? = null
    
        fun setPopupListener(listener: OnPopupClick) {
            popupListener = WeakReference(listener)
        }
    
        interface OnPopupClick {
            fun goToRepository()
            fun goToOwner()
        }
    
        class RepositoryViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
            fun bind(repository: Repo) = with(itemView) {
                repositoryName.text = repository.name
                repositoryDescription.text = repository.description
                ownerLogin.text = repository.owner.login
                Glide.with(context)
                    .load(repository.owner.avatarUrl)
                    .into(imageView)
    
    
                itemView.setOnLongClickListener{
                    onLongClick()
                }
    
                if (repository.forksCount > 0) {
                    itemView.setBackgroundColor(ContextCompat.getColor(context, R.color.light_green))
                } else {
                    itemView.setBackgroundColor(ContextCompat.getColor(context, android.R.color.white))
                }
            }
    
            fun onLongClick(){
    
                //MenuAnchor must be added to your item view
                val popup = PopupMenu(view.context, menuAnchor)
    
                popup.inflate(R.menu.yourMenu)  //Customize for user
    
                popup.setOnMenuItemClickListener(object : PopupMenu.OnMenuItemClickListener {
                    override fun onMenuItemClick(item: MenuItem?): Boolean {
                        when (item?.itemId) {
                            R.id.owner -> {
                                popupListener?.get()?.goToOwner()
                                return true
                            }
                            R.id.repo ->{
                                popupListener?.get()?.goToRepository()
                                return true
                            }
                        }
                        return true
                    }
                })
    
                popup.show()
    
            }
        }
    }
    
    class RepositoryDiffCallback : DiffUtil.ItemCallback<Repo>() {
        override fun areItemsTheSame(oldItem: Repo, newItem: Repo): Boolean {
            return oldItem.id == newItem.id
        }
    
        override fun areContentsTheSame(oldItem: Repo, newItem: Repo): Boolean {
            return oldItem == newItem
        }
    }

最好的方法是在适配器中处理长时间单击弹出窗口,并在用户单击以分割/活动之后使用操作

    class RepositoryListAdapter : ListAdapter<Repo, RepositoryListAdapter.RepositoryViewHolder>(
        RepositoryDiffCallback()
    ) {
    
    
        adapter.setPopupListener(object : OnPopupClick {
            override fun goToRepository() {
                //Consume action
            }
    
            override fun goToOwner(){
                //Consume action
            }
        })
    
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
            RepositoryViewHolder(
                LayoutInflater.from(parent.context).inflate(
                    R.layout.item_repository,
                    parent,
                    false
                )
            )
    
        override fun onBindViewHolder(holder: RepositoryViewHolder, position: Int) {
            holder.bind(getItem(position))
        }
    
        //WeakReference to prevent un-wanted gc clean of listener
        private var popupListener: WeakReference<OnPopupClick>? = null
    
        fun setPopupListener(listener: OnPopupClick) {
            popupListener = WeakReference(listener)
        }
    
        interface OnPopupClick {
            fun goToRepository()
            fun goToOwner()
        }
    
        class RepositoryViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
            fun bind(repository: Repo) = with(itemView) {
                repositoryName.text = repository.name
                repositoryDescription.text = repository.description
                ownerLogin.text = repository.owner.login
                Glide.with(context)
                    .load(repository.owner.avatarUrl)
                    .into(imageView)
    
    
                itemView.setOnLongClickListener{
                    onLongClick()
                }
    
                if (repository.forksCount > 0) {
                    itemView.setBackgroundColor(ContextCompat.getColor(context, R.color.light_green))
                } else {
                    itemView.setBackgroundColor(ContextCompat.getColor(context, android.R.color.white))
                }
            }
    
            fun onLongClick(){
    
                //MenuAnchor must be added to your item view
                val popup = PopupMenu(view.context, menuAnchor)
    
                popup.inflate(R.menu.yourMenu)  //Customize for user
    
                popup.setOnMenuItemClickListener(object : PopupMenu.OnMenuItemClickListener {
                    override fun onMenuItemClick(item: MenuItem?): Boolean {
                        when (item?.itemId) {
                            R.id.owner -> {
                                popupListener?.get()?.goToOwner()
                                return true
                            }
                            R.id.repo ->{
                                popupListener?.get()?.goToRepository()
                                return true
                            }
                        }
                        return true
                    }
                })
    
                popup.show()
    
            }
        }
    }
    
    class RepositoryDiffCallback : DiffUtil.ItemCallback<Repo>() {
        override fun areItemsTheSame(oldItem: Repo, newItem: Repo): Boolean {
            return oldItem.id == newItem.id
        }
    
        override fun areContentsTheSame(oldItem: Repo, newItem: Repo): Boolean {
            return oldItem == newItem
        }
    }

我最后就是这样做的,以防有人觉得有用

RepositoryListAdapter


我最后就是这样做的,以防有人觉得有用

RepositoryListAdapter


避免在onBindViewHolder中设置任何侦听器,因为此方法将被反复调用。请检查我的答案,以获得更优化的方法。对不起,我忘记了。在适配器位置之前。我编辑了,再次检查。如果您觉得有用,请将其标记为已接受。您能将其更改为以下内容吗?这是第二次,所以它没有得到这个职位。另外{viewHolder->viewHolder.itemView.setOnLongClickListener{val position=viewHolder.adapterPosition if position!=RecyclerView.NO_position{interaction?.onItemLongClickgetItemposition}true}正如我上面所说,onBindViewHolder将被反复调用,因此setOnLongClickListener最终将被不必要地多次调用。避免在onBindViewHolder中设置任何侦听器,因为此方法将被反复调用。请检查我的答案,以获得更优化的方法。对不起,我忘记了。在适配器位置之前。我编辑了,再次检查。如果您觉得有用,请将其标记为已接受。您能将其更改为以下内容吗?这是第二次,所以它没有得到这个职位。另外{viewHolder->viewHolder.itemView.setOnLongClickListener{val position=viewHolder.adapterPosition if position!=RecyclerView.NO_position{interaction?.onItemLongClickgetItemposition}true}看看这个,就像我上面说的,onBindViewHolder会被反复调用,所以setOnLongClickListener最终会被不必要地调用很多次。
  adapter.setPopupListener(object : OnPopupClick {
    override fun goToRepository() {
        //Consume action
    }

    override fun goToOwner(){
        //Consume action
    }
})
class RepositoryListAdapter(private val interaction: Interaction? = null) : ListAdapter<Repo, RepositoryListAdapter.RepositoryViewHolder>(
    RepositoryDiffCallback()
) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
        RepositoryViewHolder(
            LayoutInflater.from(parent.context).inflate(
                R.layout.item_repository,
                parent,
                false
            ),
            interaction
        )

    override fun onBindViewHolder(holder: RepositoryViewHolder, position: Int) {
        holder.bind(getItem(position))
    }

    class RepositoryViewHolder(itemView: View, private val interaction: Interaction?)
        : RecyclerView.ViewHolder(itemView){
        fun bind(repository: Repo) = with(itemView) {
            repositoryName.text = repository.name
            repositoryDescription.text = repository.description
            ownerLogin.text = repository.owner.login
            Glide.with(context)
                .load(repository.owner.avatarUrl)
                .into(imageView)
            if (repository.forksCount > 0) {
                itemView.setBackgroundColor(ContextCompat.getColor(context, R.color.light_green))
            } else {
                itemView.setBackgroundColor(ContextCompat.getColor(context, android.R.color.white))
            }
            setOnLongClickListener {
                interaction?.onItemLongClick(repository)
                true
            }
        }
    }

    interface Interaction {
        fun onItemLongClick(item: Repo)
    }
}
class MainActivity : AppCompatActivity(), RepositoryListAdapter.Interaction {
...
    private fun setupListAdapter() {
        repositoryListAdapter = RepositoryListAdapter(this)
     ...
     }

    private fun showDialog(repo: Repo) {
        dialog = AlertDialog.Builder(this)
            .setItems(arrayOf("Repository url", "Owner url")) { _, which ->
                when (which) {
                    0 -> openUrl(repo.htmlUrl)
                    1 -> openUrl(repo.owner.htmlUrl)
                }
            }.show()
    }

    private fun openUrl(url: String?) {
        url?.let {
            startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
        }
    }

    override fun onItemLongClick(item: Repo) {
        showDialog(item)
    }
...
}