美文网首页
教你用kotlin撸一个背景透明度联动的banner

教你用kotlin撸一个背景透明度联动的banner

作者: jhyHenry | 来源:发表于2018-05-26 16:26 被阅读0次

    教你用kotlin撸一个背景透明度联动的banner

    最近因为接到个需求:banner分成前景和背景2层,背景随着前景的横向切换而变换透明度,透明度的变换具体是,消失的上一张慢慢变透明,同时要出现的下一张慢慢变不透明,好了,话不多说,先上图,看下效果:

    image

    看完之后我们来撸代码。

    (一):准备工作

    因为我们这次要用kotlin来写,所以先加好依赖

    image

    由于是demo,所以随便找了个banner库

    image

    准备基本完成,let's go。

    (二):先说下思路,我准备先把背景做出来,布局中分别有3个imageview,分别代表前一张、当前和下一张,然后监听前景的切换而变换背景的透明度

    先做背景

    class LinkageBackground @JvmOverloads constructor(
            context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
    ) : FrameLayout(context, attrs, defStyleAttr) {
    
        private val backgroundCur: ImageView? by bindOptionalView(R.id.backgroundCur)
        private val backgroundPre: ImageView? by bindOptionalView(R.id.backgroundPre)
        private val backgroundNext: ImageView? by bindOptionalView(R.id.backgroundNext)
        private lateinit var bgRes: MutableList<Any>
    
        init {
            initView()
        }
    
        fun initView() {
            View.inflate(context, R.layout.layout_linkage_bg, this)
        }
    
        /**
         * 初始化背景
         */
        fun setBgRes(res: List<Any>) {
            bgRes = res.toMutableList()
            resetImg(0)
        }
    
        /**
         * 向左滑动,不需要操作pre
         */
        fun scroll2Left(offset: Float) {
    //        Log.d("LinkageBanner :", "<<<<<<<<<<$offset")
            backgroundNext?.visibility = View.VISIBLE
            backgroundNext?.alpha = offset
            backgroundCur?.alpha = 1 - offset
        }
    
        /**
         * 向右滑,让next隐藏,对pre和cur操作透明度
         */
        fun scroll2Right(offset: Float) {
    //        Log.d("LinkageBanner :", ">>>>>>>>>>$offset")
            backgroundNext?.visibility = View.GONE
            backgroundNext?.alpha = 0f
            backgroundPre?.visibility = View.VISIBLE
            backgroundPre?.alpha = 1 - offset
            backgroundCur?.alpha = offset
        }
    
        /**
         * 重置所有背景,pre和next隐藏
         */
        fun resetImg(cur: Int) {
            backgroundPre?.visibility = View.GONE
            backgroundNext?.visibility = View.GONE
    
            val pre = if (cur - 1 < 0) bgRes.size - 1 else cur - 1
            backgroundPre?.loadImg(bgRes[pre])
            backgroundPre?.alpha = 0f
    
            backgroundCur?.loadImg(bgRes[cur])
            backgroundCur?.alpha = 1f
    
            val next = if (cur + 1 > bgRes.size - 1) 0 else cur + 1
            backgroundNext?.loadImg(bgRes[next])
            backgroundNext?.alpha = 0f
        }
    
    }
    

    上面的@JvmOverloads注解的作用:在有默认参数值的方法中使用,Kotlin会暴露多个重载方法。其余的在代码中都标注清楚了,应该不难懂

    2.接下来做个容器,用来放背景和前景,在其中监听banner切换

    class LinkageBanner @JvmOverloads constructor(
            context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0)
        : FrameLayout(context, attrs, defStyleAttr) {
    
        private val bgBanner: LinkageBackground? by bindOptionalView(R.id.bgBanner)
        private val srcBanner: Banner? by bindOptionalView(R.id.srcBanner)
    
        private var isScrolling = false
        private var currentPosition = 0
        private var beforeX: Float = 0f//手指刚触摸时的x坐标
        var isScroll2Left = false
        var isScroll2Right = false
    
        init {
            initView()
        }
    
        fun initView() {
            View.inflate(context, R.layout.layout_linkage_banner, this)
        }
    
        fun setRes(bgRes: List<Any>, srcRes: List<Any>) {
            bgBanner?.setBgRes(bgRes)
            srcBanner?.setImageLoader(BannerImgLoader())
            srcBanner?.setImages(srcRes)
            srcBanner?.start()
            setListener()
        }
    
        fun getBanner(): Banner {
            return srcBanner!!
        }
    
        override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
            when (ev?.action) {
                MotionEvent.ACTION_DOWN ->
                    //获取起始坐标值
                    beforeX = ev.x
                MotionEvent.ACTION_MOVE ->
                    if (ev.x < beforeX) { // 向左侧滑动
                        isScroll2Left = true
                        isScroll2Right = false
                    } else if (ev.x > beforeX) {// 向右侧滑动
                        isScroll2Right = true
                        isScroll2Left = false
                    }
                else -> {
                }
            }
            return super.dispatchTouchEvent(ev)
        }
    
        private fun setListener() {
            srcBanner?.setOnPageChangeListener(object : ViewPager.OnPageChangeListener {
                override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
                    if (isScrolling) {
                        //根据滑动方向改变背景透明度
                        if (isScroll2Left && positionOffset > 0) {
                            bgBanner?.scroll2Left(positionOffset)
                        } else if (isScroll2Right && positionOffset > 0) {
                            bgBanner?.scroll2Right(positionOffset)
                        }
                    }
                }
    
                override fun onPageSelected(position: Int) {
                    currentPosition = position
                    bgBanner?.resetImg(currentPosition)
                }
    
                override fun onPageScrollStateChanged(state: Int) {
                    isScrolling = state == 1
                }
            })
        }
    
        class BannerImgLoader : ImageLoader() {
            /**
             * 注意:
             * 1.图片加载器由自己选择,这里不限制,只是提供几种使用方法
             * 2.返回的图片路径为Object类型,由于不能确定到底使用的那种图片加载器,
             * 传输的到的是什么格式,那么这种就使用Object接收和返回,只需要强转成你传输的类型就行,
             */
            override fun displayImage(context: Context, path: Any, imageView: ImageView) {
                imageView.loadImg(path)
            }
        }
    }
    

    在实践过程中,发现viewpager的setOnPageChangeListener监听对于滑动方向的判断有些不太准确,所以我自己拦截了touch事件,对滑动方向做了判断。

    3.最后就是在你代码中使用了,很简单,只需要初始化你背景和前景的图片资源就好:

    class MainActivity : AppCompatActivity() {
        private val linkageBanner: LinkageBanner? by bindOptionalView(R.id.linkageBanner)
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            //初始化
            val bgRes = listOf(R.drawable.bg1, R.drawable.bg2, R.drawable.bg3)
            val srcRes = listOf(R.drawable.src1, R.drawable.src2, R.drawable.src3)
            linkageBanner?.setRes(bgRes, srcRes)
        }
    
        override fun onStart() {
            super.onStart()
            linkageBanner?.getBanner()?.startAutoPlay()
        }
    
        override fun onStop() {
            super.onStop()
            linkageBanner?.getBanner()?.stopAutoPlay()
        }
    }
    

    怎么样,是不是灰常简单?赶紧试试吧。

    代码地址在这:传送门

    原创,转载请标明来源,3Q。

    相关文章

      网友评论

          本文标题:教你用kotlin撸一个背景透明度联动的banner

          本文链接:https://www.haomeiwen.com/subject/fvvmjftx.html