** Do not just use Glide.xxx.into(imageView).
use ImageView.setImageAsDrawable()
in ImageViews.kt
fun ImageView.setImageAsDrawable( | |
url: String, | |
@DrawableRes placeHolder: Int? = null | |
) { | |
Glide.with(this) | |
// .asBitmap() | |
.load(url) | |
.apply { | |
if (placeHolder != null) { | |
apply(RequestOptions().placeholder(placeHolder)) | |
} | |
} | |
.into(object : CustomTarget<Drawable>() { | |
override fun onLoadCleared(placeholder: Drawable?) { | |
this@setImageAsDrawable.setImageDrawable(placeholder) | |
} | |
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) { | |
this@setImageAsDrawable.setImageDrawable(resource) | |
} | |
}) | |
} |
package com.fanhl.parallaximage | |
import android.graphics.Matrix | |
import android.graphics.RectF | |
import android.util.Log | |
import android.widget.ImageView | |
import androidx.core.math.MathUtils | |
import androidx.recyclerview.widget.RecyclerView | |
/** | |
* 处理图像在滚动中的显示 | |
*/ | |
class ParallaxImageRecyclerViewHelper private constructor() { | |
/** 目前图像 */ | |
private var target: ImageView? = null | |
/** 目前图像所在的滚动父布局 */ | |
private var dependency: RecyclerView? = null | |
/** target的宽度与dependency的宽度的比率 */ | |
private var widthRate = 1f | |
private var heightRate = 1f | |
private var horizontalBias = 0.5f | |
private var verticalBias = 0.5f | |
/** | |
* 临时存放区 | |
* FIXME 之后加上生命周期 | |
*/ | |
private val outLocation = IntArray(2) | |
private val onScrollListener = object : RecyclerView.OnScrollListener() { | |
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { | |
super.onScrolled(recyclerView, dx, dy) | |
computeImageMatrix( | |
target ?: return, | |
dependency ?: return | |
) | |
} | |
} | |
private fun setup(recyclerView: RecyclerView, imageView: ImageView) { | |
this.target = imageView | |
if (this.dependency != recyclerView) { | |
this.dependency?.removeOnScrollListener(onScrollListener) | |
this.dependency = recyclerView | |
} | |
recyclerView?.addOnScrollListener(onScrollListener) ?: return | |
} | |
private fun computeImageMatrix( | |
target: ImageView, | |
dependency: RecyclerView | |
) { | |
//FIXME 这部分可以只修改一次 | |
widthRate = target.width.toFloat() / dependency.width | |
heightRate = target.height.toFloat() / dependency.height | |
//FIXME 这部分可以根据父布局的滚动方向,只计算对应方向的就可以了 | |
target.getLocationOnScreen(outLocation) | |
val targetX = outLocation[0] | |
val targetY = outLocation[1] | |
dependency.getLocationOnScreen(outLocation) | |
val dependencyX = outLocation[0] | |
val dependencyY = outLocation[1] | |
horizontalBias = ((targetX - dependencyX).toFloat() / (dependency.width - target.width)).clamp() | |
verticalBias = ((targetY - dependencyY).toFloat() / (dependency.height - target.height)).clamp() | |
// Log.d(TAG, "widthRate:$widthRate,heightRate:$heightRate horizontalBias:$horizontalBias,verticalBias:$verticalBias") | |
this.target?.apply { | |
val drawable = drawable ?: return | |
// val matrix = imageMatrix | |
val viewWidth = width// - paddingLeft - paddingRight | |
val viewHeight = height// - paddingTop - paddingBottom | |
val drawableWidth = drawable.intrinsicWidth | |
val drawableHeight = drawable.intrinsicHeight | |
// TODO 以下计算式等其它部分全部完全后再优化 | |
val drawableRect = if (drawableWidth * viewHeight > drawableHeight * viewWidth) { | |
val scale = viewHeight.toFloat() / drawableHeight.toFloat() | |
// val horizontalBias = left.toFloat() / (left + (parent as View).right - right) | |
val dx = horizontalBias * (drawableWidth - viewWidth / scale) | |
RectF(dx, 0f, dx + drawableHeight.toFloat(), drawableHeight.toFloat() * viewWidth / viewHeight) | |
} else { | |
val scale = viewWidth.toFloat() / drawableWidth.toFloat() | |
// val verticalBias = top.toFloat() / (top + (parent as View).bottom - bottom) | |
val dy = verticalBias * (drawableHeight - viewHeight / scale) | |
RectF(0f, dy, drawableWidth.toFloat(), dy + drawableWidth.toFloat() * viewHeight / viewWidth) | |
} | |
val viewRect = RectF(0f, 0f, viewWidth.toFloat(), viewHeight.toFloat()) | |
Log.d(TAG, "drawableRect:$drawableRect viewRect:$viewRect") | |
imageMatrix.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.FILL) | |
invalidate() | |
// imageMatrix = matrix | |
} | |
} | |
companion object { | |
private val TAG = ParallaxImageRecyclerViewHelper::class.java.simpleName | |
fun setup(recyclerView: RecyclerView, imageView: ImageView) { | |
ParallaxImageRecyclerViewHelper().setup(recyclerView, imageView) | |
} | |
} | |
private fun Float.clamp() = MathUtils.clamp(this, 0f, 1f) | |
} |