本文介绍了如何像在使用ContextMenu时一样在触摸位置附近显示自定义的Popup窗口?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 限时删除!! 背景 看到正式使用上下文菜单的行自定义视图甚至图标是不可能的( 但是,我找不到如何做到这一点的方法 我尝试过的事情 显示PopupWindow可以通过长时间触摸来完成,因为例如: onCreateViewHolder(parent:ViewGroup,viewType:Int)的替代乐趣:ViewHolder { val inflater = LayoutInflater。 from(context) valholder = ViewHolder(inflater.inflate(R.layout.list_item_main,parent,false))holder.itemView.setOnLongClickListener { val contextMenuView = inflater.inflate(R .layout.context_menu,null) val popupWindow = PopupWindow(contextMenuView,ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT,true) popupWindow.showAsDropDown(holder.itemView,0,0); 真实的} 返回持有者} 而且,如果您想要一个好的背景而不是透明的,可以使用 问题 如何将弹出窗口设置为显示在屏幕上的触摸位置附近,而无需甚至处理onTouch事件,就像使用ContextMenu在示例上所做的一样? 上下文菜单(或类似菜单)是否具有我可以获取的一些属性,可以将其设置为显示的最大大小(简而言之:默认最大宽度)?如果可以,该如何使用?如何设置宽度和高度以考虑膨胀视图之一? 解决方案 为此,您需要在用户触摸视图的位置找到精确的协调,因此需要使用 setOnTouchListener() 尝试这种方式 您这个 PopupWindowHelper PopupWindowHelper import android.view.Gravity 导入android.graphics.drawable.BitmapDrawable 导入android.content.Context 导入android.graphics.Rect 导入android.view.LayoutInflater 导入android.view.MotionEvent 导入android.view.View 导入android.widget.LinearLayout 导入android.widget.PopupWindow class PopupWindowHelper(priv val ctx:Context ){ private val tipWindow:PopupWindow? 私有val内容查看器:查看私有val充气器:LayoutInflater 内部val isTooltipShown:布尔值 get()= tipWindow!= null&& tipWindow.isShowing init { tipWindow = PopupWindow(ctx) inflater = ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE)as LayoutInflater contentView = inflater.inflate(R.layout.popup_window,null)} 内部乐趣showToolTip(anchor:View,event:MotionEvent){ tipWindow !!。height = LinearLayout.LayoutParams.WRAP_CONTENT tipWindow.width = LinearLayout.LayoutParams.WRAP_CONTENT tipWindow.isOutsideTouchable = true tipWindow.isTouchable = true tipWindow .isFocusable = true tipWindow.setBackgroundDrawable(BitmapDrawable()) tipWindow.contentView = contentView val screenPos = IntArray(2)锚点。 getLocationOnScreen(screenPos) val anchorRect = Rect(screenPos [0],screenPos [1],screenPos [0] + anchor.width,screenPos [1] + anchor.height) contentView.measure( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT ) val contentViewHeight = contentView.measuredHeight val contentViewWidth = contentView.measuredWidth val positionX = anchorRect.centerX()-contentViewWidth / 2 val positionY = anchorRect.bottom-anchorRect.height()/ 2 tipWindow.showAtLocation(anchor,Gravity.NO_GRAVITY,event.x.toInt(),positionY) } 内部乐趣dismissTooltip(){ if(tipWindow!= null& tipWindow.isShowing) tipWindow.dismiss()} } 导入androidx.appcompat.app.AppCompatActivity 导入android.os.Bundle 导入androidx.recyclerview.widget.LinearLayoutManager 导入kotlinx.android.synthetic.main.activity_main。* 类MainActivity:AppCompatActivity(){ 重写fun onCreate(savedInstanceState:Bundle?){ super.onCreate(savedInstanceState) setContentView(R.layout.activity_main ) myRecyclerView.layoutManager = LinearLayoutManager(this) myRecyclerView.setHasFixedSize(true) myRecyclerView.adapter = DataAdapter(this)} } 导入android.content.Context 导入android.util.Log 导入andro id.view.LayoutInflater 导入android.view.View 导入android.view.ViewGroup 导入androidx.recyclerview.widget.RecyclerView 导入kotlinx.android.synthetic.main。 row_layout.view。* 导入android.view.MotionEvent 导入android.view.View.OnTouchListener 类DataAdapter(context:Context): RecyclerView.Adapter< ; DataAdapter.ViewHolder>(){ val mContext = context private var lastTouchDown:Long = 0 private val CLICK_ACTION_THRESHHOLD = 200 覆盖onCreateViewHolder(parent: ViewGroup,viewType:Int):ViewHolder { val view = LayoutInflater.from(mContext) .inflate(R.layout.row_layout,parent,false) view.setOnTouchListener {myView,event-> when(event?.action){ MotionEvent.ACTION_DOWN-> lastTouchDown = System.currentTimeMillis() MotionEvent.ACTION_UP->如果(System.currentTimeMillis()-lastTouchDown< CLICK_ACTION_THRESHHOLD){ val popupWindowHelper = PopupWindowHelper(mContext) myView?.let { popupWindowHelper.showToolTip( it ,事件)} } } 真} return ViewHolder(view)} 重写fun getItemCount():Int { return 30 } 重写fun onBindViewHolder(holder:ViewHolder,position:Int){ holder.tvDescription.text =行描述$ position holder.tvTitle.text =行标题$ position } 内部类ViewHolder(itemView:View):RecyclerView.ViewHolder(itemView){ val tvTitle = itemView.tvTitle val tvDescription = itemView.tv的描述} } 您可以在中找到完整的代码href = https://github.com/RathodNilesh14/PopupWindowIn_RecyclerViewItem rel = nofollow noreferrer>我的GitHub存储库 BackgroundSeeing that it's not officially possible to have a context menu which has a customized view or even icons for its rows (here), I decided to create my own solution (of custom view that acts like it).The problemWhen using a context menu on a RecyclerView, the touch position matters, so if you long touch an item, the context menu will try to appear near the touch location (sample taken from here), and without me giving this information (meaning via OnClickListener or onLongClickListener ) :However, I can't find how to do this in the more basic classes.What I've triedShowing a PopupWindow can be done via long touch, as such:override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val inflater = LayoutInflater.from(context) val holder = ViewHolder(inflater.inflate(R.layout.list_item_main, parent, false)) holder.itemView.setOnLongClickListener { val contextMenuView=inflater.inflate(R.layout.context_menu,null) val popupWindow = PopupWindow(contextMenuView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true) popupWindow.showAsDropDown(holder.itemView,0,0); true } return holder}And, if you want to have a nice background for it instead of being transparent, you could use a workaround, of ListPopupWindow, and if you don't want a list, you can just set its promptView , as such (code available here) :override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val inflater = LayoutInflater.from(context) val holder = ViewHolder(inflater.inflate(R.layout.list_item_main, parent, false)) val maxAllowedPopupWidth = context.resources.displayMetrics.widthPixels * 90 / 100 holder.itemView.setOnLongClickListener { val contextMenuView = inflater.inflate(R.layout.context_menu, null) val listPopupWindow = ListPopupWindow(context) contextMenuView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED) val width = min(maxAllowedPopupWidth, contextMenuView.measuredWidth) listPopupWindow.setPromptView(contextMenuView) listPopupWindow.setContentWidth(width) listPopupWindow.anchorView = it listPopupWindow.show() true } return holder}I'm not sure about the max width that I've calculated, because I can't find what's the maximum size that a popup can have. I know that the context menu has some maximum and then it just truncates the text for some reason. Maybe it's the same as of Dialog? Except that for dialog I could find a maximum width, yet I've found a minimal : windowMinWidthMajor and windowMinWidthMinor.But back to the issue: I can't find any function here that's related to putting the popup near the touch location.So this is what I get, for example:The questionsHow to set the popup window to appear near the touch location on the screen, without even handling onTouch event, as done on the sample using ContextMenu ?Does the context menu (or similar) have some attribute that I can get, to set as the max size for what I show (in short: a default max width) ? If so, how do I use it? How can I set the width&height to consider the one of the inflated view? 解决方案 For this purpose, you need to find exact coordination where the user has touch the view so you need to use setOnTouchListener()Try this wayYou this PopupWindowHelperimport android.view.Gravityimport android.graphics.drawable.BitmapDrawableimport android.content.Contextimport android.graphics.Rectimport android.view.LayoutInflaterimport android.view.MotionEventimport android.view.Viewimport android.widget.LinearLayoutimport android.widget.PopupWindowclass PopupWindowHelper(private val ctx: Context) { private val tipWindow: PopupWindow? private val contentView: View private val inflater: LayoutInflater internal val isTooltipShown: Boolean get() = tipWindow != null && tipWindow.isShowing init { tipWindow = PopupWindow(ctx) inflater = ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater contentView = inflater.inflate(R.layout.popup_window, null) } internal fun showToolTip(anchor: View, event: MotionEvent) { tipWindow!!.height = LinearLayout.LayoutParams.WRAP_CONTENT tipWindow.width = LinearLayout.LayoutParams.WRAP_CONTENT tipWindow.isOutsideTouchable = true tipWindow.isTouchable = true tipWindow.isFocusable = true tipWindow.setBackgroundDrawable(BitmapDrawable()) tipWindow.contentView = contentView val screenPos = IntArray(2) anchor.getLocationOnScreen(screenPos) val anchorRect = Rect(screenPos[0], screenPos[1], screenPos[0] + anchor.width, screenPos[1] + anchor.height) contentView.measure( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT ) val contentViewHeight = contentView.measuredHeight val contentViewWidth = contentView.measuredWidth val positionX = anchorRect.centerX() - contentViewWidth / 2 val positionY = anchorRect.bottom - anchorRect.height() / 2 tipWindow.showAtLocation(anchor, Gravity.NO_GRAVITY, event.x.toInt(), positionY) } internal fun dismissTooltip() { if (tipWindow != null && tipWindow.isShowing) tipWindow.dismiss() }}import androidx.appcompat.app.AppCompatActivityimport android.os.Bundleimport androidx.recyclerview.widget.LinearLayoutManagerimport kotlinx.android.synthetic.main.activity_main.*class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) myRecyclerView.layoutManager=LinearLayoutManager(this) myRecyclerView.setHasFixedSize(true) myRecyclerView.adapter=DataAdapter(this) }}import android.content.Contextimport android.util.Logimport android.view.LayoutInflaterimport android.view.Viewimport android.view.ViewGroupimport androidx.recyclerview.widget.RecyclerViewimport kotlinx.android.synthetic.main.row_layout.view.*import android.view.MotionEventimport android.view.View.OnTouchListenerclass DataAdapter(context: Context) : RecyclerView.Adapter<DataAdapter.ViewHolder>() { val mContext = context private var lastTouchDown: Long = 0 private val CLICK_ACTION_THRESHHOLD = 200 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(mContext) .inflate(R.layout.row_layout, parent, false) view.setOnTouchListener { myView, event -> when (event?.action) { MotionEvent.ACTION_DOWN -> lastTouchDown = System.currentTimeMillis() MotionEvent.ACTION_UP -> if (System.currentTimeMillis() - lastTouchDown < CLICK_ACTION_THRESHHOLD) { val popupWindowHelper = PopupWindowHelper(mContext) myView?.let { popupWindowHelper.showToolTip( it , event ) } } } true } return ViewHolder(view) } override fun getItemCount(): Int { return 30 } override fun onBindViewHolder(holder: ViewHolder, position: Int) { holder.tvDescription.text = "Row Description $position" holder.tvTitle.text = "Row Title $position" } inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val tvTitle = itemView.tvTitle val tvDescription = itemView.tvDescription }}You can find complete code from my GitHub repo 这篇关于如何像在使用ContextMenu时一样在触摸位置附近显示自定义的Popup窗口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 1403页,肝出来的.. 09-06 18:44