recyclerView实现gallery效果

作者: 有点健忘 | 来源:发表于2018-10-26 10:30 被阅读21次

    先看效果图再上代码,在解释代码


    20181026_101704.gif

    分析

    decorationNormal:图中的间隔,这个是控件宽度的百分比,比如decorationNormal=1f/15,
    centerViewLeft:中心view的lfet距离屏幕左侧的距离,等于2倍的decorationNormal的距离,
    我们通过设置addItemDecoration给第一个item添加左边的间隔,以及给最后一个item添加右边的间隔,其他view之间是没有间隔,你能看到间隔,是因为除了中心的item,其他的都被缩小了。
    moveX:就是一个item从一个位置移动到另一个位置的距离,其实也就是item的宽度了。我们是按照未缩放来计算的。
    图上红色是原始大小,紫色的是缩小的,可以看到缩小的比例smaller就是decorationNormal除以item的宽度的一半。

    image.png

    整体流程

    首先就是继承一个LinearLayoutManager,先啥也不写,完事给recyclerview,设置这个manager,在添加一个itemDecoration,完事所有item的宽度设置为recyclerView宽度减去4倍的decorationNormal的距离。第一个完工。

    然后开始写manager,重写scrollHorizontallyBy方法,在滑动的时候动态修改item的缩放比例即可
    简单分析下。
    中心view往屏幕左边滑动,scale从1开始变化到1-smaller。也就是移动距离从0到item宽,scale大小缩小了smaller
    右边view往中心滑动,scale从1-smaller变化到1,移动距离从item宽到0,scale增加了smaller,最终为1.
    代码

    var decorationNormal=1f/15
            rv_gallary.apply {
                layoutManager=GallaryLayoutManager(this@ActivityGallary,LinearLayoutManager.HORIZONTAL,false)
                addItemDecoration(object :RecyclerView.ItemDecoration(){
                    override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
                            val position=parent.getChildAdapterPosition(view)
                            val layoutManager=parent.layoutManager as LinearLayoutManager
                            val count=layoutManager.itemCount
                            val interval=(parent.width*decorationNormal).toInt()
                          outRect.apply {
                            when(position){
                                0->{
                                  left=interval*2
                                }
                                count-1->{
                                    right=interval*2
                                }
                            }
                        }
    
                    }
                })
    
                adapter=object :BaseRvAdapter<Int>(datas){
                    override fun getLayoutID(viewType: Int): Int {
                        return R.layout.item_gallary_pic
                    }
    
                    override fun onBindViewHolder(holder: BaseRvHolder, position: Int) {
                        holder.setImageRes(R.id.iv_pic,getItemData(position))
                        holder.itemView.layoutParams.width= (rv_gallary.width*(1-4*decorationNormal)).toInt()
                    }
                }
                LinearSnapHelper().attachToRecyclerView(this)
            }
    

    需要处理的地方

    这里是水平滑动的代码,如果是垂直滚动的,那么修改为设置item的高度
    decoration设置top和bottom

    //设置item的宽度
    holder.itemView.layoutParams.width= (rv_gallary.width*(1-4*decorationNormal)).toInt()
    //给第一个和最后一个item分别添加left和right间隔
    addItemDecoration
    

    一次可以滚动多个item用LinearSnapHelper().attachToRecyclerView(this)
    如果一次只想滚动一个item用PagerSnapHelper().attachToRecyclerView(this)

    自定义的manager

    import android.content.Context
    import android.support.v7.widget.LinearLayoutManager
    import android.support.v7.widget.RecyclerView
    import android.view.View
    
    class GallaryLayoutManager:LinearLayoutManager{
    
        constructor(context: Context?) : super(context)
        constructor(context: Context?, orientation: Int, reverseLayout: Boolean) : super(context, orientation, reverseLayout)
        private var smaller=0f//最大缩小比例,原始都是1,也就是最多缩小为原来view的0.8,这个可以自己改
         //水平滚动的时候这里会执行
        override fun scrollHorizontallyBy(dx: Int, recycler: RecyclerView.Recycler, state: RecyclerView.State?): Int {
            handleHorizontalView()
            return super.scrollHorizontallyBy(dx, recycler, state)
        }
        private fun handleView(){
            when(orientation){
                LinearLayoutManager.HORIZONTAL->{
                    handleHorizontalView()
                }
                LinearLayoutManager.VERTICAL->{
                    handleVerticalView()
                }
            }
        }
    
        var decorationNormal=1f/15//这里和java代码里的值一样
        //垂直滚动的时候会走这里
        override fun scrollVerticallyBy(dy: Int, recycler: RecyclerView.Recycler?, state: RecyclerView.State?): Int {
            handleVerticalView()
            return super.scrollVerticallyBy(dy, recycler, state)
        }
        private fun handleHorizontalView(){
            val centerViewLeft=width*2*decorationNormal;//view居中显示的时候left位置
            val moveX=width*(1-4*decorationNormal)//从一个位置移动到另一个位置item移动的距离
            calculateScale(centerViewLeft,moveX)
        }
        private fun handleVerticalView(){
            val centerViewTop=height*2*decorationNormal;//view居中显示的时候top位置
            val moveY=height*(1-4*decorationNormal)//从一个位置移动到另一个位置item移动的距离
            calculateScale(centerViewTop,moveY)
        }
        /**@param centerViewLeft 水平滑动的时候是left位置,垂直滑动是top位置
         * @param moveDistance 水平滑动是x轴移动距离,垂直滑动是y轴移动距离*/
        private fun calculateScale(centerViewLeft:Float,moveDistance:Float){
            repeat(childCount){
                getChildAt(it)?.apply {
                    var left=this.left
                    when(orientation){
                        LinearLayoutManager.VERTICAL->{
                            left=this.top
                        }
                    }
                    var factor= (left-centerViewLeft)/moveDistance
                    factor=Math.max(-1f,factor)
                    factor=Math.min(1f,factor)
                    if(factor>0){//屏幕右边的view往中心滑动
                        scale(this,1f-factor*smaller)
                    }else{//屏幕中间的view往左边滑动
                        scale(this,1f+factor*smaller)
                    }
                }
            }
        }
        fun scale(view:View,scale:Float){
            view.apply {
                pivotX=this.width/2f
                pivotY=this.height/2f
                scaleX=scale
                scaleY=scale
            }
        }
    
        override fun onLayoutCompleted(state: RecyclerView.State?) {
            super.onLayoutCompleted(state)
            if(smaller==0f){
                smaller=2*decorationNormal/(1-4*decorationNormal)
            }
            handleView()//因为布局首次加载完不滑动是不会执行scroll方法的,所以这里得修改view的scale
        }
    }
    

    相关文章

      网友评论

        本文标题:recyclerView实现gallery效果

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