Android 上拉菜单

Android 上拉菜单

Dialog 会置于顶层,项目需求是这样的:


image

要求点击购物车,弹出后面的视图,弹出的视图要置于 购物车按钮 下方
Dialog会将购物车盖住。
所以自己写了个自定义View实现该功能。

image
image

使用时实现 BottomPopupConstraintLayout.BottomConstraintLayoutAdap 接口:

class BottomAdapter(val context:Context):BottomPopupConstraintLayout.BottomConstraintLayoutAdapter{
    override fun getMaxHeight(): Int {
        val dp2px = DisplayUtil.dp2px(context, 462f)
        return dp2px
    }

    override fun getDuration(): Long {
        return 300
    }
}

必须实现的方法:
getMaxHeight() 从来设置 弹出的高度

剩下还有一些可选的方法,查看BottomPopupConstraintLayout.BottomConstraintLayoutAdapter 即可

布局文件非常简单:




    

    


    

下面是具体代码:

package zyf.com.selectdemo
import android.animation.Animator
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Color
import android.support.constraint.ConstraintLayout
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup

/**
 * create by zyf on 2019/1/8 7:23 PM
 */
class BottomPopupConstraintLayout : ConstraintLayout {

    private val mShadowView: View = View(context)
    private var mIsShow = false
    private var mIsSliding = false

    private var mAlphaMin = 80

    private var slideTop: ValueAnimator? = null

    private var slideBottom: ValueAnimator? = null

    private lateinit var mAdapter: BottomConstraintLayoutAdapter


    constructor(context: Context) : this(context, null) {
    }


    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) {

    }

    constructor(context: Context, attrs: AttributeSet?, defstyleAttr: Int) : super(context, attrs, defstyleAttr) {
        mInit(context)
    }


    private fun mInit(context: Context) {


    }


    private fun mDeployAnimator() {

        slideTop = ValueAnimator.ofInt(mAdapter.getMinHeight(), mAdapter.getMaxHeight()).apply {
            addUpdateListener {
                val value = it.animatedValue as Int

                layoutParams.height = value
                requestLayout()

                if (mAdapter.showShadow()) {
                    mShadowView.setBackgroundColor(Color.argb(mAlphaMin * value / mAdapter.getMaxHeight(), 0, 0, 0))
                }
            }

            addListener(object : Animator.AnimatorListener {
                override fun onAnimationRepeat(animation: Animator?) {

                }

                override fun onAnimationCancel(animation: Animator?) {
                }

                override fun onAnimationStart(animation: Animator?) {
                    changeSlideStatus()
                    mShadowView.visibility = View.VISIBLE
                    visibility = View.VISIBLE

                }

                override fun onAnimationEnd(animation: Animator?) {
                    changeSlideStatus()
                    mAdapter.getShowCompleted().invoke()
                }

            })

            duration = mAdapter.getDuration()


        }
        slideBottom = ValueAnimator.ofInt(mAdapter.getMaxHeight(), mAdapter.getMinHeight()).apply {
            addUpdateListener {
                val value = it.animatedValue as Int
                layoutParams.height = value
                if(value == mAdapter.getMinHeight()){
                    visibility = View.GONE
                }
                requestLayout()
                if (mAdapter.showShadow()) {

                    if (value == mAdapter.getMinHeight()) {
                        mShadowView.setBackgroundColor(Color.argb(0, 0, 0, 0))

                    } else {
                        mShadowView.setBackgroundColor(Color.argb(mAlphaMin * value / maxHeight, 0, 0, 0))
                    }

                }
            }

            addListener(object : Animator.AnimatorListener {
                override fun onAnimationRepeat(animation: Animator?) {

                }

                override fun onAnimationCancel(animation: Animator?) {
                }

                override fun onAnimationStart(animation: Animator?) {
                    changeSlideStatus()
                }

                override fun onAnimationEnd(animation: Animator?) {
                    mShadowView.visibility = View.GONE
                    changeSlideStatus()
                    mAdapter.getHideCompleted().invoke()

                }

            })

            duration = mAdapter.getDuration()

        }
    }


    private fun mDeployShadow() {
        if (mAdapter.showShadow()) {
            mShadowView.apply {
                layoutParams =
                        ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
            }

            val viewGroup = parent as ViewGroup
            viewGroup.addView(mShadowView, 0)
            mShadowView.setOnClickListener {
                if (mAdapter.clickOutSideClose()) {
                    hide()
                }
            }
        }
    }

    private fun mDeployDefaultListener() {
        setOnClickListener { }
    }

    private fun changeSlideStatus() {
        mIsSliding = !mIsSliding
    }

    private fun changeShowStatus() {
        mIsShow = !mIsShow
    }

    fun showOrHide() {
        if (mIsShow) {
            hide()
        } else {
            show()
        }
    }

    fun show() {
        if (!mIsShow && !mIsSliding) {

            slideTop?.start()
            changeShowStatus()
        }
    }

    fun hide() {
        if (mIsShow && !mIsSliding) {

            slideBottom?.start()
            changeShowStatus()
        }
    }

    fun setAdapter(adapter: BottomConstraintLayoutAdapter) {
        mAdapter = adapter

        //配置动画
        mDeployAnimator()

        //配置阴影点击时间
        mDeployShadow()

        //配置点击默认点击时间,否则点击时间会穿过Constraint,使得Shadow响应
        mDeployDefaultListener()
    }


    interface BottomConstraintLayoutAdapter {
        fun getMaxHeight(): Int
        fun getMinHeight(): Int = 1
        fun showShadow(): Boolean = true
        fun clickOutSideClose(): Boolean = true
        fun getDuration(): Long = 500
        fun getHideCompleted() = {}
        fun getShowCompleted() = {}

    }
}

你可能感兴趣的:(Android 上拉菜单)