Merge pull request #1255 from KryptKode/fix/popup-anchor

fix: clipped popup on android 9
This commit is contained in:
Tibor Kaputa 2022-01-14 13:12:54 +01:00 committed by GitHub
commit 02b48c0b4d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 70 additions and 30 deletions

View file

@ -15,26 +15,26 @@ import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.extensions.applyColorFilter
import com.simplemobiletools.commons.extensions.windowManager
import com.simplemobiletools.commons.helpers.isRPlus
import kotlinx.android.synthetic.main.item_action_mode_popup.view.*
import kotlinx.android.synthetic.main.item_action_mode_popup.view.cab_item
class BottomActionMenuItemPopup(
private val context: Context,
private val items: List<BottomActionMenuItem>,
private val onSelect: (BottomActionMenuItem) -> Unit
private val onSelect: (BottomActionMenuItem) -> Unit,
) {
private val popup = PopupWindow(context, null, android.R.attr.popupMenuStyle)
private var anchorView: View? = null
private var dropDownWidth = ViewGroup.LayoutParams.WRAP_CONTENT
private var dropDownHeight = ViewGroup.LayoutParams.WRAP_CONTENT
private var dropDownVerticalOffset: Int = 0
private var dropDownHorizontalOffset: Int = 0
private val tempRect = Rect()
private val popupMinWidth: Int
private val popupPaddingBottom: Int
private val popupPaddingStart: Int
private val popupPaddingEnd: Int
private val popupPaddingTop: Int
private val dropDownGravity: Int = Gravity.TOP or Gravity.END
val isShowing: Boolean
get() = popup.isShowing
private val popupListAdapter = object : ArrayAdapter<BottomActionMenuItem>(context, R.layout.item_action_mode_popup, items) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
@ -74,14 +74,28 @@ class BottomActionMenuItemPopup(
buildDropDown()
PopupWindowCompat.setWindowLayoutType(popup, WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL)
popup.isOutsideTouchable = true
if (popup.isShowing) {
val dropDownHeight = if (dropDownHeight < 0) -1 else dropDownHeight
popup.update(anchorView, dropDownHorizontalOffset, dropDownVerticalOffset, dropDownWidth, dropDownHeight)
} else {
popup.width = dropDownWidth
popup.height = dropDownHeight
PopupWindowCompat.showAsDropDown(popup, anchorView, dropDownHorizontalOffset, dropDownVerticalOffset, dropDownGravity)
}
popup.width = dropDownWidth
popup.height = dropDownHeight
var x = 0
var y = 0
val contentView: View = popup.contentView
val windowRect = Rect()
contentView.getWindowVisibleDisplayFrame(windowRect)
val windowW = windowRect.width()
val windowH = windowRect.height()
contentView.measure(
makeDropDownMeasureSpec(dropDownWidth, windowW),
makeDropDownMeasureSpec(dropDownHeight, windowH)
)
val anchorLocation = IntArray(2)
anchorView.getLocationInWindow(anchorLocation)
x += anchorLocation[0]
y += anchorView.height * 2
x -= dropDownWidth - anchorView.width
popup.showAtLocation(contentView, Gravity.BOTTOM, x, y)
}
internal fun dismiss() {
@ -97,9 +111,10 @@ class BottomActionMenuItemPopup(
divider = null
isFocusableInTouchMode = true
clipToPadding = false
isVerticalScrollBarEnabled = false
isVerticalScrollBarEnabled = true
isHorizontalScrollBarEnabled = false
clipToOutline = true
elevation = 3f
setPaddingRelative(popupPaddingStart, popupPaddingTop, popupPaddingEnd, popupPaddingBottom)
}
@ -117,23 +132,15 @@ class BottomActionMenuItemPopup(
// to get the available height for the whole window.
val padding: Int
val popupBackground = popup.background
if (popupBackground != null) {
padding = if (popupBackground != null) {
popupBackground.getPadding(tempRect)
padding = tempRect.top + tempRect.bottom
// If we don't have an explicit vertical offset, determine one from
// the window background so that content will line up.
dropDownVerticalOffset -= tempRect.top
tempRect.top + tempRect.bottom
} else {
tempRect.setEmpty()
padding = 0
0
}
if (dropDownGravity and Gravity.BOTTOM == Gravity.BOTTOM) {
dropDownVerticalOffset += anchorView!!.height
}
val maxHeight = popup.getMaxAvailableHeight(anchorView!!, dropDownVerticalOffset)
val maxHeight = popup.getMaxAvailableHeight(anchorView!!, 0)
val listContent = measureHeightOfChildrenCompat(maxHeight - otherHeights)
if (listContent > 0) {
val listPadding = dropDownList.paddingTop + dropDownList.paddingBottom
@ -246,4 +253,25 @@ class BottomActionMenuItemPopup(
}
return maxWidth
}
private fun makeDropDownMeasureSpec(measureSpec: Int, maxSize: Int): Int {
return MeasureSpec.makeMeasureSpec(
getDropDownMeasureSpecSize(measureSpec, maxSize),
getDropDownMeasureSpecMode(measureSpec)
)
}
private fun getDropDownMeasureSpecSize(measureSpec: Int, maxSize: Int): Int {
return when (measureSpec) {
ViewGroup.LayoutParams.MATCH_PARENT -> maxSize
else -> MeasureSpec.getSize(measureSpec)
}
}
private fun getDropDownMeasureSpecMode(measureSpec: Int): Int {
return when (measureSpec) {
ViewGroup.LayoutParams.WRAP_CONTENT -> MeasureSpec.UNSPECIFIED
else -> MeasureSpec.EXACTLY
}
}
}

View file

@ -14,7 +14,10 @@ import android.widget.LinearLayout
import androidx.annotation.IdRes
import com.google.android.material.animation.AnimationUtils
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.extensions.applyColorFilter
import com.simplemobiletools.commons.extensions.beVisibleIf
import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.extensions.windowManager
import com.simplemobiletools.commons.helpers.isRPlus
class BottomActionMenuView : LinearLayout {
@ -40,6 +43,7 @@ class BottomActionMenuView : LinearLayout {
private var currentAnimator: ViewPropertyAnimator? = null
private var callback: BottomActionMenuCallback? = null
private var itemPopup: BottomActionMenuItemPopup? = null
init {
orientation = HORIZONTAL
@ -151,7 +155,11 @@ class BottomActionMenuView : LinearLayout {
(inflater.inflate(R.layout.item_action_mode, this, false) as ImageView).apply {
setupItem(item)
setOnClickListener {
callback?.onItemClicked(item)
if (itemPopup?.isShowing == true) {
itemPopup?.dismiss()
} else {
callback?.onItemClicked(item)
}
}
setOnLongClickListener {
context.toast(item.title)
@ -167,9 +175,13 @@ class BottomActionMenuView : LinearLayout {
val contentDesc = context.getString(R.string.more_info)
contentDescription = contentDesc
applyColorFilter(Color.WHITE)
val popup = getOverflowPopup(overFlowItems)
itemPopup = getOverflowPopup(overFlowItems)
setOnClickListener {
popup.show(it)
if (itemPopup?.isShowing == true) {
itemPopup?.dismiss()
} else {
itemPopup?.show(it)
}
}
setOnLongClickListener {
context.toast(contentDesc)