先看效果圖再上代碼,在解釋代碼

分析
decorationNormal:圖中的間隔,這個(gè)是控件寬度的百分比,比如decorationNormal=1f/15,
centerViewLeft:中心view的lfet距離屏幕左側(cè)的距離,等于2倍的decorationNormal的距離,
我們通過設(shè)置addItemDecoration給第一個(gè)item添加左邊的間隔,以及給最后一個(gè)item添加右邊的間隔,其他view之間是沒有間隔,你能看到間隔,是因?yàn)槌酥行牡膇tem,其他的都被縮小了。
moveX:就是一個(gè)item從一個(gè)位置移動(dòng)到另一個(gè)位置的距離,其實(shí)也就是item的寬度了。我們是按照未縮放來計(jì)算的。
圖上紅色是原始大小,紫色的是縮小的,可以看到縮小的比例smaller就是decorationNormal除以item的寬度的一半。

整體流程
首先就是繼承一個(gè)LinearLayoutManager,先啥也不寫,完事給recyclerview,設(shè)置這個(gè)manager,在添加一個(gè)itemDecoration,完事所有item的寬度設(shè)置為recyclerView寬度減去4倍的decorationNormal的距離。第一個(gè)完工。
然后開始寫manager,重寫scrollHorizontallyBy方法,在滑動(dòng)的時(shí)候動(dòng)態(tài)修改item的縮放比例即可
簡(jiǎn)單分析下。
中心view往屏幕左邊滑動(dòng),scale從1開始變化到1-smaller。也就是移動(dòng)距離從0到item寬,scale大小縮小了smaller
右邊view往中心滑動(dòng),scale從1-smaller變化到1,移動(dòng)距離從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)
}
需要處理的地方
這里是水平滑動(dòng)的代碼,如果是垂直滾動(dòng)的,那么修改為設(shè)置item的高度
decoration設(shè)置top和bottom
//設(shè)置item的寬度
holder.itemView.layoutParams.width= (rv_gallary.width*(1-4*decorationNormal)).toInt()
//給第一個(gè)和最后一個(gè)item分別添加left和right間隔
addItemDecoration
一次可以滾動(dòng)多個(gè)item用LinearSnapHelper().attachToRecyclerView(this)
如果一次只想滾動(dòng)一個(gè)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,這個(gè)可以自己改
//水平滾動(dòng)的時(shí)候這里會(huì)執(zhí)行
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代碼里的值一樣
//垂直滾動(dòng)的時(shí)候會(huì)走這里
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居中顯示的時(shí)候left位置
val moveX=width*(1-4*decorationNormal)//從一個(gè)位置移動(dòng)到另一個(gè)位置item移動(dòng)的距離
calculateScale(centerViewLeft,moveX)
}
private fun handleVerticalView(){
val centerViewTop=height*2*decorationNormal;//view居中顯示的時(shí)候top位置
val moveY=height*(1-4*decorationNormal)//從一個(gè)位置移動(dòng)到另一個(gè)位置item移動(dòng)的距離
calculateScale(centerViewTop,moveY)
}
/**@param centerViewLeft 水平滑動(dòng)的時(shí)候是left位置,垂直滑動(dòng)是top位置
* @param moveDistance 水平滑動(dòng)是x軸移動(dòng)距離,垂直滑動(dòng)是y軸移動(dòng)距離*/
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往中心滑動(dòng)
scale(this,1f-factor*smaller)
}else{//屏幕中間的view往左邊滑動(dòng)
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()//因?yàn)椴季质状渭虞d完不滑動(dòng)是不會(huì)執(zhí)行scroll方法的,所以這里得修改view的scale
}
}