老规矩先来诉诉苦,为什么发布这篇文章呢 上一篇也说过了 单纯的是不想让刚进android的小白走那么多弯路,毕竟android迭代太快,我的进步还很小,感觉自己要被大时代淘汰,趁现在还没淘汰,努力帮一帮刚进这个行业的程序猿们,凑巧我也有这个需求,就发出来了!
不要觉得文章多 全部都是傻瓜式复制!!!
我可以很负责人的告诉你们,市场需要的是资深人才,目前看来我们这一行小白居多,缺大佬,导致一些公司招工的时候 工资一压再压话不多说,加油吧看我文章的各位!!!
没有运行时的效果 这个没办法 不能上传视频请谅解。
WebView加载本地html
private String html="<p>" +
"<xmp style=\\\"font-size:20px;font-family: generic-font;white-space: normal;\\\">" +
"\\t在Android应用程序中,如果组件的导出值在应用程序的清单文件中被明确标记为false,那么该组件将变为私有的。如果不指定组件的访问权限,那么,任何应用程序都可以访问该组件。</xmp></p><p><xmp style=" +
"\\\"font-size:20px;font-family: generic-font;white-space: normal;\\\">" +
"\\t只在应用程序内部使用的组件必须设置为非公开,以防受到其他应用程序的调用。若应用组件未设置exported属性:</xmp></p><p><xmp style=" +
"\\\"font-size:20px;font-family: generic-font;white-space: normal;\\\">\\t若应用组件未设置<intent-filter>标签,exported属性默认值为false,否则默认值为true。" +
"</xmp></p><p><xmp style=\\\"font-size:20px;font-family: generic-font;white-space: normal;\\\">" +
"\\t因此,私有组件(不存在对外交互)应该在AndroidManifest.xml文件中显式设置该组件的android:exported属性值为false,否则,可能会对外暴露内部接口," +
"若被恶意应用利用,则会造成组件信息泄露或发起拒绝服务攻击。</xmp></p><p><xmp style=\\\"font-size:20px;font-family: generic-font;white-space: normal;\\\">" +
"\\t需要注意的是,私有组件如果声明了<intent-filter>标签,即使显式设置exported属性为false,也是存在组件信息泄露的风险。如图1-1所示,假设组件A-1是私有组件" +
",应用程序A的某一组件根据组件A-1声明的行为X给组件A-1发送消息;若恶意应用程序B定义了公开组件B-1,并声明了和组件A-1相同的行为X,当应用A通过行为X发送敏感信息给组件A-1时," +
"会给用户弹出消息接收选择框,用户在不知情的情况下可能会选择组件B-1,导致恶意应用B接收到应用A发送的内部消息,造成信息泄露。" +"<img style='margin:10px' src='http://images.china-pub.com/ebook25001-30000/27518/zcover.jpg' width='100'/>"+"</xmp></p><p><xmp style=\\\"font-size:20px;font-family: generic-font;white-space: normal;\\\">";
/*
在这扩展一下WebView默认的是白色的如果跟背景不一样的话会很难看 这个是改变WebView的背景色
如果单独设置一个的话不会起作用 还有最重要的一点就是 在WebView控件加上背景透明的属性 这样才可以生效。
xml中加入android:background="@android:color/transparent"
*/
mWebView.setBackgroundColor(0);//设置背景色
mWebView.getBackground().setAlpha(0);
/**
如果是只加载html数据的话个人倾向用第二种 加载网址的话就需要第一种了
当时我写这个的时候上网找了很多 第一个方法的话当时好像是图片或者表格加载不出来
然后我换了第二种加载的方式加载出来的。这个大家可以实验一下 我当时加载的时候确实碰到了这样的问题。
*/
mWebView.loadData( html, "text/html", "utf-8");
mWebView.loadDataWithBaseURL(null, html, "text/html", "utf-8", null);
现在是拦截WebView中图片的点击事件
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return true;
}
});
//java回调js代码,不要忘了@JavascriptInterface这个注解,不然点击事件不起作用
mWebView.addJavascriptInterface(new JsCallJavaObj() {
@JavascriptInterface
@Override
public void showBigImg(String url) { //url是图片的url
/*这里我也没搞懂为什么加Handler 当时我写的时候 不加会崩溃掉
所以我在这里加上了handler 如果有的小伙伴加hanlder不行的话 那就去掉
我项目中很多地方都用到了这个东西 这有这一个地方加了,不加如果不报错的话那就不需要加*/
mHandler.post(new Runnable() {
@Override
public void run() {
String imagePath;
/**
判断图片的url带不带http或者https
如果获取的url没有http或者https
就需要你自己使用自己的ip或者域名拼接上url
ip就是你请求接口时最前面的一部分比如说172.22.222.189:80/
域名也是你请求接口时最前面的一部分https:baidu.zxc/
*/
if (url.contains("http")){
imagePath = url;
}else {
imagePath = ip或者域名 + url;
}
//布局的话我会贴到最下面
View inflate = getLayoutInflater().inflate(R.layout.range_click_image_dialog, null);
//展示在dialog上面的大图PhotoView是自定义的手势放大缩小类
PhotoView dialogImg = inflate.findViewById(R.id.range_click_img);
Button xuanzhaun = inflate.findViewById(R.id.xuanzhuan);
//ComponentDialog是我自定义的弹框
mComponentDialog = new ComponentDialog(MainActivity.this, 0, 0, inflate, R.style.RangeFragment);
Glide.with(dialogImg).load(imagePath).fitCenter().into(dialogImg);
mComponentDialog.setCancelable(true);
mComponentDialog.create();
mComponentDialog.show();
//自定义View放大缩小 自定义View唯一的方法 只要调用他就可以手势放大缩小===傻瓜式
dialogImg.enable();
dialogImg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mComponentDialog.cancel();
}
});
//点击按钮进行旋转的数组 因为int类型不可以我用数组代替的
final int[] rota = {90};
xuanzhaun.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialogImg.setRotation(rota[0]);
rota[0] += 90;
}
});
}
});
}
},"jsCallJavaObj");
mWebView.setWebViewClient(new WebViewClient(){
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
setWebImageClick(view);
}
});
//截取webView图片点击
private void setWebImageClick(WebView view) {
String jsCode="javascript:(function(){" +
"var imgs=document.getElementsByTagName(\"img\");" +
"for(var i=0;i<imgs.length;i++){" +
"imgs[i].οnclick=function(){" +
"window.jsCallJavaObj.showBigImg(this.src);" +
"}}})()";
mWebView.loadUrl(jsCode);
}
//截取图片点击事件需要的回调接口
private interface JsCallJavaObj{
void showBigImg(String url);
}
//自定义弹框类
public class ComponentDialog extends Dialog {
public ComponentDialog(Context context, int width, int height, View layout, int style) {
super(context, style);
setContentView(layout);
Window window = getWindow();
WindowManager.LayoutParams params = window.getAttributes();
params.gravity = Gravity.CENTER;
window.setAttributes(params);
}
}
//自定义手势缩放的类 看着有点多 直接傻瓜式复制 中途可能会爆红 这个时候你就要自己搞一下了 都不复杂
@SuppressLint("AppCompatCustomView")
public class PhotoView extends ImageView {
private final static int MIN_ROTATE = 35;
private final static int ANIMA_DURING = 340;
private final static float MAX_SCALE = 2.5f;
private int mMinRotate;
private int mAnimaDuring;
private float mMaxScale;
private int MAX_OVER_SCROLL = 0;
private int MAX_FLING_OVER_SCROLL = 0;
private int MAX_OVER_RESISTANCE = 0;
private int MAX_ANIM_FROM_WAITE = 500;
private Matrix mBaseMatrix = new Matrix();
private Matrix mAnimaMatrix = new Matrix();
private Matrix mSynthesisMatrix = new Matrix();
private Matrix mTmpMatrix = new Matrix();
private RotateGestureDetector mRotateDetector;
private GestureDetector mDetector;
private ScaleGestureDetector mScaleDetector;
private OnClickListener mClickListener;
private ScaleType mScaleType;
private boolean hasMultiTouch;
private boolean hasDrawable;
private boolean isKnowSize;
private boolean hasOverTranslate;
private boolean isEnable = false;
private boolean isRotateEnable = false;
private boolean isInit;
private boolean mAdjustViewBounds;
// 当前是否处于放大状态
private boolean isZoonUp;
private boolean canRotate;
private boolean imgLargeWidth;
private boolean imgLargeHeight;
private float mRotateFlag;
private float mDegrees;
private float mScale = 1.0f;
private int mTranslateX;
private int mTranslateY;
private float mHalfBaseRectWidth;
private float mHalfBaseRectHeight;
private RectF mWidgetRect = new RectF();
private RectF mBaseRect = new RectF();
private RectF mImgRect = new RectF();
private RectF mTmpRect = new RectF();
private RectF mCommonRect = new RectF();
private PointF mScreenCenter = new PointF();
private PointF mScaleCenter = new PointF();
private PointF mRotateCenter = new PointF();
private Transform mTranslate = new Transform();
private RectF mClip;
private Info mFromInfo;
private long mInfoTime;
private Runnable mCompleteCallBack;
private OnLongClickListener mLongClick;
public PhotoView(Context context) {
super(context);
init();
}
public PhotoView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public PhotoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
super.setScaleType(ScaleType.MATRIX);
if (mScaleType == null) mScaleType = ScaleType.CENTER_INSIDE;
mRotateDetector = new RotateGestureDetector(mRotateListener);
mDetector = new GestureDetector(getContext(), mGestureListener);
mScaleDetector = new ScaleGestureDetector(getContext(), mScaleListener);
float density = getResources().getDisplayMetrics().density;
MAX_OVER_SCROLL = (int) (density * 30);
MAX_FLING_OVER_SCROLL = (int) (density * 30);
MAX_OVER_RESISTANCE = (int) (density * 140);
mMinRotate = MIN_ROTATE;
mAnimaDuring = ANIMA_DURING;
mMaxScale = MAX_SCALE;
}
/**
* 获取默认的动画持续时间
*/
public int getDefaultAnimaDuring() {
return ANIMA_DURING;
}
@Override
public void setOnClickListener(OnClickListener l) {
super.setOnClickListener(l);
mClickListener = l;
}
@Override
public void setScaleType(ScaleType scaleType) {
if (scaleType == ScaleType.MATRIX) return;
if (scaleType != mScaleType) {
mScaleType = scaleType;
if (isInit) {
initBase();
}
}
}
@Override
public void setOnLongClickListener(OnLongClickListener l) {
mLongClick = l;
}
/**
* 设置动画的插入器
*/
public void setInterpolator(DecelerateInterpolator interpolator) {
mTranslate.setInterpolator(interpolator);
}
/**
* 获取动画持续时间
*/
public int getAnimaDuring() {
return mAnimaDuring;
}
/**
* 设置动画的持续时间
*/
public void setAnimaDuring(int during) {
mAnimaDuring = during;
}
/**
* 设置最大可以缩放的倍数
*/
public void setMaxScale(float maxScale) {
mMaxScale = maxScale;
}
/**
* 获取最大可以缩放的倍数
*/
public float getMaxScale() {
return mMaxScale;
}
/**
* 启用缩放功能
*/
public void enable() {
isEnable = true;
}
/**
* 禁用缩放功能
*/
public void disenable() {
isEnable = false;
}
/**
* 启用旋转功能
*/
public void enableRotate() {
isRotateEnable = true;
}
/**
* 禁用旋转功能
*/
public void disableRotate() {
isRotateEnable = false;
}
/**
*/
public void setMaxAnimFromWaiteTime(int wait) {
MAX_ANIM_FROM_WAITE = wait;
}
@Override
public void setImageResource(int resId) {
Drawable drawable = null;
try {
drawable = getResources().getDrawable(resId);
} catch (Exception e) {
}
setImageDrawable(drawable);
}
@Override
public void setImageDrawable(Drawable drawable) {
super.setImageDrawable(drawable);
if (drawable == null) {
hasDrawable = false;
return;
}
if (!hasSize(drawable))
return;
if (!hasDrawable) {
hasDrawable = true;
}
initBase();
}
private boolean hasSize(Drawable d) {
if ((d.getIntrinsicHeight() <= 0 || d.getIntrinsicWidth() <= 0)
&& (d.getMinimumWidth() <= 0 || d.getMinimumHeight() <= 0)
&& (d.getBounds().width() <= 0 || d.getBounds().height() <= 0)) {
return false;
}
return true;
}
private static int getDrawableWidth(Drawable d) {
int width = d.getIntrinsicWidth();
if (width <= 0) width = d.getMinimumWidth();
if (width <= 0) width = d.getBounds().width();
return width;
}
private static int getDrawableHeight(Drawable d) {
int height = d.getIntrinsicHeight();
if (height <= 0) height = d.getMinimumHeight();
if (height <= 0) height = d.getBounds().height();
return height;
}
private void initBase() {
if (!hasDrawable) return;
if (!isKnowSize) return;
mBaseMatrix.reset();
mAnimaMatrix.reset();
isZoonUp = false;
Drawable img = getDrawable();
int w = getWidth();
int h = getHeight();
int imgw = getDrawableWidth(img);
int imgh = getDrawableHeight(img);
mBaseRect.set(0, 0, imgw, imgh);
// 以图片中心点居中位移
int tx = (w - imgw) / 2;
int ty = (h - imgh) / 2;
float sx = 1;
float sy = 1;
// 缩放,默认不超过屏幕大小
if (imgw > w) {
sx = (float) w / imgw;
}
if (imgh > h) {
sy = (float) h / imgh;
}
float scale = sx < sy ? sx : sy;
mBaseMatrix.reset();
mBaseMatrix.postTranslate(tx, ty);
mBaseMatrix.postScale(scale, scale, mScreenCenter.x, mScreenCenter.y);
mBaseMatrix.mapRect(mBaseRect);
mHalfBaseRectWidth = mBaseRect.width() / 2;
mHalfBaseRectHeight = mBaseRect.height() / 2;
mScaleCenter.set(mScreenCenter);
mRotateCenter.set(mScaleCenter);
executeTranslate();
switch (mScaleType) {
case CENTER:
initCenter();
break;
case CENTER_CROP:
initCenterCrop();
break;
case CENTER_INSIDE:
initCenterInside();
break;
case FIT_CENTER:
initFitCenter();
break;
case FIT_START:
initFitStart();
break;
case FIT_END:
initFitEnd();
break;
case FIT_XY:
initFitXY();
break;
}
isInit = true;
if (mFromInfo != null && System.currentTimeMillis() - mInfoTime < MAX_ANIM_FROM_WAITE) {
animaFrom(mFromInfo);
}
mFromInfo = null;
}
private void initCenter() {
if (!hasDrawable) return;
if (!isKnowSize) return;
Drawable img = getDrawable();
int imgw = getDrawableWidth(img);
int imgh = getDrawableHeight(img);
if (imgw > mWidgetRect.width() || imgh > mWidgetRect.height()) {
float scaleX = imgw / mImgRect.width();
float scaleY = imgh / mImgRect.height();
mScale = scaleX > scaleY ? scaleX : scaleY;
mAnimaMatrix.postScale(mScale, mScale, mScreenCenter.x, mScreenCenter.y);
executeTranslate();
resetBase();
}
}
private void initCenterCrop() {
if (mImgRect.width() < mWidgetRect.width() || mImgRect.height() < mWidgetRect.height()) {
float scaleX = mWidgetRect.width() / mImgRect.width();
float scaleY = mWidgetRect.height() / mImgRect.height();
mScale = scaleX > scaleY ? scaleX : scaleY;
mAnimaMatrix.postScale(mScale, mScale, mScreenCenter.x, mScreenCenter.y);
executeTranslate();
resetBase();
}
}
private void initCenterInside() {
if (mImgRect.width() > mWidgetRect.width() || mImgRect.height() > mWidgetRect.height()) {
float scaleX = mWidgetRect.width() / mImgRect.width();
float scaleY = mWidgetRect.height() / mImgRect.height();
mScale = scaleX < scaleY ? scaleX : scaleY;
mAnimaMatrix.postScale(mScale, mScale, mScreenCenter.x, mScreenCenter.y);
executeTranslate();
resetBase();
}
}
private void initFitCenter() {
if (mImgRect.width() < mWidgetRect.width()) {
mScale = mWidgetRect.width() / mImgRect.width();
mAnimaMatrix.postScale(mScale, mScale, mScreenCenter.x, mScreenCenter.y);
executeTranslate();
resetBase();
}
}
private void initFitStart() {
initFitCenter();
float ty = -mImgRect.top;
mAnimaMatrix.postTranslate(0, ty);
executeTranslate();
resetBase();
mTranslateY += ty;
}
private void initFitEnd() {
initFitCenter();
float ty = (mWidgetRect.bottom - mImgRect.bottom);
mTranslateY += ty;
mAnimaMatrix.postTranslate(0, ty);
executeTranslate();
resetBase();
}
private void initFitXY() {
float scaleX = mWidgetRect.width() / mImgRect.width();
float scaleY = mWidgetRect.height() / mImgRect.height();
mAnimaMatrix.postScale(scaleX, scaleY, mScreenCenter.x, mScreenCenter.y);
executeTranslate();
resetBase();
}
private void resetBase() {
Drawable img = getDrawable();
int imgw = getDrawableWidth(img);
int imgh = getDrawableHeight(img);
mBaseRect.set(0, 0, imgw, imgh);
mBaseMatrix.set(mSynthesisMatrix);
mBaseMatrix.mapRect(mBaseRect);
mHalfBaseRectWidth = mBaseRect.width() / 2;
mHalfBaseRectHeight = mBaseRect.height() / 2;
mScale = 1;
mTranslateX = 0;
mTranslateY = 0;
mAnimaMatrix.reset();
}
private void executeTranslate() {
mSynthesisMatrix.set(mBaseMatrix);
mSynthesisMatrix.postConcat(mAnimaMatrix);
setImageMatrix(mSynthesisMatrix);
mAnimaMatrix.mapRect(mImgRect, mBaseRect);
imgLargeWidth = mImgRect.width() > mWidgetRect.width();
imgLargeHeight = mImgRect.height() > mWidgetRect.height();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (!hasDrawable) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
Drawable d = getDrawable();
int drawableW = getDrawableWidth(d);
int drawableH = getDrawableHeight(d);
int pWidth = MeasureSpec.getSize(widthMeasureSpec);
int pHeight = MeasureSpec.getSize(heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int width = 0;
int height = 0;
ViewGroup.LayoutParams p = getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
if (p.width == ViewGroup.LayoutParams.MATCH_PARENT) {
if (widthMode == MeasureSpec.UNSPECIFIED) {
width = drawableW;
} else {
width = pWidth;
}
} else {
if (widthMode == MeasureSpec.EXACTLY) {
width = pWidth;
} else if (widthMode == MeasureSpec.AT_MOST) {
width = drawableW > pWidth ? pWidth : drawableW;
} else {
width = drawableW;
}
}
if (p.height == ViewGroup.LayoutParams.MATCH_PARENT) {
if (heightMode == MeasureSpec.UNSPECIFIED) {
height = drawableH;
} else {
height = pHeight;
}
} else {
if (heightMode == MeasureSpec.EXACTLY) {
height = pHeight;
} else if (heightMode == MeasureSpec.AT_MOST) {
height = drawableH > pHeight ? pHeight : drawableH;
} else {
height = drawableH;
}
}
if (mAdjustViewBounds && (float) drawableW / drawableH != (float) width / height) {
float hScale = (float) height / drawableH;
float wScale = (float) width / drawableW;
float scale = hScale < wScale ? hScale : wScale;
width = p.width == ViewGroup.LayoutParams.MATCH_PARENT ? width : (int) (drawableW * scale);
height = p.height == ViewGroup.LayoutParams.MATCH_PARENT ? height : (int) (drawableH * scale);
}
setMeasuredDimension(width, height);
}
@Override
public void setAdjustViewBounds(boolean adjustViewBounds) {
super.setAdjustViewBounds(adjustViewBounds);
mAdjustViewBounds = adjustViewBounds;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidgetRect.set(0, 0, w, h);
mScreenCenter.set(w / 2, h / 2);
if (!isKnowSize) {
isKnowSize = true;
initBase();
}
}
@Override
public void draw(Canvas canvas) {
if (mClip != null) {
canvas.clipRect(mClip);
mClip = null;
}
super.draw(canvas);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (isEnable) {
final int Action = event.getActionMasked();
if (event.getPointerCount() >= 2) hasMultiTouch = true;
mDetector.onTouchEvent(event);
if (isRotateEnable) {
mRotateDetector.onTouchEvent(event);
}
mScaleDetector.onTouchEvent(event);
if (Action == MotionEvent.ACTION_UP || Action == MotionEvent.ACTION_CANCEL) onUp();
return true;
} else {
return super.dispatchTouchEvent(event);
}
}
private void onUp() {
if (mTranslate.isRuning) return;
if (canRotate || mDegrees % 90 != 0) {
float toDegrees = (int) (mDegrees / 90) * 90;
float remainder = mDegrees % 90;
if (remainder > 45)
toDegrees += 90;
else if (remainder < -45)
toDegrees -= 90;
mTranslate.withRotate((int) mDegrees, (int) toDegrees);
mDegrees = toDegrees;
}
float scale = mScale;
if (mScale < 1) {
scale = 1;
mTranslate.withScale(mScale, 1);
} else if (mScale > mMaxScale) {
scale = mMaxScale;
mTranslate.withScale(mScale, mMaxScale);
}
float cx = mImgRect.left + mImgRect.width() / 2;
float cy = mImgRect.top + mImgRect.height() / 2;
mScaleCenter.set(cx, cy);
mRotateCenter.set(cx, cy);
mTranslateX = 0;
mTranslateY = 0;
mTmpMatrix.reset();
mTmpMatrix.postTranslate(-mBaseRect.left, -mBaseRect.top);
mTmpMatrix.postTranslate(cx - mHalfBaseRectWidth, cy - mHalfBaseRectHeight);
mTmpMatrix.postScale(scale, scale, cx, cy);
mTmpMatrix.postRotate(mDegrees, cx, cy);
mTmpMatrix.mapRect(mTmpRect, mBaseRect);
doTranslateReset(mTmpRect);
mTranslate.start();
}
private void doTranslateReset(RectF imgRect) {
int tx = 0;
int ty = 0;
if (imgRect.width() <= mWidgetRect.width()) {
if (!isImageCenterWidth(imgRect))
tx = -(int) ((mWidgetRect.width() - imgRect.width()) / 2 - imgRect.left);
} else {
if (imgRect.left > mWidgetRect.left) {
tx = (int) (imgRect.left - mWidgetRect.left);
} else if (imgRect.right < mWidgetRect.right) {
tx = (int) (imgRect.right - mWidgetRect.right);
}
}
if (imgRect.height() <= mWidgetRect.height()) {
if (!isImageCenterHeight(imgRect))
ty = -(int) ((mWidgetRect.height() - imgRect.height()) / 2 - imgRect.top);
} else {
if (imgRect.top > mWidgetRect.top) {
ty = (int) (imgRect.top - mWidgetRect.top);
} else if (imgRect.bottom < mWidgetRect.bottom) {
ty = (int) (imgRect.bottom - mWidgetRect.bottom);
}
}
if (tx != 0 || ty != 0) {
if (!mTranslate.mFlingScroller.isFinished()) mTranslate.mFlingScroller.abortAnimation();
mTranslate.withTranslate(mTranslateX, mTranslateY, -tx, -ty);
}
}
private boolean isImageCenterHeight(RectF rect) {
return Math.abs(Math.round(rect.top) - (mWidgetRect.height() - rect.height()) / 2) < 1;
}
private boolean isImageCenterWidth(RectF rect) {
return Math.abs(Math.round(rect.left) - (mWidgetRect.width() - rect.width()) / 2) < 1;
}
private OnRotateListener mRotateListener = new OnRotateListener() {
@Override
public void onRotate(float degrees, float focusX, float focusY) {
mRotateFlag += degrees;
if (canRotate) {
mDegrees += degrees;
mAnimaMatrix.postRotate(degrees, focusX, focusY);
} else {
if (Math.abs(mRotateFlag) >= mMinRotate) {
canRotate = true;
mRotateFlag = 0;
}
}
}
};
private ScaleGestureDetector.OnScaleGestureListener mScaleListener = new ScaleGestureDetector.OnScaleGestureListener() {
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scaleFactor = detector.getScaleFactor();
if (Float.isNaN(scaleFactor) || Float.isInfinite(scaleFactor))
return false;
mScale *= scaleFactor;
// mScaleCenter.set(detector.getFocusX(), detector.getFocusY());
mAnimaMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
executeTranslate();
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
}
};
private float resistanceScrollByX(float overScroll, float detalX) {
float s = detalX * (Math.abs(Math.abs(overScroll) - MAX_OVER_RESISTANCE) / (float) MAX_OVER_RESISTANCE);
return s;
}
private float resistanceScrollByY(float overScroll, float detalY) {
float s = detalY * (Math.abs(Math.abs(overScroll) - MAX_OVER_RESISTANCE) / (float) MAX_OVER_RESISTANCE);
return s;
}
/**
* 匹配两个Rect的共同部分输出到out,若无共同部分则输出0,0,0,0
*/
private void mapRect(RectF r1, RectF r2, RectF out) {
float l, r, t, b;
l = r1.left > r2.left ? r1.left : r2.left;
r = r1.right < r2.right ? r1.right : r2.right;
if (l > r) {
out.set(0, 0, 0, 0);
return;
}
t = r1.top > r2.top ? r1.top : r2.top;
b = r1.bottom < r2.bottom ? r1.bottom : r2.bottom;
if (t > b) {
out.set(0, 0, 0, 0);
return;
}
out.set(l, t, r, b);
}
private void checkRect() {
if (!hasOverTranslate) {
mapRect(mWidgetRect, mImgRect, mCommonRect);
}
}
private Runnable mClickRunnable = new Runnable() {
@Override
public void run() {
if (mClickListener != null) {
mClickListener.onClick(PhotoView.this);
}
}
};
private GestureDetector.OnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() {
@Override
public void onLongPress(MotionEvent e) {
if (mLongClick != null) {
mLongClick.onLongClick(PhotoView.this);
}
}
@Override
public boolean onDown(MotionEvent e) {
hasOverTranslate = false;
hasMultiTouch = false;
canRotate = false;
removeCallbacks(mClickRunnable);
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (hasMultiTouch) return false;
if (!imgLargeWidth && !imgLargeHeight) return false;
if (mTranslate.isRuning) return false;
float vx = velocityX;
float vy = velocityY;
if (Math.round(mImgRect.left) >= mWidgetRect.left || Math.round(mImgRect.right) <= mWidgetRect.right) {
vx = 0;
}
if (Math.round(mImgRect.top) >= mWidgetRect.top || Math.round(mImgRect.bottom) <= mWidgetRect.bottom) {
vy = 0;
}
if (canRotate || mDegrees % 90 != 0) {
float toDegrees = (int) (mDegrees / 90) * 90;
float remainder = mDegrees % 90;
if (remainder > 45)
toDegrees += 90;
else if (remainder < -45)
toDegrees -= 90;
mTranslate.withRotate((int) mDegrees, (int) toDegrees);
mDegrees = toDegrees;
}
doTranslateReset(mImgRect);
mTranslate.withFling(vx, vy);
mTranslate.start();
// onUp(e2);
return super.onFling(e1, e2, velocityX, velocityY);
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (mTranslate.isRuning) {
mTranslate.stop();
}
if (canScrollHorizontallySelf(distanceX)) {
if (distanceX < 0 && mImgRect.left - distanceX > mWidgetRect.left)
distanceX = mImgRect.left;
if (distanceX > 0 && mImgRect.right - distanceX < mWidgetRect.right)
distanceX = mImgRect.right - mWidgetRect.right;
mAnimaMatrix.postTranslate(-distanceX, 0);
mTranslateX -= distanceX;
} else if (imgLargeWidth || hasMultiTouch || hasOverTranslate) {
checkRect();
if (!hasMultiTouch) {
if (distanceX < 0 && mImgRect.left - distanceX > mCommonRect.left)
distanceX = resistanceScrollByX(mImgRect.left - mCommonRect.left, distanceX);
if (distanceX > 0 && mImgRect.right - distanceX < mCommonRect.right)
distanceX = resistanceScrollByX(mImgRect.right - mCommonRect.right, distanceX);
}
mTranslateX -= distanceX;
mAnimaMatrix.postTranslate(-distanceX, 0);
hasOverTranslate = true;
}
if (canScrollVerticallySelf(distanceY)) {
if (distanceY < 0 && mImgRect.top - distanceY > mWidgetRect.top)
distanceY = mImgRect.top;
if (distanceY > 0 && mImgRect.bottom - distanceY < mWidgetRect.bottom)
distanceY = mImgRect.bottom - mWidgetRect.bottom;
mAnimaMatrix.postTranslate(0, -distanceY);
mTranslateY -= distanceY;
} else if (imgLargeHeight || hasOverTranslate || hasMultiTouch) {
checkRect();
if (!hasMultiTouch) {
if (distanceY < 0 && mImgRect.top - distanceY > mCommonRect.top)
distanceY = resistanceScrollByY(mImgRect.top - mCommonRect.top, distanceY);
if (distanceY > 0 && mImgRect.bottom - distanceY < mCommonRect.bottom)
distanceY = resistanceScrollByY(mImgRect.bottom - mCommonRect.bottom, distanceY);
}
mAnimaMatrix.postTranslate(0, -distanceY);
mTranslateY -= distanceY;
hasOverTranslate = true;
}
executeTranslate();
return true;
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
postDelayed(mClickRunnable, 250);
return false;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
mTranslate.stop();
float from = 1;
float to = 1;
float imgcx = mImgRect.left + mImgRect.width() / 2;
float imgcy = mImgRect.top + mImgRect.height() / 2;
mScaleCenter.set(imgcx, imgcy);
mRotateCenter.set(imgcx, imgcy);
mTranslateX = 0;
mTranslateY = 0;
if (isZoonUp) {
from = mScale;
to = 1;
} else {
from = mScale;
to = mMaxScale;
mScaleCenter.set(e.getX(), e.getY());
}
mTmpMatrix.reset();
mTmpMatrix.postTranslate(-mBaseRect.left, -mBaseRect.top);
mTmpMatrix.postTranslate(mRotateCenter.x, mRotateCenter.y);
mTmpMatrix.postTranslate(-mHalfBaseRectWidth, -mHalfBaseRectHeight);
mTmpMatrix.postRotate(mDegrees, mRotateCenter.x, mRotateCenter.y);
mTmpMatrix.postScale(to, to, mScaleCenter.x, mScaleCenter.y);
mTmpMatrix.postTranslate(mTranslateX, mTranslateY);
mTmpMatrix.mapRect(mTmpRect, mBaseRect);
doTranslateReset(mTmpRect);
isZoonUp = !isZoonUp;
mTranslate.withScale(from, to);
mTranslate.start();
return false;
}
};
public boolean canScrollHorizontallySelf(float direction) {
if (mImgRect.width() <= mWidgetRect.width()) return false;
if (direction < 0 && Math.round(mImgRect.left) - direction >= mWidgetRect.left)
return false;
if (direction > 0 && Math.round(mImgRect.right) - direction <= mWidgetRect.right)
return false;
return true;
}
public boolean canScrollVerticallySelf(float direction) {
if (mImgRect.height() <= mWidgetRect.height()) return false;
if (direction < 0 && Math.round(mImgRect.top) - direction >= mWidgetRect.top)
return false;
if (direction > 0 && Math.round(mImgRect.bottom) - direction <= mWidgetRect.bottom)
return false;
return true;
}
@Override
public boolean canScrollHorizontally(int direction) {
if (hasMultiTouch) return true;
return canScrollHorizontallySelf(direction);
}
@Override
public boolean canScrollVertically(int direction) {
if (hasMultiTouch) return true;
return canScrollVerticallySelf(direction);
}
private class InterpolatorProxy extends Interpolator implements com.seclab.assistant.util.photoutil.InterpolatorProxy, android.view.animation.Interpolator {
private DecelerateInterpolator mTarget;
public InterpolatorProxy() {
super(10);
mTarget = new DecelerateInterpolator();
}
public void setTargetInterpolator(DecelerateInterpolator interpolator) {
mTarget = interpolator;
}
@Override
public float getInterpolation(float input) {
if (mTarget != null) {
return mTarget.getInterpolation(input);
}
return input;
}
}
private class Transform implements Runnable {
boolean isRuning;
OverScroller mTranslateScroller;
OverScroller mFlingScroller;
Scroller mScaleScroller;
Scroller mClipScroller;
Scroller mRotateScroller;
ClipCalculate C;
int mLastFlingX;
int mLastFlingY;
int mLastTranslateX;
int mLastTranslateY;
RectF mClipRect = new RectF();
InterpolatorProxy mInterpolatorProxy = new InterpolatorProxy();
Transform() {
Context ctx = getContext();
mTranslateScroller = new OverScroller(ctx, mInterpolatorProxy);
mScaleScroller = new Scroller(ctx, mInterpolatorProxy);
mFlingScroller = new OverScroller(ctx, mInterpolatorProxy);
mClipScroller = new Scroller(ctx, mInterpolatorProxy);
mRotateScroller = new Scroller(ctx, mInterpolatorProxy);
}
public void setInterpolator(DecelerateInterpolator interpolator) {
mInterpolatorProxy.setTargetInterpolator(interpolator);
}
void withTranslate(int startX, int startY, int deltaX, int deltaY) {
mLastTranslateX = 0;
mLastTranslateY = 0;
mTranslateScroller.startScroll(0, 0, deltaX, deltaY, mAnimaDuring);
}
void withScale(float form, float to) {
mScaleScroller.startScroll((int) (form * 10000), 0, (int) ((to - form) * 10000), 0, mAnimaDuring);
}
void withClip(float fromX, float fromY, float deltaX, float deltaY, int d, ClipCalculate c) {
mClipScroller.startScroll((int) (fromX * 10000), (int) (fromY * 10000), (int) (deltaX * 10000), (int) (deltaY * 10000), d);
C = c;
}
void withRotate(int fromDegrees, int toDegrees) {
mRotateScroller.startScroll(fromDegrees, 0, toDegrees - fromDegrees, 0, mAnimaDuring);
}
void withRotate(int fromDegrees, int toDegrees, int during) {
mRotateScroller.startScroll(fromDegrees, 0, toDegrees - fromDegrees, 0, during);
}
void withFling(float velocityX, float velocityY) {
mLastFlingX = velocityX < 0 ? Integer.MAX_VALUE : 0;
int distanceX = (int) (velocityX > 0 ? Math.abs(mImgRect.left) : mImgRect.right - mWidgetRect.right);
distanceX = velocityX < 0 ? Integer.MAX_VALUE - distanceX : distanceX;
int minX = velocityX < 0 ? distanceX : 0;
int maxX = velocityX < 0 ? Integer.MAX_VALUE : distanceX;
int overX = velocityX < 0 ? Integer.MAX_VALUE - minX : distanceX;
mLastFlingY = velocityY < 0 ? Integer.MAX_VALUE : 0;
int distanceY = (int) (velocityY > 0 ? Math.abs(mImgRect.top) : mImgRect.bottom - mWidgetRect.bottom);
distanceY = velocityY < 0 ? Integer.MAX_VALUE - distanceY : distanceY;
int minY = velocityY < 0 ? distanceY : 0;
int maxY = velocityY < 0 ? Integer.MAX_VALUE : distanceY;
int overY = velocityY < 0 ? Integer.MAX_VALUE - minY : distanceY;
if (velocityX == 0) {
maxX = 0;
minX = 0;
}
if (velocityY == 0) {
maxY = 0;
minY = 0;
}
mFlingScroller.fling(mLastFlingX, mLastFlingY, (int) velocityX, (int) velocityY, minX, maxX, minY, maxY, Math.abs(overX) < MAX_FLING_OVER_SCROLL * 2 ? 0 : MAX_FLING_OVER_SCROLL, Math.abs(overY) < MAX_FLING_OVER_SCROLL * 2 ? 0 : MAX_FLING_OVER_SCROLL);
}
void start() {
isRuning = true;
postExecute();
}
void stop() {
removeCallbacks(this);
mTranslateScroller.abortAnimation();
mScaleScroller.abortAnimation();
mFlingScroller.abortAnimation();
mRotateScroller.abortAnimation();
isRuning = false;
}
@Override
public void run() {
// if (!isRuning) return;
boolean endAnima = true;
if (mScaleScroller.computeScrollOffset()) {
mScale = mScaleScroller.getCurrX() / 10000f;
endAnima = false;
}
if (mTranslateScroller.computeScrollOffset()) {
int tx = mTranslateScroller.getCurrX() - mLastTranslateX;
int ty = mTranslateScroller.getCurrY() - mLastTranslateY;
mTranslateX += tx;
mTranslateY += ty;
mLastTranslateX = mTranslateScroller.getCurrX();
mLastTranslateY = mTranslateScroller.getCurrY();
endAnima = false;
}
if (mFlingScroller.computeScrollOffset()) {
int x = mFlingScroller.getCurrX() - mLastFlingX;
int y = mFlingScroller.getCurrY() - mLastFlingY;
mLastFlingX = mFlingScroller.getCurrX();
mLastFlingY = mFlingScroller.getCurrY();
mTranslateX += x;
mTranslateY += y;
endAnima = false;
}
if (mRotateScroller.computeScrollOffset()) {
mDegrees = mRotateScroller.getCurrX();
endAnima = false;
}
if (mClipScroller.computeScrollOffset() || mClip != null) {
float sx = mClipScroller.getCurrX() / 10000f;
float sy = mClipScroller.getCurrY() / 10000f;
mTmpMatrix.setScale(sx, sy, (mImgRect.left + mImgRect.right) / 2, C.calculateTop());
mTmpMatrix.mapRect(mClipRect, mImgRect);
if (sx == 1) {
mClipRect.left = mWidgetRect.left;
mClipRect.right = mWidgetRect.right;
}
if (sy == 1) {
mClipRect.top = mWidgetRect.top;
mClipRect.bottom = mWidgetRect.bottom;
}
mClip = mClipRect;
}
if (!endAnima) {
applyAnima();
postExecute();
} else {
isRuning = false;
// 修复动画结束后边距有些空隙,
boolean needFix = false;
if (imgLargeWidth) {
if (mImgRect.left > 0) {
mTranslateX -= mImgRect.left;
} else if (mImgRect.right < mWidgetRect.width()) {
mTranslateX -= (int) (mWidgetRect.width() - mImgRect.right);
}
needFix = true;
}
if (imgLargeHeight) {
if (mImgRect.top > 0) {
mTranslateY -= mImgRect.top;
} else if (mImgRect.bottom < mWidgetRect.height()) {
mTranslateY -= (int) (mWidgetRect.height() - mImgRect.bottom);
}
needFix = true;
}
if (needFix) {
applyAnima();
}
invalidate();
if (mCompleteCallBack != null) {
mCompleteCallBack.run();
mCompleteCallBack = null;
}
}
}
private void applyAnima() {
mAnimaMatrix.reset();
mAnimaMatrix.postTranslate(-mBaseRect.left, -mBaseRect.top);
mAnimaMatrix.postTranslate(mRotateCenter.x, mRotateCenter.y);
mAnimaMatrix.postTranslate(-mHalfBaseRectWidth, -mHalfBaseRectHeight);
mAnimaMatrix.postRotate(mDegrees, mRotateCenter.x, mRotateCenter.y);
mAnimaMatrix.postScale(mScale, mScale, mScaleCenter.x, mScaleCenter.y);
mAnimaMatrix.postTranslate(mTranslateX, mTranslateY);
executeTranslate();
}
private void postExecute() {
if (isRuning) post(this);
}
}
public Info getInfo() {
RectF rect = new RectF();
int[] p = new int[2];
getLocation(this, p);
rect.set(p[0] + mImgRect.left, p[1] + mImgRect.top, p[0] + mImgRect.right, p[1] + mImgRect.bottom);
return new Info(rect, mImgRect, mWidgetRect, mBaseRect, mScreenCenter, mScale, mDegrees, mScaleType);
}
public static Info getImageViewInfo(ImageView imgView) {
int[] p = new int[2];
getLocation(imgView, p);
Drawable drawable = imgView.getDrawable();
Matrix matrix = imgView.getImageMatrix();
int width = getDrawableWidth(drawable);
int height = getDrawableHeight(drawable);
RectF imgRect = new RectF(0, 0, width, height);
matrix.mapRect(imgRect);
RectF rect = new RectF(p[0] + imgRect.left, p[1] + imgRect.top, p[0] + imgRect.right, p[1] + imgRect.bottom);
RectF widgetRect = new RectF(0, 0, imgView.getWidth(), imgView.getHeight());
RectF baseRect = new RectF(widgetRect);
PointF screenCenter = new PointF(widgetRect.width() / 2, widgetRect.height() / 2);
return new Info(rect, imgRect, widgetRect, baseRect, screenCenter, 1, 0, imgView.getScaleType());
}
private static void getLocation(View target, int[] position) {
position[0] += target.getLeft();
position[1] += target.getTop();
ViewParent viewParent = target.getParent();
while (viewParent instanceof View) {
final View view = (View) viewParent;
if (view.getId() == android.R.id.content) return;
position[0] -= view.getScrollX();
position[1] -= view.getScrollY();
position[0] += view.getLeft();
position[1] += view.getTop();
viewParent = view.getParent();
}
position[0] = (int) (position[0] + 0.5f);
position[1] = (int) (position[1] + 0.5f);
}
private void reset() {
mAnimaMatrix.reset();
executeTranslate();
mScale = 1;
mTranslateX = 0;
mTranslateY = 0;
}
public interface ClipCalculate {
float calculateTop();
}
public class START implements ClipCalculate {
@Override
public float calculateTop() {
return mImgRect.top;
}
}
public class END implements ClipCalculate {
@Override
public float calculateTop() {
return mImgRect.bottom;
}
}
public class OTHER implements ClipCalculate {
@Override
public float calculateTop() {
return (mImgRect.top + mImgRect.bottom) / 2;
}
}
/**
* 在PhotoView内部还没有图片的时候同样可以调用该方法
* <p></p>
* 此时并不会播放动画,当给PhotoView设置图片后会自动播放动画。
* <p></p>
* 若等待时间过长也没有给控件设置图片,则会忽略该动画,若要再次播放动画则需要重新调用该方法
* (等待的时间默认500毫秒,可以通过setMaxAnimFromWaiteTime(int)设置最大等待时间)
*/
public void animaFrom(Info info) {
if (isInit) {
reset();
Info mine = getInfo();
float scaleX = info.mImgRect.width() / mine.mImgRect.width();
float scaleY = info.mImgRect.height() / mine.mImgRect.height();
float scale = scaleX < scaleY ? scaleX : scaleY;
float ocx = info.mRect.left + info.mRect.width() / 2;
float ocy = info.mRect.top + info.mRect.height() / 2;
float mcx = mine.mRect.left + mine.mRect.width() / 2;
float mcy = mine.mRect.top + mine.mRect.height() / 2;
mAnimaMatrix.reset();
// mAnimaMatrix.postTranslate(-mBaseRect.left, -mBaseRect.top);
mAnimaMatrix.postTranslate(ocx - mcx, ocy - mcy);
mAnimaMatrix.postScale(scale, scale, ocx, ocy);
mAnimaMatrix.postRotate(info.mDegrees, ocx, ocy);
executeTranslate();
mScaleCenter.set(ocx, ocy);
mRotateCenter.set(ocx, ocy);
mTranslate.withTranslate(0, 0, (int) -(ocx - mcx), (int) -(ocy - mcy));
mTranslate.withScale(scale, 1);
mTranslate.withRotate((int) info.mDegrees, 0);
if (info.mWidgetRect.width() < info.mImgRect.width() || info.mWidgetRect.height() < info.mImgRect.height()) {
float clipX = info.mWidgetRect.width() / info.mImgRect.width();
float clipY = info.mWidgetRect.height() / info.mImgRect.height();
clipX = clipX > 1 ? 1 : clipX;
clipY = clipY > 1 ? 1 : clipY;
ClipCalculate c = info.mScaleType == ScaleType.FIT_START ? new START() : info.mScaleType == ScaleType.FIT_END ? new END() : new OTHER();
mTranslate.withClip(clipX, clipY, 1 - clipX, 1 - clipY, mAnimaDuring / 3, c);
mTmpMatrix.setScale(clipX, clipY, (mImgRect.left + mImgRect.right) / 2, c.calculateTop());
mTmpMatrix.mapRect(mTranslate.mClipRect, mImgRect);
mClip = mTranslate.mClipRect;
}
mTranslate.start();
} else {
mFromInfo = info;
mInfoTime = System.currentTimeMillis();
}
}
public void animaTo(Info info, Runnable completeCallBack) {
if (isInit) {
mTranslate.stop();
mTranslateX = 0;
mTranslateY = 0;
float tcx = info.mRect.left + info.mRect.width() / 2;
float tcy = info.mRect.top + info.mRect.height() / 2;
mScaleCenter.set(mImgRect.left + mImgRect.width() / 2, mImgRect.top + mImgRect.height() / 2);
mRotateCenter.set(mScaleCenter);
// 将图片旋转回正常位置,用以计算
mAnimaMatrix.postRotate(-mDegrees, mScaleCenter.x, mScaleCenter.y);
mAnimaMatrix.mapRect(mImgRect, mBaseRect);
// 缩放
float scaleX = info.mImgRect.width() / mBaseRect.width();
float scaleY = info.mImgRect.height() / mBaseRect.height();
float scale = scaleX > scaleY ? scaleX : scaleY;
mAnimaMatrix.postRotate(mDegrees, mScaleCenter.x, mScaleCenter.y);
mAnimaMatrix.mapRect(mImgRect, mBaseRect);
mDegrees = mDegrees % 360;
mTranslate.withTranslate(0, 0, (int) (tcx - mScaleCenter.x), (int) (tcy - mScaleCenter.y));
mTranslate.withScale(mScale, scale);
mTranslate.withRotate((int) mDegrees, (int) info.mDegrees, mAnimaDuring * 2 / 3);
if (info.mWidgetRect.width() < info.mRect.width() || info.mWidgetRect.height() < info.mRect.height()) {
float clipX = info.mWidgetRect.width() / info.mRect.width();
float clipY = info.mWidgetRect.height() / info.mRect.height();
clipX = clipX > 1 ? 1 : clipX;
clipY = clipY > 1 ? 1 : clipY;
final float cx = clipX;
final float cy = clipY;
final ClipCalculate c = info.mScaleType == ScaleType.FIT_START ? new START() : info.mScaleType == ScaleType.FIT_END ? new END() : new OTHER();
postDelayed(new Runnable() {
@Override
public void run() {
mTranslate.withClip(1, 1, -1 + cx, -1 + cy, mAnimaDuring / 2, c);
}
}, mAnimaDuring / 2);
}
mCompleteCallBack = completeCallBack;
mTranslate.start();
}
}
public void rotate(float degrees) {
mDegrees += degrees;
int centerX = (int) (mWidgetRect.left + mWidgetRect.width() / 2);
int centerY = (int) (mWidgetRect.top + mWidgetRect.height() / 2);
mAnimaMatrix.postRotate(degrees, centerX, centerY);
executeTranslate();
}
}
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.seclab.assistant.util.photoutil.PhotoView
android:id="@+id/range_click_img"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerInside"/>
<Button
android:text="旋转"
android:id="@+id/xuanzhuan"
android:layout_width="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:layout_height="wrap_content"></Button>
</RelativeLayout>
//别忘了哦 dialog也需要释放的 我这里就不贴了
@Override
protected void onPause() {
super.onPause();
if (mHandler != null) {
mHandler.removeCallbacksAndMessages(null);
}
}
//这里有两个style都可以使用
<!-- 自定义对话框-->
<style name="DialogTheme" parent="@android:style/Theme.Dialog">
<!-- 边框 -->
<item name="android:windowFrame">@null</item>
<!-- 是否浮现在activity之上 -->
<item name="android:windowIsFloating">true</item>
<!-- 半透明 -->
<item name="android:windowIsTranslucent">true</item>
<!-- 无标题 -->
<item name="android:windowNoTitle">true</item>
<item name="android:background">@android:color/transparent</item>
<!-- 背景透明 -->
<item name="android:windowBackground">@android:color/transparent</item>
<!-- 模糊 -->
<item name="android:backgroundDimEnabled">true</item>
<!-- 遮罩层 -->
<item name="android:backgroundDimAmount">0.5</item>
</style>
<style name="FeedBackActivity" parent="AppTheme">
<item name="windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>
</style>
<style name="RangeFragment" parent="AppTheme">
<item name="windowNoTitle">true</item>
<!-- 背景透明 -->
<item name="android:windowBackground">@android:color/transparent</item>
<!-- 模糊 -->
<item name="android:backgroundDimEnabled">true</item>
<item name="android:windowFullscreen">true</item>
</style>
在这里说明一下
在这里给你们打个包票 肯定可以 如果不可以的话我是不会写这篇文章的 毕竟这个是我写的东西啊,我来口述一下效果吧 加载一个WebView点击图片出现一个dialog点击的图片显示到dialog上 可以根据手势放大缩小,点击旋转的时候图片进行旋转。如果想要炫酷的界面可以自己制定把我的界面换下来。
我一直都在的,因为我也一直因为需求找解决办法,如果有解决不了的可以来找我。也可以随时私信我,毕竟我还有很长的路要走,希望能收获到自己的第一个粉丝,嘿嘿~
如果帮助到你的话可以点点小心心和评论,不要质疑我代码的正确性 这些都是我自己的需求
只有我写出来才会发出来。
在这里还有个问题没解决 WebView加载图片在手机上会模糊,所以需要放大,放大我就忍了还要我旋转,旋转出来了还说旋转的时候把图片的高变成宽,宽变成高,我心态裂开 我就是在这个心态中写的这篇文章,我从来没见过app可以图片旋转,毕竟QQ微信都没有这个功能的,我还要继续去找,如果有做过的大佬,记得照顾一下小弟互相交流一下*.*。加油吧,同行们!!
这个是结合了两个项目写的,历经了两个小时,如需转载的话就标注本人谢谢!