Pm需求:單張背景圖做平移,至圖片的最左移動至最右邊,ImageView本身沒有什么變化,類似Android的桌面單張長圖的模式。
想法:
- 需要達(dá)成需求,等比縮放后圖的寬度一定要大于屏幕寬度,否則就沒有效果
- 畫一個保存圖片區(qū)域的矩形 , 再利用矩陣對矩形的Translate進(jìn)行變換
- 利用ValueAnimator做成動畫效果即可
//應(yīng)該用如下方法才是創(chuàng)建Matrix對象
Matrix matrix = new Matrix ( mImage.getImageMatrix () );
一、先將XML中的ImageView的scaleType設(shè)置成matrix
使用RectF畫出需要存放圖片的矩形區(qū)域
// 存放圖片區(qū)域的矩形
RectF rectF = new RectF(img.getDrawable().getBounds());
// 圖片寬高
float dw = rectF.width();
float dh = rectF.height();
// 控件寬高
int width = imgBg.getWidth();
int height = imgBg.getHeight();
//初始化矩陣值
imgBg.setImageMatrix(new Matrix());
//獲取矩陣
Matrix matrix = imgBg.getImageMatrix();
//縮放比例
float value = height / dh;
// 縮放變換,按照比例放大,使圖片高度等于控件高度
matrix.postScale(value, value);
// 矩陣縮放映射到存放圖片區(qū)域的矩形
matrix.mapRect(rectF);
// 移動圖片到坐標(biāo)原點
matrix.postTranslate(0, 0);
// 將變換應(yīng)用到圖片
imgBg.setImageMatrix(matrix);
注意:
- postTranslate是指在setScale后平移(preTranslate是在setScale前),他們參數(shù)是平移的距離,而不是平移目的地的坐標(biāo)。
二、設(shè)置位移動畫
位移動畫的移動距離為圖片對當(dāng)前屏幕縮放后的真實寬度減去屏幕(或者當(dāng)前場景下ImageView寬度)
setTranslateAnimation(imgBg, -(dw * value - screenWidth), 0);
動畫的添加:
public void setTranslateAnimation(final ImageView imgBg, float translateX, float translateY) {
Matrix matrix = imgBg.getImageMatrix();
float[] startMatrixValue = new float[9];
float[] endMatrixValue = new float[9];
// 獲取矩陣的初始值
matrix.getValues(startMatrixValue);
// 對矩陣進(jìn)行變換
matrix.postTranslate(translateX, translateY);
// 獲取變換后的值
matrix.getValues(endMatrixValue);
ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
animator.addUpdateListener(new TransXAnimatorListener(imgBg, startMatrixValue, endMatrixValue));
animator.setDuration(4000);
animator.setTarget(imgBg);
// 設(shè)置插值器 LinearInterpolator為勻速效果
animator.setInterpolator(new LinearInterpolator());
animator.start();
}
三、設(shè)置好初始狀態(tài)的矩陣和最終狀態(tài)的矩陣及變換動畫
class TransXAnimatorListener implements ValueAnimator.AnimatorUpdateListener {
private float[] mStartMatrixValue;
private float[] mEndMatrixValue;
private float[] mInterpolateMatrixValue; // 矩陣變換動畫過程中間值
private Matrix mMatrix;
private ImageView imgBg;
public TransXAnimatorListener(final ImageView imgBg, float[] startMatrixValue, float[] endMatrixValue) {
this.mStartMatrixValue = startMatrixValue;
this.mEndMatrixValue = endMatrixValue;
this.imgBg = imgBg;
mInterpolateMatrixValue = new float[9];
mMatrix = imgBg.getImageMatrix();
}
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatedValue = (float) animation.getAnimatedValue();
// 根據(jù)動畫當(dāng)前進(jìn)度設(shè)置矩陣的值
for (int i = 0; i < 9; i++) {
mInterpolateMatrixValue[i] = mStartMatrixValue[i]
+ (mEndMatrixValue[i] - mStartMatrixValue[i]) * animatedValue;
}
mMatrix.setValues(mInterpolateMatrixValue);
imgBg.setImageMatrix(mMatrix);
// setImageMatrix() 不一定會調(diào)用invalidate(),此處手動調(diào)用即可,
// 或者為了避免重復(fù)繪制也可以參考setImageMatrix()源碼進(jìn)行改進(jìn)
imgBg.invalidate();
}
}
此處onAnimationUpdate方法內(nèi)矩陣變換參考:
籬開羅 - 自定義可旋轉(zhuǎn)、平移、縮放的ImageView 中的 [動畫技巧]
四、后續(xù)優(yōu)化
測試過程中放一些分辨率高的圖片的時候發(fā)現(xiàn)出現(xiàn)卡頓,使用bitmap壓縮的話在壓縮過程中會出現(xiàn)短時間的空白屏
- 這里使用Fresco的SimpleDraweeView進(jìn)行替換當(dāng)前的ImageView
- 添加Viewpager和Indicator效果,完成需求
也有使用過Glide去加載并簡化,不過效果會有些問題,還需要再度完善,新手一枚還需要多多練習(xí)。
Demo已放在上Github,如有需要的盆友可以看一下,互相交流~