Android 书本打开关闭动效
2019-03-28 本文已影响0人
reaiya
先上效果图:
Video_20190327_111654_826.gif
封面类CoverView:
public class CoverView extends View {
private final static String TAG = "CoverView";
private static final int DEFAULT_DERATION = 600;
private Bitmap mBitmap,mContentBgBitmap;
private Matrix mMatrix,mContentBgMatrix;
private int mLeft,mTop,mRight,mBottom;
private int mParentWidth,mParentHeight,mPivotx,mPivoty;
private ActionCallBack mActionCallBack;
private int mDuration = DEFAULT_DERATION;
private ValueAnimator mValueAnimator;
public CoverView(Context context) {
this(context,null);
}
public CoverView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CoverView(Context context, @Nullable AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
initData();
}
public void setCol(int left,int top,int right,int bottom){
mLeft = left;
mTop = top;
mRight = right;
mBottom = bottom;
invalidate();
}
private void initData() {
mMatrix = new Matrix();
mMatrix.reset();
mContentBgMatrix = new Matrix();
mContentBgMatrix.reset();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(mBitmap != null && mContentBgBitmap != null) {
canvas.drawBitmap(mContentBgBitmap, mContentBgMatrix, null);
canvas.drawBitmap(mBitmap, mMatrix, null);
}
}
@Override
public void layout(int l, int t, int r, int b) {
super.layout(mLeft,mTop,mRight,mBottom);
}
public void openOrClose(final boolean isOpen){
final int width = mRight - mLeft;
final int height = mBottom - mTop;
final float[] src = {0,0,
width,0,
width, height,
0, height};
Log.d(TAG, "open: " + mParentWidth + "-" + width);
if(mParentWidth == width || mParentHeight == height){
return;
}
mPivotx = mLeft*width / (mParentWidth - width);
mPivoty = mTop*height / (mParentHeight - height);
final float scale = Math.max((float) mParentWidth/width,(float) mParentHeight/height);
mValueAnimator = ValueAnimator.ofInt(100);
mValueAnimator.setDuration(mDuration);
mValueAnimator.setInterpolator(new LinearInterpolator());
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int animatedValue = isOpen ? (int)animation.getAnimatedValue() : 100-(int)animation.getAnimatedValue();
float j = (scale-1)/100 * animatedValue;
mMatrix.reset();
int polyX = (int) (width * (1 - animatedValue/50f));
polyX = polyX == 0 ? 1 : polyX;
Log.d(TAG, "onAnimationUpdate: "+polyX);
float[] dst = {0,0,
polyX,-5*animatedValue,
polyX,height + 5*animatedValue,
0, height};
mMatrix.setPolyToPoly(src,0,dst,0,src.length >> 1);
mMatrix.postScale(1+j,1+j,mPivotx,mPivoty);
mContentBgMatrix.reset();
mContentBgMatrix.postScale(1+j,1+j,mPivotx,mPivoty);
invalidate();
if((int)animation.getAnimatedValue() == 100 && mActionCallBack != null){
if (isOpen) {
mActionCallBack.onOpened();
}else{
mActionCallBack.onClosed();
}
}
}
});
mValueAnimator.start();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if(mActionCallBack != null){
mActionCallBack = null;
}
if(mValueAnimator != null){
mValueAnimator.removeAllUpdateListeners();
}
}
public void setActionCallBack(ActionCallBack mActionCallBack) {
this.mActionCallBack = mActionCallBack;
}
public void setBitmap(Bitmap mBitmap) {
this.mBitmap = mBitmap;
}
public void setContentBgBitmap(Bitmap mBitmap) {
this.mContentBgBitmap = mBitmap;
}
public void setParentSize(int width, int height) {
this.mParentWidth = width;
this.mParentHeight = height;
}
public void setDuration(int mDuration) {
this.mDuration = mDuration;
}
public interface ActionCallBack{
void onOpened();
void onClosed();
}
}
打开或关闭书本方法
private void openBook(ImageView v, Bitmap bitmap) {
final WindowManager wm = ((WindowManager) getSystemService(WINDOW_SERVICE));
if(Build.VERSION.SDK_INT >= 26) {
wm.addView(mRootView,
new WindowManager.LayoutParams(WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_FULLSCREEN |
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSPARENT));
}else{
wm.addView(mRootView,
new WindowManager.LayoutParams(WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_FULLSCREEN |
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSPARENT));
}
final CoverView coverView = new CoverView(ThemeActivity.this);
int[] location = new int[2];
v.getLocationInWindow(location);
coverView.setCol(location[0], location[1], (location[0]+v.getWidth()),
(location[1]+v.getHeight()));
Point screenPoint = new Point();
getWindowManager().getDefaultDisplay().getRealSize(screenPoint);
coverView.setParentSize(screenPoint.x,screenPoint.y);
// DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
// coverView.setParentSize(displayMetrics.widthPixels,displayMetrics.heightPixels);
coverView.setDuration(600);
mRootView.removeAllViews();
mRootView.addView(coverView);
coverView.setActionCallBack(new CoverView.ActionCallBack() {
@Override
public void onOpened() {
coverView.openOrClose(false);
}
@Override
public void onClosed() {
wm.removeView(mRootView);
mIsClickable = true;
}
});
coverView.setBitmap(getBitmap(v.getDrawable()));
coverView.setContentBgBitmap(bitmap);
coverView.openOrClose(true);
}
原理:
使用Matrix对bitmap进行放大和自定义变换实现
需要注意的是8.0之后悬浮窗type要写TYPE_APPLICATION_OVERLAY
todo:
- 现在只是放大到窗口大小,不能自定义放大后的区域位置
- 可以不依靠window实现
写于2019-3-27