偶然間看到知乎廣告位的效果,做爲一名好奇心爆棚的程序員,以爲頗有趣,思考了下原理,決定造個輪子,國際慣例效果圖以下(注意圖中的章魚):android
首先應該市有一張長圖,隨着滾動按區域加載長圖的局部,就能夠實現效果。首先自定義一個 IamgeView,能夠隨着 RecyclerView 的滾動動態加載長圖的的取域,獲取滾動距離代碼以下:程序員
/**
* 獲取到RecyclerView的滾動距離
*/
private fun setRecyclerView() {
post {
var par: ViewParent? = parent
while (true) {
if (par is RecyclerView) {
rv = par
break
} else {
par = par?.parent
}
}
rv!!.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
}
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
Log.d(TAG, "onScrolled$dy")
setShowH(dy)
}
})
}
}
複製代碼
根據滾動距離動態加載圖片,代碼以下:bash
/**
* @param h 每次過分的距離,用於計算 RecyclerView 滾動的總距離
*/
fun setShowH(h: Int) {
if (dettach) {
return
}
scollHeight += h
//邊界
scollHeight = min(bitmapRegionDecoder.height - mHeight, (max(scollHeight, 0)))
Log.d(TAG, "setShowH$scollHeight")
Log.d(TAG, "bitmapRegionDecoder.height${bitmapRegionDecoder.height}")
Log.d(TAG, "scollHeight + mHeig${scollHeight + mHeight}")
//按舉行區域加載圖片
var bitmap: Bitmap =
bitmapRegionDecoder.decodeRegion(
Rect(0, scollHeight, width, scollHeight + mHeight),
null
)
setImageBitmap(bitmap)
}
複製代碼
完整代碼以下:ide
package com.example.juejin
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapRegionDecoder
import android.graphics.Rect
import android.util.AttributeSet
import android.util.Log
import android.view.ViewParent
import android.widget.ImageView
import androidx.recyclerview.widget.RecyclerView
import kotlin.math.max
import kotlin.math.min
/**
* @author lishaojie on 2019/10/22
*/
class RegionImageView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
val TAG: String = "RegionImageView",
var dettach: Boolean = false
) : ImageView(context, attrs, defStyleAttr) {
var mHeight: Int = 0
var scollHeight: Int = 0
private var rv: RecyclerView? = null
//長圖
var bitmapRegionDecoder: BitmapRegionDecoder = BitmapRegionDecoder.newInstance(
context.assets.open("octopus.jpg"),
false
)
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
if (mHeight == 0) {
mHeight = h
setShowH(0)
setRecyclerView()
}
}
/**
* 獲取到RecyclerView的滾動距離
*/
private fun setRecyclerView() {
post {
var par: ViewParent? = parent
while (true) {
if (par is RecyclerView) {
rv = par
break
} else {
par = par?.parent
}
}
rv!!.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
}
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
Log.d(TAG, "onScrolled$dy")
setShowH(dy)
}
})
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
dettach = false
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
Log.d(TAG, "onDetachedFromWindow")
dettach = true
}
/**
* @param h 每次過分的距離,用於計算 RecyclerView 滾動的總距離
*/
fun setShowH(h: Int) {
if (dettach) {
return
}
scollHeight += h
//邊界
scollHeight = min(bitmapRegionDecoder.height - mHeight, (max(scollHeight, 0)))
Log.d(TAG, "setShowH$scollHeight")
Log.d(TAG, "bitmapRegionDecoder.height${bitmapRegionDecoder.height}")
Log.d(TAG, "scollHeight + mHeig${scollHeight + mHeight}")
//按舉行區域加載圖片
var bitmap: Bitmap =
bitmapRegionDecoder.decodeRegion(
Rect(0, scollHeight, width, scollHeight + mHeight),
null
)
setImageBitmap(bitmap)
}
}
複製代碼
binggopost