Ken Burns effect是一种图片在切换之前,会缓慢在页面移动或者放大缩小,然后再慢慢切换过去。这样的效果使得每一张静止图片都有动态的效果感觉。类似的效果在电子相册,或者在电影视频对静态图片的处理中经常可见。项目前期设计时有运动功能就是Ken Burns effect 效果但是各种原因给砍掉了QAQ
与网上的效果不同的是,项目需求需要对一张图定位起始位置和结束为止然后点击播放的时候开始KenBurns动画
同时点击推进和拉远可以回到默认位置,可以重新进行缩放,最后在上传的时候讲其实位置的参数和结束为止的参数上传到服务器
先给个效果图
image.png
这张图是半成品,因为还没有加入动画,但是没关系因为动画也就几行代码的事情
梳理一下思路首先要实现的是左右滑动两张的RecyclerView直接重写dispatchTouchEvent
看代码
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int pointerCount = ev.getPointerCount();
switch (ev.getAction()) {
case MotionEvent.ACTION_POINTER_1_DOWN:
Log.i("ContentValues", "MyRecyclerdispatchTouchEvent: ACTION_POINTER_1_DOWN");
break;
case MotionEvent.ACTION_POINTER_2_DOWN:
if (isMove) {
//当第二个手指触摸当时候,取消第一个手指的触摸
int pointerId = ev.getPointerId(0);
Log.i("ContentValues", "MyRecyclerdispatchTouchEvent: ACTION_POINTER_2_DOWN pointerId === " + pointerId);
// ev.setAction(MotionEvent.ACTION_CANCEL);
return true;
}
break;
case MotionEvent.ACTION_POINTER_3_DOWN:
Log.i("ContentValues", "MyRecyclerdispatchTouchEvent: ACTION_POINTER_3_DOWN");
break;
case MotionEvent.ACTION_DOWN:
downX = ev.getX();
downX1 = ev.getX();
downY = ev.getY();
downY1 = ev.getY();
Log.i("ContentValues", "MyRecyclerdispatchTouchEvent: ACTION_DOWN = " + downX);
break;
case MotionEvent.ACTION_MOVE:
if (pointerCount == 1 && isNeedScroll) {
float preX = downX;
float preY = downY;
float nowX = ev.getX();
float nowY = ev.getY();
i = (int) (preX - nowX);
j = (int) (preY - nowY);
if (Math.abs(i) > 1) {
isMove = true;
}
scrollBy(i, j);
downX = nowX;
downY = nowY;
distanceX = nowX - downX1;
distanceY = nowY - downY1;
invalidate();
Log.i("ContentValues", "MyRecyclerdispatchTouchEvent: ACTION_MOVE" + nowX + "---i" + i + "----j" + j + "+=++distanceX = " + distanceX);
return true;
} else {
isNeedScroll = false;
}
break;
case MotionEvent.ACTION_UP:
Log.i("ContentValues", "MyRecyclerdispatchTouchEvent: ACTION_UP ===distanceX = " + distanceX + "===distanceY" + distanceY);
if (pointerCount == 1 && isNeedScroll && isMove) {
//如果向左滑动的距离大于50表示向左滑动 如果 向右滑动的距离大于50表示向右滑动
if (Math.abs(distanceX) > 50 && distanceX < 0 && Math.abs(distanceY) < 100) {
smoothScrollToPosition(1);
if (onDotChangeListener != null) {
onDotChangeListener.change(1);
}
Log.i("ContentValues", "MyRecyclerdispatchTouchEvent: smoothScrollToPosition(1)");
} else {
Log.i("ContentValues", "MyRecyclerdispatchTouchEvent: smoothScrollToPosition(0)");
smoothScrollToPosition(0);
if (onDotChangeListener != null) {
onDotChangeListener.change(0);
}
}
}
isNeedScroll = true;
isMove = false;
break;
case MotionEvent.ACTION_POINTER_UP:
Log.i("ContentValues", "MyRecyclerdispatchTouchEvent: ACTION_POINTER_UP");
break;
}
return super.dispatchTouchEvent(ev);
}
主要是RecyclerView和可缩放的CropPhotoView滑动冲突太鸡儿坑人了,所以不得不重写,同时还要将滑到半途时自动滑动
接下来就是CropPhotoView了 这个自定义的View使我们之前项目就有的我就直接拿来用了,也没怎么看
贴下代码吧 其实你可以不用看直接拿来用就行了,哪里报错改哪里
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.os.Handler;
import android.os.Message;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.View.OnTouchListener;
import com.wanyueliang.avm.config.AppConfig;
import com.wanyueliang.avm.model.databean.AdjustParam;
import com.wanyueliang.avm.utils.log.AppLog;
import java.lang.ref.WeakReference;
import java.text.DecimalFormat;
public class CropPhotoView extends AppCompatImageView implements OnTouchListener {
private boolean CROP_PHOTO_MIN_ZOOM = false;
private Bitmap bitmap = null;
private boolean bOnTouchEnable = true;
public static final int UI_MOVE_ANIME_START = 1;
public static final int UI_MOVE_ANIME_STOP = 2;
private static final int UI_ROTATE_ANIME_START = 3;
private static final int UI_ROTATE_ANIME_STOP = 4;
private DecimalFormat decimalFormat = new DecimalFormat("##0.00000000");
private double mNowDegrees = 0.0f;
private float to_degrees = 0.0f;
private final float one_step_degrees = 1.0f;
private float step_count_degrees = 0.0f;
private final int rotate_speed = 0; // 越小越快
//
private float to_move_x = 0.0f;
private float to_move_y = 0.0f;
private float one_step_move_x = 1.0f;
private float one_step_move_y = 1.0f;
private float step_count_move_xy = 0.0f;
private float step_total_count_move_xy = 0.0f;
private final int move_xy_speed = 2; // 越小越快
private final static float CROP_WIDTH_1920 = 1920;
private final static float CROP_HEIGHT_1080 = 1080;
private float view_width;
private float view_height;
private float crop_width, crop_height, bmWidth, bmHeight;
public float origWidth, origHeight;
private float outPutPhotoW, outPutPhotoH;
private double crop_diagonally, crop_degree_diagonally_s;
private Matrix matrix = new Matrix();
private float[] m = new float[9];
private boolean isFitDependWidth = true;
public AdjustParam mAdjustParam = new AdjustParam();
private float centerOffsetX;
private float centerOffsetY;
private static final int NONE = 0;
private static final int PAN = 1;
private static final int ZOOM = 2;
public int mode = NONE;
public PointF LastPoint = new PointF();
public PointF StartPoint = new PointF();
public PointF P1 = new PointF();
public PointF P2 = new PointF();
public PointF P3 = new PointF();
public PointF P4 = new PointF();
public float saveScale = 1f;
float minScale = 1f;
float maxScale = 3f;
private ScaleGestureDetector mScaleDetector;
private Context mContext;
private int padding;
private float max_crop_in_padding;
private float horizontal_minScale;// 水平时最小的缩放系数
private float vertical_minScale;// 垂直时最小的缩放系数
private float vertical_saveScale = 0;
private Handler mUIHandler;
/**
* 5.1.0版本增加一个监听
*/
private OnTouchListener onTouchListener;
private String TAG = getClass().getSimpleName();
public CropPhotoView(Context context) {
super(context);
init();
mContext = context;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
}
public CropPhotoView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
mContext = context;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
}
public CropPhotoView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
mContext = context;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
}
public void init() {
this.setOnTouchListener(this);
mUIHandler = new UiHandler((Activity) mContext, this);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 画出变换后的图像
if (bitmap != null) {
canvas.drawBitmap(bitmap, matrix, null);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (w > 0 && h > 0) {
view_width = w;
view_height = h;
calculateValue();
invalidate();
}
}
private void calculateValue() {
// clear init start
mNowDegrees = 0.0f;
to_degrees = 0.0f;
step_count_degrees = 0.0f;
matrix = new Matrix();
m = new float[9];
LastPoint = new PointF();
StartPoint = new PointF();
P1 = new PointF();
P2 = new PointF();
P3 = new PointF();
P4 = new PointF();
saveScale = 1f;
maxScale = 3f;
// clear init end
// 设置剪裁区域宽度
crop_width = view_width - 2 * padding;
// 设置剪裁区域高度
crop_height = view_height - 2 * padding;
// 设置剪裁区域中心横线与对角线夹角
crop_degree_diagonally_s = Math.atan(crop_height / crop_width) / Math.PI * 180;
// 设置剪裁区域对角线长度
crop_diagonally = Math.sqrt((crop_width * crop_width + crop_height * crop_height)) / 2;
// 设置所编辑照片宽度充满剪裁区域,高度可以超出剪裁区域
fitScreen();
// 如果此前该照片被裁剪过,则按照裁剪的坐标显示
if (mAdjustParam.isAdjusted.equals("1")) {
float org_crop_w = view_width - 2 * AppConfig.CROP_PADDING; // 剪裁区域的间距10(目前是固定值)
float org_crop_h = org_crop_w * 9 / 16;
float c_scale = crop_width / org_crop_w;
float fCenterOffsetX = 0;
float fCenterOffsetY = 0;
float scaleR = 1.0f;
if (isFitDependWidth) {
fCenterOffsetX = c_scale * (Float.parseFloat(mAdjustParam.centerOffset.offsetX) * org_crop_w / CROP_WIDTH_1920);
fCenterOffsetY = c_scale * (Float.parseFloat(mAdjustParam.centerOffset.offsetY) * org_crop_h / CROP_HEIGHT_1080);
float savedScaleWidth = Float.parseFloat(mAdjustParam.zoomScale) * (org_crop_w / CROP_WIDTH_1920) * (float) outPutPhotoW;
scaleR = savedScaleWidth / org_crop_w;
} else {
fCenterOffsetX = c_scale * (Float.parseFloat(mAdjustParam.centerOffset.offsetX) * org_crop_w / CROP_WIDTH_1920);
fCenterOffsetY = c_scale * (Float.parseFloat(mAdjustParam.centerOffset.offsetY) * org_crop_h / CROP_HEIGHT_1080);
float savedScaleHeight = Float.parseFloat(mAdjustParam.zoomScale) * (org_crop_h / CROP_HEIGHT_1080) * (float) outPutPhotoH;
scaleR = savedScaleHeight / org_crop_h;
}
float deegrees = (-Float.parseFloat(mAdjustParam.rotateScale) * 360) / (2 * (float) Math.PI);
mNowDegrees = deegrees;
matrix.postRotate(deegrees, view_width / 2, view_height / 2);
setZoomScale(scaleR, view_width / 2, view_height / 2);
matrix.postTranslate(fCenterOffsetX, fCenterOffsetY >= 0 ? -fCenterOffsetY : -Math.round(fCenterOffsetY));
}
}
/**
* 新添加的模式
*/
public void setBitmap(boolean crop_min_zoom, Bitmap bitmap, int padding, float outPutPhotoW, float outPutPhotoH) {
setValue(crop_min_zoom, bitmap, padding, outPutPhotoW, outPutPhotoH);
if (view_width > 0) {
this.mAdjustParam = getAdjustParam();
notifySetDataChange();
}
}
/**
* 编辑的模式
*/
public void setBitmap(boolean crop_min_zoom, Bitmap bitmap, int padding, AdjustParam aAdjustParam, float outPutPhotoW, float outPutPhotoH) {
setValue(crop_min_zoom, bitmap, padding, outPutPhotoW, outPutPhotoH);
this.mAdjustParam = aAdjustParam;
if (view_width > 0) {
notifySetDataChange();
}
}
public void setValue(boolean crop_min_zoom, Bitmap bitmap, int padding, float outPutPhotoW, float outPutPhotoH) {
this.CROP_PHOTO_MIN_ZOOM = crop_min_zoom;
this.outPutPhotoW = outPutPhotoW;
this.outPutPhotoH = outPutPhotoH;
// 设置所编辑照片的bitmap
this.bitmap = bitmap;
// 设置剪裁区域余白边距
this.padding = padding;
// 原始图片宽度
bmWidth = bitmap.getWidth();
// 原始图片高度
bmHeight = bitmap.getHeight();
}
public void notifySetDataChange() {
calculateValue();
invalidate();
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
try {
if (bitmap != null) {
canvas.drawBitmap(bitmap, matrix, null);
}
} catch (Exception e) {
}
}
// 设置父控件是否可以获取到触摸处理权限
private void setParentScrollAble(boolean flag) {
getParent().requestDisallowInterceptTouchEvent(!flag);
}
public boolean onTouch(View v, MotionEvent event) {
if (onTouchListener != null) {
onTouchListener.onTouch(v, event);
}
if (bOnTouchEnable) {
if (CROP_PHOTO_MIN_ZOOM) {
if (Math.abs((int) mNowDegrees / 90) % 2 == 1) {
if (origWidth < origHeight) {
minScale = crop_height / origWidth;
}
}
} else {
if (Math.abs((int) mNowDegrees / 90) % 2 == 1 && origWidth > origHeight) {
minScale = crop_width / origHeight;
} else {
minScale = 1.0f;
}
}
mScaleDetector.onTouchEvent(event);
update4PointXY();
PointF NowPoint = new PointF(event.getX(), event.getY());
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
setParentScrollAble(false);
// CropViewOnTouchEvent down_event = new CropViewOnTouchEvent();
// down_event.isOnTouch = true;
// EventBus.getDefault().post(down_event);
LastPoint.set(event.getX(), event.getY());
StartPoint.set(LastPoint);
mode = PAN;
break;
case MotionEvent.ACTION_MOVE:
if (mode == PAN) {
float deltaX = NowPoint.x - LastPoint.x;
float deltaY = NowPoint.y - LastPoint.y;
matrix.postTranslate(deltaX, deltaY);
LastPoint.set(NowPoint.x, NowPoint.y);
}
break;
case MotionEvent.ACTION_UP:
setParentScrollAble(true);
case MotionEvent.ACTION_CANCEL:
mode = NONE;
noScaleTranslateToFitEdge(false);
// CropViewOnTouchEvent up_event = new CropViewOnTouchEvent();
// up_event.isOnTouch = false;
// EventBus.getDefault().post(up_event);
if (onMovingListener != null) {
onMovingListener.onMoving();
}
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
// CropViewOnTouchEvent point_up_event = new CropViewOnTouchEvent();
// point_up_event.isOnTouch = false;
// EventBus.getDefault().post(point_up_event);
break;
}
invalidate();
}
return true;
}
private OnMovingListener onMovingListener;
public void setOnMovingListener(OnMovingListener onMovingListener) {
this.onMovingListener = onMovingListener;
}
public interface OnMovingListener {
void onMoving();
}
public double getDegrees() {
return mNowDegrees;
}
public void setZoomScale(float mScaleFactor, float px, float py) {
float origScale = saveScale;
saveScale *= mScaleFactor;
if (saveScale > maxScale) {
saveScale = maxScale;
mScaleFactor = maxScale / origScale;
} else if (saveScale < minScale) {
saveScale = minScale;
mScaleFactor = minScale / origScale;
}
matrix.postScale(mScaleFactor, mScaleFactor, px, py);
update4PointXY();
// 缩小的时候
if (mScaleFactor < 1) {
// noScaleTranslateToFitEdge();
}
}
public void noScaleTranslateToFitEdge(boolean smooth) {
update4PointXY();
float moveX = 0.0f;
float moveY = 0.0f;
float zfMarkX = 1.0f;
float zfMarkY = 1.0f;
// 照片的左边有余白的时候,平移至左边边缘对齐
float left_padding = Math.min(Math.min(Math.min(P1.x, P2.x), P3.x), P4.x);
if (left_padding > padding) {
moveX = -(left_padding - padding);
zfMarkX = -zfMarkX;
}
// 照片的右边有余白的时候,平移至右边边缘对齐
float right_padding = Math.max(Math.max(Math.max(P1.x, P2.x), P3.x), P4.x);
if (right_padding < crop_width + padding) {
moveX = crop_width + padding - right_padding;
}
// 照片的上边有余白的时候,平移至上边边缘对齐
float top_padding = Math.min(Math.min(Math.min(P1.y, P2.y), P3.y), P4.y);
if (top_padding > padding) {
moveY = -(top_padding - padding);
zfMarkY = -zfMarkY;
}
// 照片的下边有余白的时候,平移至下边边缘对齐
float bottom_padding = Math.max(Math.max(Math.max(P1.y, P2.y), P3.y), P4.y);
if (bottom_padding < crop_height + padding) {
moveY = crop_height + padding - bottom_padding;
}
if (CROP_PHOTO_MIN_ZOOM) {
// 照片的左边和右边同时有余白时,平移至中间对齐
if (saveScale <= 1.0f && Math.abs((int) mNowDegrees / 90) % 2 == 0) {
if (left_padding > padding || right_padding < crop_width + padding) {
moveX = (-(left_padding - padding) + crop_width + padding - right_padding) / 2;
zfMarkX = -zfMarkX;
}
} else if (Math.abs((int) mNowDegrees / 90) % 2 == 1) {
if (left_padding > padding || right_padding < crop_width + padding) {
moveX = (-(left_padding - padding) + crop_width + padding - right_padding) / 2;
zfMarkX = -zfMarkX;
}
}
}
if (smooth) {
bOnTouchEnable = false;
to_move_x = moveX;
to_move_y = moveY;
if (Math.abs(to_move_x) == 0 && Math.abs(to_move_y) != 0) {
step_total_count_move_xy = Math.abs(to_move_y);
one_step_move_x = 0;
one_step_move_y = 1.0f * zfMarkY;
} else if (Math.abs(to_move_x) != 0 && Math.abs(to_move_y) == 0) {
step_total_count_move_xy = Math.abs(to_move_x);
one_step_move_x = 1.0f * zfMarkX;
one_step_move_y = 0;
} else if (Math.abs(to_move_x) >= Math.abs(to_move_y)) {
step_total_count_move_xy = Math.abs(to_move_y);
one_step_move_x = Math.abs(moveX) / Math.abs(moveY) * zfMarkX;
one_step_move_y = 1.0f * zfMarkY;
} else {
step_total_count_move_xy = Math.abs(to_move_x);
one_step_move_x = 1.0f * zfMarkX;
one_step_move_y = Math.abs(moveY) / Math.abs(moveX) * zfMarkY;
}
step_count_move_xy = 0.0f;
mUIHandler.sendEmptyMessageDelayed(UI_MOVE_ANIME_START, 0);
} else {
matrix.postTranslate(moveX, moveY);
}
}
public float getRotatedMaxCropInPadding(Matrix rotateM) {
float[] f = new float[9];
rotateM.getValues(f);
// 图片4个顶点的坐标
float x1 = f[0] * 0 + f[1] * 0 + f[2];
float y1 = f[3] * 0 + f[4] * 0 + f[5];
float x2 = f[0] * bmWidth + f[1] * 0 + f[2];
float y2 = f[3] * bmWidth + f[4] * 0 + f[5];
float x3 = f[0] * 0 + f[1] * bmHeight + f[2];
float y3 = f[3] * 0 + f[4] * bmHeight + f[5];
float x4 = f[0] * bmWidth + f[1] * bmHeight + f[2];
float y4 = f[3] * bmWidth + f[4] * bmHeight + f[5];
float max_crop_in_padding = 0.0f;
float left = 0.0f;
float top = 0.0f;
float right = 0.0f;
float bottom = 0.0f;
// 照片的左边有余白的时候
float left_padding = Math.min(Math.min(Math.min(x1, x2), x3), x4);
if (left_padding > padding) {
left = left_padding - padding;
}
// 照片的右边有余白的时候
float right_padding = Math.max(Math.max(Math.max(x1, x2), x3), x4);
if (right_padding < crop_width + padding) {
right = crop_width + padding - right_padding;
}
// 照片的上边有余白的时候
float top_padding = Math.min(Math.min(Math.min(y1, y2), y3), y4);
if (top_padding > padding) {
top = top_padding - padding;
}
// 照片的下边有余白的时候
float bottom_padding = Math.max(Math.max(Math.max(y1, y2), y3), y4);
if (bottom_padding < crop_height + padding) {
bottom = crop_height + padding - bottom_padding;
}
max_crop_in_padding = Math.max(Math.max(Math.max(top, bottom), left), right);
return max_crop_in_padding;
}
private void update4PointXY() {
matrix.getValues(m);
// 图片4个顶点的坐标
P1.x = m[0] * 0 + m[1] * 0 + m[2];
P1.y = m[3] * 0 + m[4] * 0 + m[5];
P2.x = m[0] * bmWidth + m[1] * 0 + m[2];
P2.y = m[3] * bmWidth + m[4] * 0 + m[5];
P3.x = m[0] * 0 + m[1] * bmHeight + m[2];
P3.y = m[3] * 0 + m[4] * bmHeight + m[5];
P4.x = m[0] * bmWidth + m[1] * bmHeight + m[2];
P4.y = m[3] * bmWidth + m[4] * bmHeight + m[5];
// 图片现宽度
// double width = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
public AdjustParam getAdjustParam() {
update4PointXY();
// 照片的中心相对于裁剪框的中心的偏移量
updateCenterOffsetXYParam();
// 图片最终的尺寸相对图片原始尺寸的缩放系数。
updateZoomScaleParam();
// 把角度转换为PI
// 逆时针旋转为正,最大不超过360(360即为0)
double formatDegrees = -mNowDegrees;
if (formatDegrees < 0) {
formatDegrees = 360 + formatDegrees;
}
mAdjustParam.rotateScale = String.valueOf(decimalFormat.format(((Math.abs(formatDegrees) / 360) * 2 * Math.PI)));
// showAdjustParam();
return mAdjustParam;
}
// 照片的中心相对于裁剪框的中心的偏移量(裁剪框按照1920*1080计算)
private void updateCenterOffsetXYParam() {
centerOffsetX = (P1.x + P4.x) / 2;
centerOffsetY = (P1.y + P4.y) / 2;
float offsetMPointX = padding + crop_width / 2;
float offsetMPointY = padding + crop_height / 2;
// 向限(+,+)
if (centerOffsetX >= offsetMPointX && centerOffsetY <= offsetMPointY) {
centerOffsetX = centerOffsetX - offsetMPointX;
centerOffsetY = offsetMPointY - centerOffsetY;
}
// 向限(+,-)
else if (centerOffsetX >= offsetMPointX && centerOffsetY >= offsetMPointY) {
centerOffsetX = centerOffsetX - offsetMPointX;
centerOffsetY = -(centerOffsetY - offsetMPointY);
}
// 向限(-,+)
else if (centerOffsetX <= offsetMPointX && centerOffsetY <= offsetMPointY) {
centerOffsetX = -(offsetMPointX - centerOffsetX);
centerOffsetY = offsetMPointY - centerOffsetY;
}
// 向限(-,-)
else if (centerOffsetX <= offsetMPointX && centerOffsetY >= offsetMPointY) {
centerOffsetX = -(offsetMPointX - centerOffsetX);
centerOffsetY = -(centerOffsetY - offsetMPointY);
}
centerOffsetX = (CROP_WIDTH_1920 * centerOffsetX) / crop_width;
centerOffsetY = (CROP_HEIGHT_1080 * centerOffsetY) / crop_height;
mAdjustParam.centerOffset.offsetX = decimalFormat.format(centerOffsetX) + "";
mAdjustParam.centerOffset.offsetY = decimalFormat.format(centerOffsetY) + "";
}
// 图片最终的尺寸相对图片原始尺寸的缩放系数。小数点后保留8位 默认为0
public void updateZoomScaleParam() {
float zoomScale = 1.0f;
if (isFitDependWidth) {
if (origHeight >= crop_height) {
float scaleWidth = Math.round(origWidth * saveScale);
zoomScale = (CROP_WIDTH_1920 / origWidth) * (scaleWidth / outPutPhotoW);
} else {
float scaleHeight = Math.round(origHeight * saveScale);
zoomScale = (CROP_HEIGHT_1080 / origHeight) * (scaleHeight / outPutPhotoH);
}
} else {
if (origWidth >= crop_width) {
float scaleHeight = Math.round(origHeight * saveScale);
zoomScale = (CROP_HEIGHT_1080 / origHeight) * (scaleHeight / outPutPhotoH);
} else {
float scaleWidth = Math.round(origWidth * saveScale);
zoomScale = (CROP_WIDTH_1920 / origWidth) * (scaleWidth / outPutPhotoW);
}
}
mAdjustParam.zoomScale = decimalFormat.format(zoomScale) + "";
AppLog.d(TAG, "[Photo Scale]" + mAdjustParam.zoomScale);
}
private void fitScreen() {
// Fit to screen.
float scale;
float scaleX = (float) crop_width / (float) bmWidth;
float scaleY = (float) crop_height / (float) bmHeight;
// Fit crop_width
scale = Math.max(scaleX, scaleY);
if (scaleX >= scaleY) {
isFitDependWidth = true;
} else {
isFitDependWidth = false;
}
// fit inCenter
// scale = Math.min(scaleX, scaleY);
if (!mAdjustParam.isAdjusted.equals("1")) {
mAdjustParam.zoomScale = decimalFormat.format(scale) + "";
}
matrix.setScale(scale, scale);
saveScale = 1f;
// Center the image
float redundantXSpace = ((float) crop_width - (scale * (float) bmWidth)) / 2;
float redundantYSpace = ((float) crop_height - (scale * (float) bmHeight)) / 2;
// 平移至剪裁区域左上角为定点
matrix.postTranslate(redundantXSpace + padding, redundantYSpace + padding);
// 剪裁区域初始照片宽度
origWidth = scale * (float) bmWidth;
// 剪裁区域初始照片高度
origHeight = scale * (float) bmHeight;
if (CROP_PHOTO_MIN_ZOOM) {
horizontal_minScale = crop_height / origHeight;
vertical_minScale = crop_width / origHeight;
minScale = horizontal_minScale;
} else {
minScale = 1f;
}
}
public void setRotate(float degrees, boolean smooth) {
if (bOnTouchEnable) {
mNowDegrees = mNowDegrees + degrees;
if (mNowDegrees >= 360 || mNowDegrees <= -360) {
mNowDegrees = 0;
}
update4PointXY();
boolean needScale = true;
float scaleWidth = Math.round(origWidth * saveScale);
float scaleHeight = Math.round(origHeight * saveScale);
double after_scale_w = scaleWidth;
double after_scale_h = scaleHeight;
if (degrees == 90 || degrees == -90) {
Matrix rotateM = new Matrix();
rotateM.set(matrix);
rotateM.postRotate(degrees, view_width / 2, view_height / 2); // 预旋转,然后检查旋转后是否有余白
max_crop_in_padding = getRotatedMaxCropInPadding(rotateM);
// 如果旋转后4个边没有余白距离的话不放缩
if (max_crop_in_padding == 0) {
needScale = false;
}
// 如果旋转后4个边有余白距离的话放缩
else {
if (scaleWidth <= scaleHeight) {
if (scaleWidth < crop_height) {
saveScale = (scaleHeight + 2 * max_crop_in_padding) / scaleHeight;
} else {
needScale = false;
}
} else {
if (scaleHeight < crop_width) {
saveScale = (scaleHeight + 2 * max_crop_in_padding) / scaleHeight;
vertical_saveScale = saveScale;
} else {
needScale = false;
}
}
}
}
// 不大于剪裁区域对角线与水平横线夹角的时候
else if (Math.round(degrees) <= crop_degree_diagonally_s) {
if (scaleWidth <= scaleHeight) {
after_scale_w = Math.cos((crop_degree_diagonally_s - degrees) * Math.PI / 180) * crop_diagonally * 2;
if (after_scale_w > scaleWidth) {
saveScale = (float) (after_scale_w / scaleWidth);
} else {
needScale = false;
}
} else {
after_scale_h = Math.cos((crop_degree_diagonally_s - degrees) * Math.PI / 180) * crop_diagonally * 2;
if (after_scale_h > scaleHeight) {
saveScale = (float) (after_scale_h / scaleHeight);
} else {
needScale = false;
}
}
} else {
if (scaleWidth <= scaleHeight) {
after_scale_w = Math.cos((90.0f - degrees - crop_degree_diagonally_s) * Math.PI / 180) * crop_diagonally * 2;
if (after_scale_w > scaleWidth) {
saveScale = (float) (after_scale_w / scaleWidth);
} else {
needScale = false;
}
} else {
after_scale_h = Math.cos((90.0f - degrees - crop_degree_diagonally_s) * Math.PI / 180) * crop_diagonally * 2;
if (after_scale_h > scaleHeight) {
saveScale = (float) (after_scale_h / scaleHeight);
} else {
needScale = false;
}
}
}
step_count_degrees = 0.0f;
to_degrees = degrees;
bOnTouchEnable = false;
if (smooth) {
mUIHandler.removeMessages(UI_ROTATE_ANIME_START);
mUIHandler.removeMessages(UI_ROTATE_ANIME_STOP);
mUIHandler.sendEmptyMessageDelayed(UI_ROTATE_ANIME_START, 0);
} else {
matrix.postRotate(degrees, view_width / 2, view_height / 2);
}
if (needScale) {
matrix.postScale(saveScale, saveScale, view_width / 2, view_height / 2);
}
if (CROP_PHOTO_MIN_ZOOM) {
if (Math.abs((int) mNowDegrees / 90) % 2 == 1) {
if (origWidth > origHeight) {
minScale = crop_height / origWidth;
if (needScale) {
saveScale = vertical_minScale;
}
} else {
minScale = vertical_minScale;
if (needScale) {
saveScale = vertical_minScale;
}
}
} else if (Math.abs((int) mNowDegrees / 90) % 2 == 0) {
minScale = horizontal_minScale;
if (needScale) {
saveScale = (crop_width - max_crop_in_padding) / crop_width;
}
}
}
noScaleTranslateToFitEdge(false);
if (!smooth) {
bOnTouchEnable = true;
invalidate();
}
}
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
public boolean onScaleBegin(ScaleGestureDetector detector) {
mode = ZOOM;
return true;
}
public boolean onScale(ScaleGestureDetector detector) {
float mScaleFactor = (float) Math.min(Math.max(.85f, detector.getScaleFactor()), 1.15);
setZoomScale(mScaleFactor, detector.getFocusX(), detector.getFocusY());
return true;
}
public void onScaleEnd(ScaleGestureDetector detector) {
// noScaleTranslateToFitEdge(false);
}
}
public Bitmap getCropImage() {
Bitmap rectBitmap = null;
try {
Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
rectBitmap = Bitmap.createBitmap(bitmap, padding, padding, (int) crop_width, (int) crop_height);
Canvas canvas = new Canvas(rectBitmap);
canvas.drawColor(Color.TRANSPARENT);
draw(canvas);
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
bitmap = null;
}
} catch (OutOfMemoryError err) {
System.gc();
rectBitmap = null;
} catch (Exception e) {
rectBitmap = null;
}
return rectBitmap;
}
public Bitmap getCropImage(int BgColor) {
Bitmap rectBitmap = null;
try {
Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
rectBitmap = Bitmap.createBitmap(bitmap, padding, padding, (int) crop_width, (int) crop_height);
Canvas canvas = new Canvas(rectBitmap);
canvas.drawColor(BgColor);
draw(canvas);
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
}
} catch (OutOfMemoryError err) {
System.gc();
rectBitmap = null;
} catch (Exception e) {
rectBitmap = null;
}
return rectBitmap;
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
view_width = MeasureSpec.getSize(widthMeasureSpec);
view_height = MeasureSpec.getSize(heightMeasureSpec);
}
private static class UiHandler extends Handler {
private final WeakReference<Activity> mActivity;
private final CropPhotoView mCropPhotoView;
public UiHandler(Activity activity, CropPhotoView cropPhotoView) {
this.mActivity = new WeakReference<Activity>(activity);
this.mCropPhotoView = cropPhotoView;
}
public void handleMessage(Message msg) {
Activity activity = mActivity.get();
if (activity != null) {
switch (msg.what) {
case CropPhotoView.UI_MOVE_ANIME_START:
mCropPhotoView.bOnTouchEnable = false;
if (mCropPhotoView.step_count_move_xy < mCropPhotoView.step_total_count_move_xy) {
mCropPhotoView.matrix.postTranslate(mCropPhotoView.one_step_move_x, mCropPhotoView.one_step_move_y);
mCropPhotoView.mUIHandler.sendEmptyMessageDelayed(UI_MOVE_ANIME_START, mCropPhotoView.move_xy_speed);
mCropPhotoView.step_count_move_xy++;
} else {
mCropPhotoView.mUIHandler.sendEmptyMessageDelayed(UI_MOVE_ANIME_STOP, 0);
}
mCropPhotoView.invalidate();
break;
case CropPhotoView.UI_MOVE_ANIME_STOP:
mCropPhotoView.invalidate();
mCropPhotoView.mUIHandler.removeMessages(UI_MOVE_ANIME_START);
mCropPhotoView.mUIHandler.removeMessages(UI_MOVE_ANIME_STOP);
mCropPhotoView.noScaleTranslateToFitEdge(false);
mCropPhotoView.bOnTouchEnable = true;
break;
case CropPhotoView.UI_ROTATE_ANIME_START:
mCropPhotoView.bOnTouchEnable = false;
if (mCropPhotoView.to_degrees >= 0) {
if (mCropPhotoView.step_count_degrees < mCropPhotoView.to_degrees) {
mCropPhotoView.matrix.postRotate(mCropPhotoView.one_step_degrees, mCropPhotoView.view_width / 2, mCropPhotoView.view_height / 2); // 要旋转的角度
mCropPhotoView.mUIHandler.sendEmptyMessageDelayed(UI_ROTATE_ANIME_START, mCropPhotoView.rotate_speed);
} else {
mCropPhotoView.matrix.postRotate(mCropPhotoView.to_degrees - mCropPhotoView.step_count_degrees, mCropPhotoView.view_width / 2, mCropPhotoView.view_height / 2); // 要旋转的角度
mCropPhotoView.mUIHandler.sendEmptyMessageDelayed(UI_ROTATE_ANIME_STOP, 0);
}
mCropPhotoView.step_count_degrees++;
} else {
if (mCropPhotoView.step_count_degrees > mCropPhotoView.to_degrees) {
mCropPhotoView.matrix.postRotate(-mCropPhotoView.one_step_degrees, mCropPhotoView.view_width / 2, mCropPhotoView.view_height / 2); // 要旋转的角度
mCropPhotoView.mUIHandler.sendEmptyMessageDelayed(UI_ROTATE_ANIME_START, mCropPhotoView.rotate_speed);
} else {
mCropPhotoView.matrix.postRotate(mCropPhotoView.to_degrees - mCropPhotoView.step_count_degrees, mCropPhotoView.view_width / 2, mCropPhotoView.view_height / 2); // 要旋转的角度
mCropPhotoView.mUIHandler.sendEmptyMessageDelayed(UI_ROTATE_ANIME_STOP, 0);
}
mCropPhotoView.step_count_degrees--;
}
mCropPhotoView.invalidate();
break;
case CropPhotoView.UI_ROTATE_ANIME_STOP:
mCropPhotoView.invalidate();
mCropPhotoView.mUIHandler.removeMessages(UI_ROTATE_ANIME_START);
mCropPhotoView.mUIHandler.removeMessages(UI_ROTATE_ANIME_STOP);
mCropPhotoView.noScaleTranslateToFitEdge(false);
mCropPhotoView.bOnTouchEnable = true;
break;
default:
break;
}
}
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
recycleBitmap();
}
public void recycleBitmap() {
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
bitmap = null;
}
}
public void addTouchListener(OnTouchListener onTouchListener) {
this.onTouchListener = onTouchListener;
}
private void showAdjustParam() {
AppLog.e("CROP", "-------showAdjustParam-------");
AppLog.e("CROP", "centerOffsetX:" + mAdjustParam.centerOffset.offsetX);
AppLog.e("CROP", "centerOffsetY:" + mAdjustParam.centerOffset.offsetY);
AppLog.e("CROP", "zoomScale:" + mAdjustParam.zoomScale);
AppLog.e("CROP", "rotateScale:" + mAdjustParam.rotateScale);
AppLog.e("CROP", "mNowDegrees:" + mNowDegrees);
}
}
最后就是关键的KenBurnsView了
这个也没啥好说的直接贴代码吧,自己写了三天 现在都忘光光了
import android.content.Context;
import android.graphics.Bitmap;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.Switch;
import android.widget.TextView;
import com.wanyueliang.avm.R;
import com.wanyueliang.avm.config.AppConfig;
import com.wanyueliang.avm.model.databean.AdjustParam;
import com.wanyueliang.avm.model.databean.BitmapModel;
import com.wanyueliang.avm.utils.image.BitmapUtils;
import com.wanyueliang.avm.widget.crop_photo_view.CropPhotoView;
import static android.content.ContentValues.TAG;
public class KenBurnsView extends FrameLayout {
/*View*/
private KenBurnsRecyclerView rvRecyclerView;
private Switch shSwitch;
private Button btnPushTowards;
private Button btnZoomOut;
private ImageView ivDot1;
private ImageView ivDot2;
private TextView tvMoveTips;
/*Data*/
private Context mContext;
private ItemAdapter itemAdapter;
private static final String HAND_SCHEME = "hand_scheme";//手动模式
private static final String BOOST_SCHEME = "boost_scheme";//推进模式
private static final String ZOOMOUT_SCHEME = "zoomout_scheme";//拉远模式
private static final String NOTHING_SCHEME = "nothing_scheme";//无模式
private boolean isChangeMode;
private String zoomScale1;
private String zoomScale2;
private AdjustParam adjustParam1;//item1的参数
private AdjustParam adjustParam2;//item2的参数
private String path;
private Bitmap bitmap;
private int itemCount = 2;
private ItemAdapter.ItemViewHolder itemViewHolder1;
private ItemAdapter.ItemViewHolder itemViewHolder2;
private String rotateScale = "0";
private CompoundButton.OnCheckedChangeListener onCheckedChangeListener;
float outPutPhotoH = 0;
float outPutPhotoW = 0;
private int dmw;
private int dmh;
private Bitmap bgBitmap;
public KenBurnsView(Context context) {
this(context, null);
this.mContext = context;
}
public KenBurnsView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
this.mContext = context;
}
public KenBurnsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
DisplayMetrics dm = getResources().getDisplayMetrics();
dmw = dm.widthPixels; // 屏幕宽(像素,如:3200px)
dmh = dm.heightPixels; // 屏幕高(像素,如:1280px)
LayoutInflater.from(context).inflate(R.layout.ken_burns_view_rootview, this);
findView();
initView();
setListener();
}
private void initView() {
LinearLayoutManager manager = new LinearLayoutManager(mContext);
manager.setOrientation(LinearLayoutManager.HORIZONTAL);
rvRecyclerView.setLayoutManager(manager);
itemAdapter = new ItemAdapter();
rvRecyclerView.setAdapter(itemAdapter);
}
private void setMoveMode(String moveMode, int itemCount, boolean isTipShow, boolean isChangeMode, boolean isShowDot) {
rvRecyclerView.setMode(moveMode);
this.itemCount = itemCount;
this.isChangeMode = isChangeMode;
if (isTipShow) {
tvMoveTips.setVisibility(VISIBLE);
} else {
tvMoveTips.setVisibility(INVISIBLE);
}
if (isShowDot) {
ivDot1.setVisibility(VISIBLE);
ivDot2.setVisibility(VISIBLE);
ivDot1.setImageResource(R.drawable.ken_burns_view_viewpager_circle_selected);
ivDot2.setImageResource(R.drawable.ken_burns_view_viewpager_circle_normal);
} else {
ivDot1.setVisibility(INVISIBLE);
ivDot2.setVisibility(INVISIBLE);
}
rvRecyclerView.smoothScrollToPosition(0);
itemAdapter.notifyDataSetChanged();
}
private void setListener() {
btnPushTowards.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//点击后进入推进模式 该模式下从1.0倍数到1.2倍数 当缩放之后进入手动模式
if (path == null && bitmap == null) {
return;
}
adjustParam1 = new AdjustParam();
adjustParam1.zoomScale = String.valueOf(Double.valueOf(zoomScale1) * 1.0f);
adjustParam1.isAdjusted = "1";
adjustParam1.rotateScale = rotateScale;
adjustParam2 = new AdjustParam();
adjustParam2.zoomScale = String.valueOf(Double.valueOf(zoomScale2) * 1.2f);
adjustParam2.isAdjusted = "1";
adjustParam2.rotateScale = rotateScale;
itemViewHolder1.touchImageView.getAdjustParam().isAdjusted = "0";
if (onMatrixChangeListener != null) {
onMatrixChangeListener.adjustParamChange(adjustParam1);//设置1。0倍
}
setMoveMode(BOOST_SCHEME, 2, true, true, true);
}
});
btnZoomOut.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//点击后进入拉远模式 该模式下从1.2倍数到1.0倍数 当缩放之后进入手动模式
if (path == null && bitmap == null) {
return;
}
adjustParam1 = new AdjustParam();
adjustParam1.zoomScale = String.valueOf(Double.valueOf(zoomScale1) * 1.2f);
adjustParam1.isAdjusted = "1";
adjustParam1.rotateScale = rotateScale;
adjustParam2 = new AdjustParam();
adjustParam2.zoomScale = String.valueOf(Double.valueOf(zoomScale2) * 1.0f);
adjustParam2.isAdjusted = "1";
adjustParam2.rotateScale = rotateScale;
itemViewHolder1.touchImageView.getAdjustParam().isAdjusted = "0";
if (onMatrixChangeListener != null) {
onMatrixChangeListener.adjustParamChange(adjustParam1);//设置1。0倍
}
setMoveMode(ZOOMOUT_SCHEME, 2, true, true, true);
}
});
rvRecyclerView.setOnDotChangeListener(new KenBurnsRecyclerView.OnDotChangeListener() {
@Override
public void change(int position) {
if (position == 0) {
ivDot1.setImageResource(R.drawable.ken_burns_view_viewpager_circle_selected);
ivDot2.setImageResource(R.drawable.ken_burns_view_viewpager_circle_normal);
} else if (position == 1) {
ivDot1.setImageResource(R.drawable.ken_burns_view_viewpager_circle_normal);
ivDot2.setImageResource(R.drawable.ken_burns_view_viewpager_circle_selected);
}
}
});
shSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
//开关打开此时显示推进和拉远
//开关打开的时候item2的参数和item1的参数一致
btnPushTowards.setVisibility(VISIBLE);
btnZoomOut.setVisibility(VISIBLE);
adjustParam2 = itemViewHolder1.touchImageView.getAdjustParam().copyAdjustParam(adjustParam2);
setMoveMode(HAND_SCHEME, 2, true, true, true);
} else {
//开关关闭的时候item1的参数保留成现在的原状态
btnPushTowards.setVisibility(INVISIBLE);
btnZoomOut.setVisibility(INVISIBLE);
adjustParam1 = itemViewHolder1.touchImageView.getAdjustParam();
adjustParam1.isAdjusted = "1";
if (onMatrixChangeListener != null) {
onMatrixChangeListener.adjustParamChange(adjustParam1);//设置1。0倍
}
setMoveMode(NOTHING_SCHEME, 1, false, true, false);
}
if (onCheckedChangeListener != null) {
onCheckedChangeListener.onCheckedChanged(buttonView, isChecked);
}
}
});
}
public void setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener onCheckedChangeListener) {
this.onCheckedChangeListener = onCheckedChangeListener;
}
private void findView() {
btnPushTowards = (Button) findViewById(R.id.btn_push_towards);
btnZoomOut = (Button) findViewById(R.id.btn_zoom_out);
rvRecyclerView = (KenBurnsRecyclerView) findViewById(R.id.rv_recyclerView);
ivDot1 = (ImageView) findViewById(R.id.iv_dot_1);
ivDot2 = (ImageView) findViewById(R.id.iv_dot_2);
tvMoveTips = (TextView) findViewById(R.id.tv_move_tips);
shSwitch = (Switch) findViewById(R.id.sh_switch);
rvRecyclerView.setMode(HAND_SCHEME);
tvMoveTips.setVisibility(VISIBLE);
}
public void setUrl(String path) {
this.path = path;
}
public void setBitmapResource(Bitmap bitmap) {
this.bitmap = bitmap;
}
public void setBgBitmap(Bitmap bgBitmap) {
this.bgBitmap = bgBitmap;
}
public void setAdjustParam(AdjustParam adajustParam, boolean isUpdate2) {
//给第一个item的图设置AdjustParam
Log.i(TAG, "setAdjustParam: adajustParam" + adajustParam);
if (itemViewHolder1 != null) {
rvRecyclerView.smoothScrollToPosition(0);
adjustParam1 = adajustParam;
adjustParam1.rotateScale = rotateScale;
if (isUpdate2 && adjustParam2 != null) {
// adjustParam2 = new AdjustParam();
adjustParam2.rotateScale = rotateScale;
adjustParam2.isAdjusted = "1";
}
isChangeMode = true;
ivDot1.setImageResource(R.drawable.ken_burns_view_viewpager_circle_selected);
ivDot2.setImageResource(R.drawable.ken_burns_view_viewpager_circle_normal);
itemAdapter.notifyDataSetChanged();
}
}
public AdjustParam getAdjustParam1() {
return itemViewHolder1.touchImageView.getAdjustParam();
}
public AdjustParam getAdjustParam2() {
return itemViewHolder2.touchImageView.getAdjustParam();
}
public Float getStartZoomScale1() {
return Float.valueOf(zoomScale1);
}
public Float getStartZoomScale2() {
return Float.valueOf(zoomScale2);
}
public void setRotate(String rotateScale) {
this.rotateScale = rotateScale;
}
private class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ItemViewHolder> {
@Override
public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.ken_burns_view_rv_root, parent, false);
return new ItemViewHolder(view);
}
@Override
public void onBindViewHolder(final ItemViewHolder holder, final int position) {
BitmapModel bitmapModel = null;
if (bitmap == null) {
if (path == null) {
return;
}
bitmapModel = BitmapUtils.readBitmapModel(path, AppConfig.CROP_PHOTO_BIG_OUTPUT_SIZE_PARAM);
outPutPhotoW = Float.parseFloat(bitmapModel.mediaWidth);
outPutPhotoH = Float.parseFloat(bitmapModel.mediaHeight);
} else {
outPutPhotoW = Float.parseFloat(String.valueOf(bitmap.getWidth()));
outPutPhotoH = Float.parseFloat(String.valueOf(bitmap.getHeight()));
}
if (bitmapModel != null && bitmapModel.bitmap != null) {
setItemBitmap(holder, position, bitmapModel.bitmap, outPutPhotoW, outPutPhotoH);
} else {
if (bitmap == null) {
return;
}
setItemBitmap(holder, position, bitmap, outPutPhotoW, outPutPhotoH);
}
if (bgBitmap != null && !bgBitmap.isRecycled()) {
holder.mIvBg.setImageBitmap(bgBitmap);
} else {
holder.mIvBg.setImageResource(R.color.black);
}
holder.touchImageView.setOnMovingListener(new CropPhotoView.OnMovingListener() {
@Override
public void onMoving() {
if (onMatrixChangeListener != null) {
if (position == 0) {
adjustParam1.isAdjusted = "1";
onMatrixChangeListener.adjustParamChange(itemViewHolder1.touchImageView.getAdjustParam());
}
}
}
});
if (position == 0) {
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) holder.kenBurnsRoot.getLayoutParams();
layoutParams.rightMargin = (int) getResources().getDimension(R.dimen.x15);
holder.kenBurnsRoot.setLayoutParams(layoutParams);
} else {
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) holder.kenBurnsRoot.getLayoutParams();
layoutParams.leftMargin = (int) getResources().getDimension(R.dimen.x15);
layoutParams.rightMargin = (int) getResources().getDimension(R.dimen.x58);
holder.kenBurnsRoot.setLayoutParams(layoutParams);
}
}
//如果是推进模式 position 0 1.0倍数, position 1 1.2 倍数
//如果是拉远模式 position 0 1.2倍数, position 1 1.0倍数
private void setItemBitmap(ItemViewHolder holder, int position, Bitmap bitmap, float outPutPhotoW, float outPutPhotoH) {
if (position == 0) {
itemViewHolder1 = holder;
if (adjustParam1 == null) {
adjustParam1 = holder.touchImageView.getAdjustParam();
}
holder.touchImageView.setBitmap(true, bitmap, 0, adjustParam1, outPutPhotoW, outPutPhotoH);
if (!isChangeMode) {
zoomScale1 = holder.touchImageView.getAdjustParam().zoomScale;
}
} else {
itemViewHolder2 = holder;
if (adjustParam2 == null) {
adjustParam2 = holder.touchImageView.getAdjustParam();
}
holder.touchImageView.setBitmap(true, bitmap, 0, adjustParam2, outPutPhotoW, outPutPhotoH);
if (!isChangeMode) {
zoomScale2 = holder.touchImageView.getAdjustParam().zoomScale;
}
}
}
@Override
public int getItemCount() {
return itemCount;
}
class ItemViewHolder extends RecyclerView.ViewHolder {
CropPhotoView touchImageView;
FrameLayout kenBurnsRoot;
ImageView mIvBg;
ItemViewHolder(View itemView) {
super(itemView);
touchImageView = (CropPhotoView) itemView.findViewById(R.id.touchImageView);
kenBurnsRoot = (FrameLayout) itemView.findViewById(R.id.ken_burns_root);
mIvBg = (ImageView) itemView.findViewById(R.id.iv_bg);
}
}
}
private OnMatrixChangeListener onMatrixChangeListener;
public void setOnMatrixChangeListener(OnMatrixChangeListener onMatrixChangeListener) {
this.onMatrixChangeListener = onMatrixChangeListener;
}
public interface OnMatrixChangeListener {
void adjustParamChange(AdjustParam adjustParam);
}
}
最后就是实现动画了
import android.content.Context;
import android.view.animation.Animation;
import com.wanyueliang.avm.R;
import com.wanyueliang.avm.model.databean.AdjustParam;
import com.wanyueliang.avm.ui.main.utils.TransitionsAnimation;
import com.wanyueliang.avm.widget.crop_photo_view.CropPhotoView;
public class KenBurnsManager {
public static Float zoomScale1 = null;
public static AdjustParam getCurrentFrame(KenBurnsView kenBurnsView, float totalTime, int progress, AdjustParam adjustParam) {
AdjustParam targetAdjustParam = new AdjustParam();
if (kenBurnsView != null) {
AdjustParam adjustParam1 = kenBurnsView.getAdjustParam1();
AdjustParam adjustParam2 = kenBurnsView.getAdjustParam2();
Float zoomScale1 = Float.parseFloat(adjustParam1.zoomScale);//item1的缩放系数
Float zoomScale2 = Float.parseFloat(adjustParam2.zoomScale);//item2的缩放系数
float zoomScale = (zoomScale2 - zoomScale1) / totalTime;
targetAdjustParam.zoomScale = String.valueOf(zoomScale * progress + zoomScale1);
float x1 = Float.parseFloat(adjustParam1.centerOffset.offsetX);
float x2 = Float.parseFloat(adjustParam2.centerOffset.offsetY);
float centerOffsetX = (x2 - x1) / totalTime;
targetAdjustParam.centerOffset.offsetX = String.valueOf(centerOffsetX * progress + x1);
float y1 = Float.parseFloat(adjustParam1.centerOffset.offsetX);
float y2 = Float.parseFloat(adjustParam2.centerOffset.offsetY);
float centerOffsetY = (y2 - y1) / totalTime;
targetAdjustParam.centerOffset.offsetY = String.valueOf(centerOffsetY * progress + y1);
} else {
if (zoomScale1 == null) {
zoomScale1 = Float.parseFloat(adjustParam.zoomScale);//item1的缩放系数
}
Float zoomScale2 = zoomScale1 * 1.2f;//item2的缩放系数
float zoomScale = (zoomScale2 - zoomScale1) / totalTime;
targetAdjustParam.zoomScale = String.valueOf(zoomScale * progress + zoomScale1);
targetAdjustParam.centerOffset.offsetX = adjustParam.centerOffset.offsetX;
targetAdjustParam.centerOffset.offsetY = adjustParam.centerOffset.offsetY;
}
targetAdjustParam.isAdjusted = "1";
targetAdjustParam.turnY = adjustParam.turnY;
targetAdjustParam.rotateScale = adjustParam.rotateScale;
return targetAdjustParam;
}
public static void startPlayKenBurns(CropPhotoView cpvCropPhotoView, KenBurnsView kenBurnsView, Context mContext, Animation.AnimationListener listener) {
cpvCropPhotoView.clearAnimation();
TransitionsAnimation transitionsAnimation = new TransitionsAnimation(cpvCropPhotoView, null, 0, 0);//设置了时长之后,从这里传入动画播放的时长
final AdjustParam adjustParam1 = kenBurnsView.getAdjustParam1();
final AdjustParam adjustParam2 = kenBurnsView.getAdjustParam2();
Float zoomScale1 = Float.parseFloat(adjustParam1.zoomScale);//item1的缩放系数
Float zoomScale2 = Float.parseFloat(adjustParam2.zoomScale);//item2的缩放系数
float x1 = Float.parseFloat(adjustParam1.centerOffset.offsetX) * zoomScale2 / zoomScale1;//x1为在item1中x轴偏移量在item2中的x轴偏移量
float x2 = Float.parseFloat(adjustParam2.centerOffset.offsetX);//x2为item2中x轴偏移量
float y1 = Float.parseFloat(adjustParam1.centerOffset.offsetY) * zoomScale2 / zoomScale1;//y1为在item1中y轴偏移量在item2中的y轴的偏移量
float y2 = Float.parseFloat(adjustParam2.centerOffset.offsetY);//y2为item2中y轴的偏移量
float scale = mContext.getResources().getDimension(R.dimen.x375) / (float) 1920;//当前偏移量与实际偏移量的倍数
transitionsAnimation.startMoveZoomAnimation(1f, zoomScale2 / zoomScale1, x1, x2, y1, y2, scale, listener);
}
}
网友评论