From 7459af2f0a6da9292e1a97159d7ef11d3f857b9a Mon Sep 17 00:00:00 2001 From: renhaoting <370797079@qq.com> Date: Thu, 23 Oct 2025 16:16:07 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BC=B9=E5=87=BAmenu=E5=88=9D=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../remax/visualnovel/ui/Chat/InputPanel.kt | 21 ++- .../visualnovel/ui/Chat/PopMenuIconView.kt | 143 ++++++++++++++++++ .../com/remax/visualnovel/utils/PopupUtils.kt | 60 ++++++++ .../main/res/layout/activity_actor_chat.xml | 8 + .../src/main/res/layout/chat_inputpanel.xml | 14 +- .../res/layout/layout_pop_icon_menu_view.xml | 29 ++++ 6 files changed, 270 insertions(+), 5 deletions(-) create mode 100644 VisualNovel/app/src/main/java/com/remax/visualnovel/ui/Chat/PopMenuIconView.kt create mode 100644 VisualNovel/app/src/main/java/com/remax/visualnovel/utils/PopupUtils.kt create mode 100644 VisualNovel/app/src/main/res/layout/layout_pop_icon_menu_view.xml diff --git a/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/Chat/InputPanel.kt b/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/Chat/InputPanel.kt index 3205eac..b664dc6 100644 --- a/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/Chat/InputPanel.kt +++ b/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/Chat/InputPanel.kt @@ -3,7 +3,9 @@ package com.remax.visualnovel.ui.Chat import android.content.Context import android.util.AttributeSet import android.widget.FrameLayout +import android.widget.Toast import com.dylanc.viewbinding.nonreflection.inflate +import com.remax.visualnovel.R import com.remax.visualnovel.databinding.ChatInputpanelBinding @@ -16,7 +18,24 @@ class InputPanel @JvmOverloads constructor(context: Context, attrs: AttributeSet init { binding = inflate(ChatInputpanelBinding::inflate) binding?.run { - + chatPopMenu.setMenuList(mutableListOf( + PopMenuIconView.MenuItem(R.mipmap.ic_launcher) { + Toast.makeText(context, "首页", Toast.LENGTH_SHORT).show() + }, + PopMenuIconView.MenuItem(R.mipmap.ic_launcher) { + Toast.makeText(context, "设置", Toast.LENGTH_SHORT).show() + }, + PopMenuIconView.MenuItem(R.mipmap.ic_launcher) { + Toast.makeText(context, "分享", Toast.LENGTH_SHORT).show() + }, + PopMenuIconView.MenuItem(R.mipmap.ic_launcher) { + Toast.makeText(context, "收藏", Toast.LENGTH_SHORT).show() + } + )) } } + + + + } \ No newline at end of file diff --git a/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/Chat/PopMenuIconView.kt b/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/Chat/PopMenuIconView.kt new file mode 100644 index 0000000..ccc7a84 --- /dev/null +++ b/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/Chat/PopMenuIconView.kt @@ -0,0 +1,143 @@ +package com.remax.visualnovel.ui.Chat + + +import android.animation.AnimatorSet +import android.animation.ValueAnimator +import android.content.Context +import android.util.AttributeSet +import com.dylanc.viewbinding.nonreflection.inflate +import android.view.View +import android.view.animation.DecelerateInterpolator +import android.view.animation.OvershootInterpolator +import android.widget.FrameLayout +import android.widget.ImageView +import android.widget.LinearLayout +import com.remax.visualnovel.R +import com.remax.visualnovel.databinding.LayoutPopIconMenuViewBinding +import com.remax.visualnovel.utils.spannablex.utils.dp + + +class PopMenuIconView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr) { + + data class MenuItem( + val iconResId: Int, + val onClick: (View) -> Unit + ) + + private val mMenuItemList = mutableListOf() + private var isMenuShowing = true + private var itemSpacing = 0 + private var itemSize = 0 + + + + private var mBinding: LayoutPopIconMenuViewBinding? = null + init { + itemSize = 30.dp + itemSpacing = 20.dp + mBinding = inflate(LayoutPopIconMenuViewBinding::inflate) + mBinding?.run { + ivTrigger.setImageResource(R.mipmap.chat_up) + ivTrigger.setOnClickListener { toggleMenu() } + } + } + + + fun setMenuList(menuList : List) { + mMenuItemList.clear() + mMenuItemList.addAll(menuList) + updateMenuItems() + } + + + private fun updateMenuItems() { + mBinding!!.llMenuContainer.removeAllViews() + + mMenuItemList.forEachIndexed { index, menuItem -> + ImageView(context).apply { + setImageResource(menuItem.iconResId) + + layoutParams = LinearLayout.LayoutParams(itemSize, itemSize).apply { + if (index < mMenuItemList.size - 1) { + bottomMargin = itemSpacing + } + } + + setOnClickListener { + menuItem.onClick(this) + dismissMenu() + } + + mBinding!!.llMenuContainer.addView(this) + } + } + } + + fun toggleMenu() { + if (isMenuShowing) dismissMenu() else showMenu() + } + + private fun showMenu() { + if (isMenuShowing) return + isMenuShowing = true + + mBinding?.run { + llMenuContainer.visibility = VISIBLE + ivTrigger.setImageResource(R.mipmap.chat_down) + + val maxWidthSpec = MeasureSpec.makeMeasureSpec(Int.MAX_VALUE/2, MeasureSpec.AT_MOST) + val heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED) + llMenuContainer.measure(maxWidthSpec, heightSpec) + val measureHeight = llMenuContainer.measuredHeight + + val valueYAnim = ValueAnimator.ofInt(0, measureHeight).apply { + addUpdateListener { + val layoutParam = llMenuContainer.layoutParams + layoutParam.height = it.animatedValue as Int + llMenuContainer.layoutParams = layoutParam + } + } + + AnimatorSet().apply { + duration = 300 + interpolator = OvershootInterpolator(2f) + playTogether(valueYAnim) + start() + } + } + } + + + private fun dismissMenu() { + if (!isMenuShowing) return + isMenuShowing = false + mBinding!!.ivTrigger.setImageResource(R.mipmap.chat_up) + + mBinding?.run { + val valueYAnim = ValueAnimator.ofInt(llMenuContainer.measuredHeight, 0).apply { + addUpdateListener { + var layoutParam = llMenuContainer.layoutParams + layoutParam.height = it.animatedValue as Int + llMenuContainer.layoutParams = layoutParam + } + start() + } + + AnimatorSet().apply { + duration = 300 + interpolator = DecelerateInterpolator() + playTogether(valueYAnim) + start() + } + } + } + + + + + +} \ No newline at end of file diff --git a/VisualNovel/app/src/main/java/com/remax/visualnovel/utils/PopupUtils.kt b/VisualNovel/app/src/main/java/com/remax/visualnovel/utils/PopupUtils.kt new file mode 100644 index 0000000..04fa37b --- /dev/null +++ b/VisualNovel/app/src/main/java/com/remax/visualnovel/utils/PopupUtils.kt @@ -0,0 +1,60 @@ +package com.remax.visualnovel.utils + +import android.content.Context +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.PopupWindow +import androidx.core.widget.PopupWindowCompat + + +object PopupUtils { + fun showPopup(context: Context, anchorView: View, layoutRes: Int) { + val contentView = LayoutInflater.from(context).inflate(layoutRes, null) + val popupWindow = PopupWindow( + contentView, + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ).apply { + isFocusable = true + isOutsideTouchable = true + elevation = 10f + } + + PopupWindowCompat.setOverlapAnchor(popupWindow, true) + PopupWindowCompat.showAsDropDown(popupWindow, anchorView, 0, 0, Gravity.START) + } + + fun createPopup(context: Context, layoutRes: Int) : PopupWindow { + val contentView = LayoutInflater.from(context).inflate(layoutRes, null) + val popupWindow = PopupWindow( + contentView, + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ).apply { + isFocusable = true + isOutsideTouchable = true + elevation = 10f + } + + PopupWindowCompat.setOverlapAnchor(popupWindow, true) + return popupWindow + } + + fun createPopup(context: Context, contentView: View) : PopupWindow { + val popupWindow = PopupWindow( + contentView, + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ).apply { + isFocusable = true + isOutsideTouchable = true + elevation = 10f + } + + PopupWindowCompat.setOverlapAnchor(popupWindow, true) + return popupWindow + } + +} \ No newline at end of file diff --git a/VisualNovel/app/src/main/res/layout/activity_actor_chat.xml b/VisualNovel/app/src/main/res/layout/activity_actor_chat.xml index 1273414..3766bfc 100644 --- a/VisualNovel/app/src/main/res/layout/activity_actor_chat.xml +++ b/VisualNovel/app/src/main/res/layout/activity_actor_chat.xml @@ -6,6 +6,14 @@ android:layout_height="match_parent" android:background="@mipmap/bg_level_1_page" android:orientation="vertical"> + + - + />--> + + + + + + + \ No newline at end of file