How to show a customized Popup window near the touch location, like what we have when we use ContextMenu?

前端 未结 2 1988
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-21 17:21

Background

Seeing 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 o

2条回答
  •  醉酒成梦
    2020-12-21 18:11

    How to set the popup window to appear near the touch location on the screen?

    For this purpose, you need to find exact coordination where the user has touch the view so you need to use setOnTouchListener()

    Try this way

    You this PopupWindowHelper

    PopupWindowHelper

    import android.view.Gravity
    import android.graphics.drawable.BitmapDrawable
    import android.content.Context
    import android.graphics.Rect
    import android.view.LayoutInflater
    import android.view.MotionEvent
    import android.view.View
    import android.widget.LinearLayout
    import android.widget.PopupWindow
    
    class 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()
        }
    
    
    }
    

    MainActivity

    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import androidx.recyclerview.widget.LinearLayoutManager
    import 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)
        }
    }
    

    DataAdapter

    import android.content.Context
    import android.util.Log
    import android.view.LayoutInflater
    import android.view.View
    import android.view.ViewGroup
    import androidx.recyclerview.widget.RecyclerView
    import kotlinx.android.synthetic.main.row_layout.view.*
    import android.view.MotionEvent
    import android.view.View.OnTouchListener
    
    class DataAdapter(context: Context) :
        RecyclerView.Adapter() {
        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

提交回复
热议问题