Android 下拉菜單實現 佈局隨便定義


上圖效果,代碼如下:

主類:

class ContactsFilterPop(private val context: Activity, val mParent: View) {
    private lateinit var mCommonPopupWindow: CommonPopupWindow

    private lateinit var rv_contacts_filter: RecyclerView

    private var mBlock: (contentSelected: String) -> Unit = {}
    private var mContactsFilterAdapter: ContactsFilterAdapter? = null
    private var mList: MutableList<ContactsFilterBean> = mutableListOf()

    init {
        init()
        setListener()
    }

    private fun setListener() {


    }

    private fun init() {
        val view = LayoutInflater.from(context).inflate(R.layout.contacts_pop_filter, null)

        mList.clear()
        mList = getItemsName()
        rv_contacts_filter = view.findViewById(R.id.rv_contacts_filter)

        if (mContactsFilterAdapter == null) {
            mContactsFilterAdapter = ContactsFilterAdapter(R.layout.item_contacts_filter_pop, mList)
            rv_contacts_filter.adapter = mContactsFilterAdapter
            rv_contacts_filter.layoutManager =
                LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)

        } else {
            mContactsFilterAdapter?.notifyDataSetChanged()
        }

        mContactsFilterAdapter?.setOnItemClickListener { adapter, view, position ->
            mList?.forEach {
                it.isSelected = false
            }
            mList[position].isSelected = true
            mCommonPopupWindow.dismiss()
            mContactsFilterAdapter?.notifyDataSetChanged()

            mBlock.invoke(mList[position].itemContent)
        }


        mCommonPopupWindow = CommonPopupWindow.Builder(context)
            .setView(view)
            .setWidthAndHeight(ListPopupWindow.WRAP_CONTENT, ListPopupWindow.WRAP_CONTENT)
            .setAnimationStyle(R.style.popwin_anim_style_top)
            .setOutsideTouchable(true)
            .create()
        //動態設置popWindow的寬度
        mCommonPopupWindow.width = App.SCREEN_WIDTH / 2
    }

    /**
     * 設置彈窗內容
     *
     * @return
     */
    private fun getItemsName(): ArrayList<ContactsFilterBean> {
        val items = ArrayList<ContactsFilterBean>()

        var contactsFilterItem1 = ContactsFilterBean()
        //剛進來默認第一項選中
        contactsFilterItem1.isSelected = true
        contactsFilterItem1.itemContent = "A~Z"
        items.add(contactsFilterItem1)

        var contactsFilterItem2 = ContactsFilterBean()
        contactsFilterItem2.isSelected = false
        contactsFilterItem2.itemContent = "Recently Added"
        items.add(contactsFilterItem2)

        var contactsFilterItem3 = ContactsFilterBean()
        contactsFilterItem3.isSelected = false
        contactsFilterItem3.itemContent = "Star Rating"
        items.add(contactsFilterItem3)

        var contactsFilterItem4 = ContactsFilterBean()
        contactsFilterItem4.isSelected = false
        contactsFilterItem4.itemContent = "Recent Used"
        items.add(contactsFilterItem4)

        return items
    }


    fun show(block: (contentSelected: String) -> Unit = {}) {
        mBlock = block
        context.setWindowDark()
      //動態設置popWindow距離頂部的距離
        var mShowPop = mParent?.bottom / 3 * 4
        mCommonPopupWindow.showAtLocation(mParent, Gravity.TOP, 0, mShowPop)
    }


}

繼承基類

class CommonPopupWindow private constructor(context: Context) : PopupWindow() {
    internal val controller: PopupController = PopupController(context, this)
    private var mIsDismissDark = false

    override fun getWidth(): Int {
        return controller.mPopupView!!.measuredWidth
    }

    override fun getHeight(): Int {
        return controller.mPopupView!!.measuredHeight
    }

    interface ViewInterface {
        fun getChildView(view: View?, layoutResId: Int)
    }

    override fun dismiss() {
        super.dismiss()
        if (!mIsDismissDark) {
            controller.setBackGroundLevel(1.0f)
        }
    }

    fun cancel() {
        super.dismiss()
    }

    /**
     * 設置取消pop是否暗屏
     * @param isDismissDark true dismiss暗屏  false 亮屏
     */
    fun setIsDismissDark(isDismissDark: Boolean = false) {
        mIsDismissDark = isDismissDark
    }

    /**
     * 展示在anchor左正下方
     * @param anchor
     */
    override fun showAsDropDown(anchor: View) {
        if (Build.VERSION.SDK_INT < 24) {
            super.showAsDropDown(anchor)
        } else {
            val location = IntArray(2)
            anchor.getLocationOnScreen(location)
            showAtLocation(anchor, Gravity.NO_GRAVITY, 0, location[1] + anchor.height)
        }
    }

    /**
     * 展示在anchor左正上方
     * @param anchor
     */
    fun showAsAbove(anchor: View) {
        val location = IntArray(2)
        anchor.getLocationOnScreen(location)
        showAtLocation(anchor, Gravity.NO_GRAVITY, location[0], location[1] - height)
    }

    class Builder(context: Context) {
        private val params: PopupController.PopupParams = PopupController.PopupParams(context)
        private var listener: ViewInterface? = null

        /**
         * @param layoutResId 設置PopupWindow 佈局ID
         * @return Builder
         */
        fun setView(layoutResId: Int): Builder {
            params.mView = null
            params.layoutResId = layoutResId
            return this
        }

        /**
         * @param view 設置PopupWindow佈局
         * @return Builder
         */
        fun setView(view: View): Builder {
            params.mView = view
            params.layoutResId = 0
            return this
        }

        /**
         * 設置子View
         *
         * @param listener ViewInterface
         * @return Builder
         */
        fun setViewOnclickListener(listener: ViewInterface): Builder {
            this.listener = listener
            return this
        }

        /**
         * 設置寬度和高度 如果不設置 默認是wrap_content
         *
         * @param width 寬
         * @return Builder
         */
        fun setWidthAndHeight(width: Int, height: Int): Builder {
            params.mWidth = width
            params.mHeight = height
            return this
        }

        /**
         * 設置背景灰色程度
         *
         * @param level 0.0f-1.0f
         * @return Builder
         */
        fun setBackGroundLevel(level: Float): Builder {
            params.isShowBg = true
            params.bg_level = level
            return this
        }

        /**
         * 是否可點擊Outside消失
         *
         * @param touchable 是否可點擊
         * @return Builder
         */
        fun setOutsideTouchable(touchable: Boolean): Builder {
            params.isTouchable = touchable
            return this
        }

        /**
         *
         * @param touchable 是否可點擊
         * @return Builder
         */
        fun setIsFocusable(isFocusable: Boolean): Builder {
            params.isFocusable = isFocusable
            return this
        }

        /**
         * 設置動畫
         *
         * @return Builder
         */
        fun setAnimationStyle(animationStyle: Int): Builder {
            params.isShowAnim = true
            params.animationStyle = animationStyle
            return this
        }

        fun setInputMethondMode(inputMethodMode: Int): Builder {
            params.inoutMethodMode = inputMethodMode
            return this
        }

        fun create(): CommonPopupWindow {
            val popupWindow = CommonPopupWindow(params.mContext)
            params.apply(popupWindow.controller)
            if (listener != null && params.layoutResId != 0) {
                listener!!.getChildView(popupWindow.controller.mPopupView, params.layoutResId)
            }
            measureWidthAndHeight(popupWindow.controller.mPopupView!!)
            return popupWindow
        }

        /**
         * 測量View的寬高
         *
         * @param view View
         */
        private fun measureWidthAndHeight(view: View) {
            val widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
            val heightMeasureSpec =
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
            view.measure(widthMeasureSpec, heightMeasureSpec)
        }
    }
}

佈局:contacts_pop_filter

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:cardBackgroundColor="@color/contacts_filter_item_line"
    app:cardCornerRadius="@dimen/PX_20">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/white"
        android:orientation="vertical">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv_contacts_filter"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:listitem="@layout/item_contacts_filter_pop"/>

    </LinearLayout>
</androidx.cardview.widget.CardView>

Adapter類ContactsFilterAdapter:

class ContactsFilterAdapter(@LayoutRes layoutResId: Int, data: MutableList<ContactsFilterBean>?) :
    BaseQuickAdapter<ContactsFilterBean, BaseViewHolder>(layoutResId, data) {
    override fun convert(holder: BaseViewHolder, item: ContactsFilterBean) {
        holder?.setText(R.id.tv_show, item.itemContent)
            ?.setVisible(R.id.iv_tick, item.isSelected)

        if (holder.adapterPosition == 3) {
            holder?.getView<View>(R.id.view_contacts_filter_item_line)?.visibility = View.INVISIBLE
        }
    }

}

item-item_contacts_filter_pop

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:background="@color/white"
    android:layout_height="@dimen/PX_100">

    <TextView
        android:id="@+id/tv_show"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:gravity="center_vertical"
        android:layout_marginLeft="@dimen/PX_44"
        android:textSize="14sp"
        android:textColor="@color/black"
        android:textStyle="bold"
        android:text="1234"
        />

    <ImageView
        android:id="@+id/iv_tick"
        android:src="@mipmap/ico_gou"
        android:layout_width="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="16dp"
        android:visibility="invisible"
        android:layout_height="wrap_content" />

    <View
        android:id="@+id/view_contacts_filter_item_line"
        android:layout_width="match_parent"
        android:layout_height="@dimen/PX_1"
        android:background="@color/contacts_filter_item_line"
        android:layout_marginLeft="@dimen/PX_44"
        android:layout_alignParentBottom="true"/>

</RelativeLayout>

javaBean的實現類:

class ContactsFilterBean(

    var itemContent: String = "",
    var isSelected: Boolean = false
)

調用入口:

    // 頂部Contacts篩選
    private val mContactsFilterPop: ContactsFilterPop by lazy {
        ContactsFilterPop(activity!!, tv_title)
    }

回調接口:

tv_title?.setOnClickListener {

            mContactsFilterPop.show {
                when (it) {
                    // A~Z
                    "A~Z" -> {
                        searchContext = ""
                        mType = 0
                        getCurrentActivityUserList()
                    }
                }
            }
        }

R.style.popwin_anim_style_top

    <style name="popwin_anim_style_top">
        <item name="android:windowEnterAnimation">@anim/dialog_top_out</item>
        <item name="android:windowExitAnimation">@anim/dialog_top_in</item>
    </style>

dialog_top_in

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
        android:interpolator="@android:anim/accelerate_interpolator"
        android:fromXScale="1.0"
        android:toXScale="1.0"
        android:fromYScale="1.0"
        android:toYScale="0.0"
        android:pivotX="100%"
        android:pivotY="0%"
        android:fillAfter="false"
        android:duration="300"/>
</set>

dialog_top_out

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
        android:interpolator="@android:anim/accelerate_interpolator"
        android:fromXScale="1.0"
        android:toXScale="1.0"
        android:fromYScale="0.0"
        android:toYScale="1.0"
        android:pivotX="100%"
        android:pivotY="0%"
        android:fillAfter="false"
        android:duration="300"/>
</set>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章