Android 點選圖片放大展示 展示中可調節圖片的縮放顯示 圖片檢視器
阿新 • • 發佈:2019-02-08
1.首先需要初始化一個全域性常量
這個是常量的工具類
public final class GlobalConstant {
private static int DEVICE_WIDTH;
private static int DEVICE_HEIGHT;
private static float DEVICE_DENSITY;
public static void initDeviceInfo(Context context) {
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(metrics);
DEVICE_WIDTH = metrics.widthPixels;
DEVICE_HEIGHT = metrics.heightPixels;
DEVICE_DENSITY = metrics.density;
}
public static int getDeviceWidth() {
return DEVICE_WIDTH;
}
public static int getDeviceHeight() {
return DEVICE_HEIGHT;
}
public static float getDeviceDensity() {
return DEVICE_DENSITY;
}
}
初始化的方法就是在程式的Application類對的oncreat方法中執行
GlobalConstant.initDeviceInfo(this);
2.可縮放的ImageView
public class GestureImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener {
private static final String TAG = GestureImageView.class.getSimpleName();
private boolean isOnce = true;
//初始縮放值
private float currentScale;
private static int mWidth = GlobalConstant.getDeviceWidth();
private static int mHeight = GlobalConstant.getDeviceHeight();
private static int mDistance = (int) Math.sqrt((Math.pow(mWidth, 2) + Math.pow(mHeight, 2)));
private final float MAX_SCALE = 4.0f; // 修改這個值可以修改縮放最大值
private float MIN_SCALE;
private float[] mMatrixValues = new float[9];
private float[] initMatrixValues = new float[9];
private Matrix mMatrix = new Matrix();
private PointF scalePointF;
private PointF dragPointF;
private float preDistance = 0;
private static final int SCALE_RATE = 4;//修改此值用以修改縮放速率
public GestureImageView(Context context) {
super(context);
initImageAttribute();
}
public GestureImageView(Context context, AttributeSet attrs) {
super(context, attrs);
initImageAttribute();
}
public GestureImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initImageAttribute();
}
/**
* 初始化影象屬性
*/
private void initImageAttribute() {
setScaleType(ScaleType.MATRIX);
setFocusable(true);// 觸控事件開啟此引數用以搞事情
catchTouchEvent(true);
}
/**
* 是否捕獲touch事件
*
* @param flag true捕獲touch事件,false不捕獲
*/
public void catchTouchEvent(boolean flag) {
if (getParent() != null) {
getParent().requestDisallowInterceptTouchEvent(flag);
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
getViewTreeObserver().addOnGlobalLayoutListener(null);
}
}
@Override
public void setImageResource(int resId) {
super.setImageResource(resId);
adjustImageMatrix();
}
@Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
adjustImageMatrix();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
catchTouchEvent(true);
scalePointF = null;
preDistance = 0;
dragPointF = null;
break;
case MotionEvent.ACTION_MOVE:
if (event.getPointerCount() == 2) { //兩點觸控事件處理
handleScaleEvent(event);
}
if (event.getPointerCount() == 1) { //處理移動事件
handleDragEvent(event);
}
break;
case MotionEvent.ACTION_POINTER_UP:
if (event.getPointerCount() != 1) {
scalePointF = null;
preDistance = 0;
dragPointF = null;
}
break;
case MotionEvent.ACTION_UP:
dragPointF = null;
break;
default:
break;
}
return true;
}
/**
* 處理拖拽手勢
*
* @param event 觸控Event
*/
private void handleDragEvent(MotionEvent event) {
scalePointF = null;
if (dragPointF == null) {
dragPointF = new PointF(event.getX(), event.getY());
} else {
float x = event.getX();
float y = event.getY();
drag(x - dragPointF.x,
y - dragPointF.y);
dragPointF = new PointF(x, y);
}
}
/**
* 處理縮放手勢
*
* @param event 事件
*/
private void handleScaleEvent(MotionEvent event) {
dragPointF = null;
float fX = event.getX(0);
float fY = event.getY(0);
float sX = event.getX(1);
float sY = event.getY(1);
float distance = (float) Math.sqrt((Math.pow(fX - sX, 2) + Math.pow(fY - sY, 2)));
if (scalePointF == null) {
scalePointF = new PointF((fX + sX) / 2.0f, (fY + sY) / 2.0f);
preDistance = distance;
} else {
float scale = (distance - preDistance) / mDistance * SCALE_RATE;//修改這個值可以更改縮放速率
float judge = currentScale + scale;
scale = judge > MAX_SCALE || judge < MIN_SCALE ?
(judge > MAX_SCALE ? MAX_SCALE - currentScale : MIN_SCALE - currentScale) :
scale;
currentScale += scale;
scale(currentScale / (currentScale - scale), scalePointF);
}
preDistance = distance;
}
/**
* 根據影象矩形處理拖拽的X值
*
* @param rect 影象矩形
* @param dragX 拖拽的X值
* @return 處理以後dragX值
*/
private float handleDragX(RectF rect, float dragX) {
if (rect.left < 0 || rect.right > mWidth) { // 放大時,如果內容寬度大於螢幕,左右邊界不能出現黑邊
if (rect.left + dragX > 0) {
dragX = 0 - rect.left;
} else if (rect.right + dragX < mWidth) {
dragX = mWidth - rect.right;
}
} else {
dragX = 0;
}
return dragX;
}
/**
* 根據影象矩形處理拖拽的Y值
*
* @param rect 影象矩形
* @param dragY 拖拽的Y值
* @return 處理以後dragY值
*/
private float handleDragY(RectF rect, float dragY) {
if (rect.top <= 0 && rect.bottom >= mHeight) { // 放大時,如果內容寬度大於螢幕,左右邊界不能出現黑邊
if (rect.top + dragY > 0) {
dragY = 0 - rect.top;
} else if (rect.bottom + dragY < mHeight) {
dragY = mHeight - rect.bottom;
}
} else {
dragY = 0;
}
return dragY;
}
/**
* 拖拽imageView
*
* @param dragX X軸的移動距離
* @param dragY Y軸的移動距離
*/
private void drag(float dragX, float dragY) {
RectF rect = getImageRectF();
catchTouchEvent(canDrag(rect));
dragX = handleDragX(rect, dragX);
dragY = handleDragY(rect, dragY);
mMatrix.postTranslate(dragX, dragY);
setImageMatrix(mMatrix);
mMatrix.getValues(mMatrixValues);
}
/**
* 根據ImageView當前位置判斷是否可以拖拽
*
* @param currentRect 當前的矩形
* @return true可以拖拽,false不可以
*/
private boolean canDrag(RectF currentRect) {
RectF preRect = getInitialRectF();
boolean canDrag;
if (preRect.left > 0) {
canDrag = !(currentRect.left >= 0 || currentRect.right <= mWidth || (currentRect.left > 0 && currentScale == MAX_SCALE));
} else {
canDrag = !(currentRect.left == 0 || currentRect.right == mWidth);
}
return canDrag;
}
/**
* 獲取初始的影象矩形
*
* @return
*/
private RectF getInitialRectF() {
Matrix preMatrix1 = new Matrix();
preMatrix1.setValues(initMatrixValues);
return getImageRectF(preMatrix1);
}
/**
* 縮放時,處理邊緣不過界
*
* @param matrix 拷貝的矩陣
* @param scale 縮放比例
* @param f 縮放中心點
* @return 返回X座標的點
*/
private float handleScaleDragX(Matrix matrix, float scale, PointF f) {
matrix.postScale(scale, scale, f.x, mHeight / 2.0f);
RectF rect = getImageRectF(matrix); // 根據拷貝過後的矩陣計算得出的矩形
RectF preRect = getInitialRectF();
float x = f.x;
if (preRect.left > 0) { // 圖片初始矩形寬度小於螢幕寬度
x = rect.left > 0 || rect.right < mWidth ? mWidth / 2.0f : x;
} else {
x = rect.left > 0 ? 0 : (rect.right < mWidth ? mWidth : x);
}
return x;
}
/**
* 按照縮放比例和點進行縮放
*
* @param scale 縮放比例
* @param f 包含縮放中心點的PointF
*/
private void scale(float scale, PointF f) {
LogUtil.showLog("縮放的比率:scale", scale+"");
if (scale<=(float)1.00) {
scale=(float) 1.00;
}
Matrix matrix = new Matrix(mMatrix);
mMatrix.postScale(scale, scale, handleScaleDragX(matrix, scale, f), mHeight / 2.0f);
mMatrix.getValues(mMatrixValues);
// getImageRectF();
if (currentScale == MIN_SCALE) {// 縮放到初始位置,將圖片設定為初始位置,此處可以新增動畫,請隨意發揮。
mMatrix.setValues(initMatrixValues);
setImageMatrix(mMatrix);
}
Log.i(TAG, "currentScale = " + currentScale);
setImageMatrix(mMatrix);
}
/**
* 將影象調整到適合的位置
*/
private void adjustImageMatrix() {
Drawable d = getDrawable();
if (d == null) {
setImageResource(R.drawable.ic_launcher);
return;
}
int width = d.getIntrinsicWidth();
int height = d.getIntrinsicHeight();
float scale = 1.0f;
// 有3種情況,1、寬大於螢幕寬。2、高大於螢幕高。3、寬和高均大於螢幕,影象寬高均小於裝置的暫時不考慮
if (width > mWidth && height < mHeight) {
scale = mWidth * 1.0f / width;
}
if (height > mHeight && width < mWidth) {
scale = mHeight * 1.0f / height;
}
if (height > mHeight && width > mWidth) {
scale = Math.min(mWidth * 1.0f / width, mHeight * 1.0f / height);
}
currentScale = scale;
MIN_SCALE = scale;
mMatrix = new Matrix();
mMatrix.postTranslate((mWidth - width) / 2.0f, (mHeight - height) / 2.0f);
mMatrix.postScale(currentScale, currentScale, mWidth / 2.0f, mHeight / 2.0f);
mMatrix.getValues(mMatrixValues);
mMatrix.getValues(initMatrixValues);
setImageMatrix(mMatrix);
getImageRectF();
}
/**
* 返回Drawable的矩形
*
* @param matrix 拷貝出來的矩陣
* @return imageView矩形資料
*/
private RectF getImageRectF(Matrix matrix) {
RectF rect = new RectF();
Drawable d = getDrawable();
if (d != null) {
rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
matrix.mapRect(rect);
}
return rect;
}
/**
* 返回Drawable的矩形
*
* @return imageView矩形資料
*/
private RectF getImageRectF() {
RectF rect = new RectF();
Drawable d = getDrawable();
if (d != null) {
rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
mMatrix.mapRect(rect);
}
return rect;
}
@Override
public void onGlobalLayout() {
if (isOnce) {
isOnce = false;
adjustImageMatrix();
}
}
}
3.用於展示圖片的Activity
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
public class PhotoActivity extends Activity {
private ArrayList<GestureImageView> listViews = null;
private ViewPager pager;
private MyPageAdapter adapter;
public List<Bitmap> bmp = new ArrayList<Bitmap>();
public int max;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_photo);
for (int i = 0; i < Bimp.bmp.size(); i++) {
bmp.add(Bimp.bmp.get(i));
}
max = Bimp.max;
pager = (ViewPager) findViewById(R.id.viewpager);
pager.setOnPageChangeListener(pageChangeListener);
pager.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
for (int i = 0; i < bmp.size(); i++) {
initListViews(bmp.get(i));
}
adapter = new MyPageAdapter(listViews);// 構造adapter
pager.setAdapter(adapter);// 設定介面卡
Intent intent = getIntent();
int id = intent.getIntExtra("ID", 0);
pager.setCurrentItem(id);
}
@SuppressWarnings("deprecation")
private void initListViews(Bitmap bm) {
if (listViews == null)
listViews = new ArrayList<GestureImageView>();
GestureImageView img = new GestureImageView(this);// 構造textView物件
img.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
img.setBackgroundColor(0xff000000);
img.setImageBitmap(bm);
img.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.FILL_PARENT));
listViews.add(img);// 新增view
}
private OnPageChangeListener pageChangeListener = new OnPageChangeListener() {
public void onPageSelected(int arg0) {// 頁面選擇響應函式
}
public void onPageScrolled(int arg0, float arg1, int arg2) {// 滑動中。。。
}
public void onPageScrollStateChanged(int arg0) {// 滑動狀態改變
}
};
class MyPageAdapter extends PagerAdapter {
private ArrayList<GestureImageView> listViews;// content
private int size;// 頁數
public MyPageAdapter(ArrayList<GestureImageView> listViews) {// 建構函式
// 初始化viewpager的時候給的一個頁面
this.listViews = listViews;
size = listViews == null ? 0 : listViews.size();
}
public void setListViews(ArrayList<GestureImageView> listViews) {// 自己寫的一個方法用來新增資料
this.listViews = listViews;
size = listViews == null ? 0 : listViews.size();
}
public int getCount() {// 返回數量
return size;
}
public int getItemPosition(Object object) {
return POSITION_NONE;
}
public void destroyItem(View arg0, int arg1, Object arg2) {// 銷燬view物件
((ViewPager) arg0).removeView(listViews.get(arg1 % size));
}
public void finishUpdate(View arg0) {
}
public Object instantiateItem(View arg0, int arg1) {// 返回view物件
try {
((ViewPager) arg0).addView(listViews.get(arg1 % size), 0);
} catch (Exception e) {
LogUtil.showLogerror("執行instantiateItem方法時報錯:", e.toString());
}
return listViews.get(arg1 % size);
}
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
}
}
此Activity的佈局檔案是:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</android.support.v4.view.ViewPager>
</RelativeLayout>
4.主體都寫完了,接下來就是呼叫了
博主是這樣呼叫的。
Bitmap bm = Bimp.revitionImageSize(path);
//圖片的本地路徑
Bimp.bmp.add(bm);
Intent intent = new Intent(ctx,PhotoActivity.class);
intent.putExtra("ID", 0);
ctx.startActivity(intent);
後續,其實Bimp.bmp.add(bm);在這句程式碼裡再新增的時候,可以實現左右滑動來展示圖片,畢竟我們用的是ViewPager,但是博主在專案中展示的時候,需要實現微信的效果,還沒有構思出符合專案已有程式碼的邏輯,得加油啦。。。
5.此篇文章,我其實結合了在網上查詢的兩個Demo。
說什麼我都不能確定那兩個Demo的原始碼地址了,太對不起作者了,我已免費資源的方式放到這兩個網址中:
明天評論裡補這兩個Demo的地址,今天這資源我是傳不上去了。