在ListAdapter的longitemclick上显示对话框

时间:2020-10-23 13:26:28

标签: android kotlin android-recyclerview

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

实现此目标的最佳方法是什么?逻辑应该在活动中还是在ListAdapater / ViewHolder中?

RepositoryListAdapter

class RepositoryListAdapter : ListAdapter<Repo, RepositoryListAdapter.RepositoryViewHolder>(
    RepositoryDiffCallback()
) {
    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))
    }

    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)
            if (repository.forksCount > 0) {
                itemView.setBackgroundColor(ContextCompat.getColor(context, R.color.light_green))
            } else {
                itemView.setBackgroundColor(ContextCompat.getColor(context, android.R.color.white))
            }
        }
    }
}

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
    }
}

3 个答案:

答案 0 :(得分:2)

让Activity将侦听器传递给适配器来完成它。

在适配器中,创建一个侦听器界面:

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 YourActivity : Activity {
    private lateinit var adapter: RepositoryListAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        adapter = RepositoryListAdapter(object : OnItemLongClickListener {
            override fun onItemLongClick(item: Repo, position) {
                // Your logic to show the dialog
            }
        })
        ...    
    }
}

答案 1 :(得分:1)

最好的方法是处理适配器中的长按弹出窗口,并在用户单击片段/活动后消耗操作

    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
        }
    }

之后,将其添加到您的活动/片段中:

  adapter.setPopupListener(object : OnPopupClick {
    override fun goToRepository() {
        //Consume action
    }

    override fun goToOwner(){
        //Consume action
    }
})

答案 2 :(得分:0)

这是我最后做的,以防万一有人觉得有用。

RepositoryListAdapter

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)
    }
...
}