图片浏览 包括图片获取、缓存、显示、放大、缩小、拖动、旋转和切换功能。
布局
代码
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
import android.hardware.SensorManager;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.OrientationEventListener;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.****.**.Defines;
import com.example.****.**.Functions;
import com.example.****.**.HttpConnection;
import com.example.****.**.MainActivity;
import com.example.****.**.R;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
public class StationViewActivity extends AppCompatActivity {
private Menu mMenu;
private ImageView mImageViewStation;
private TextView mTextViewStationName;
private ProjectInfo projectInfo;
private String projectName;
private String stationName;
private float mPosX;
private float mPosY;
private PointF mid = new PointF();
private float oldDist = 1f;
private Matrix matrix = new Matrix();
private Matrix matrix1 = new Matrix();
private Matrix savedMatrix = new Matrix();
private boolean mLarger;
private float scaleTotal;
private float scale;
private int mOrientation;
private Rect viewRect;
private AlbumOrientationEventListener mAlbumOrientationEventListener;
Bitmap bitmap;
private static final int NONE = 0;
private static final int DRAG = 1;
private static final int ZOOM = 2;
int mode = NONE;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_station_view);
HttpConnection.getInstance().setHandler(mHandlerStation);
mLarger = false;
//新页面接收数据
Bundle bundle = this.getIntent().getExtras();
//接收name值
projectName = bundle.getString("project");
stationName = bundle.getString("station");
projectInfo = ProjectStations.getInstance().getProjectByName(projectName);
mTextViewStationName = (TextView) findViewById(R.id.textViewStationName);
mTextViewStationName.setText(stationName);
mImageViewStation = (ImageView) findViewById(R.id.imageViewStation);
mImageViewStation.post(new Runnable() {
@Override
public void run() {
viewRect = new Rect();
mImageViewStation.getGlobalVisibleRect(viewRect);
updatePic();
mAlbumOrientationEventListener =
new AlbumOrientationEventListener(getBaseContext(), SensorManager.SENSOR_DELAY_NORMAL);
if (mAlbumOrientationEventListener.canDetectOrientation()) {
mAlbumOrientationEventListener.enable();
}
}
});
// 实现放大、缩小、拖动和旋转
mImageViewStation.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
// 按下
case MotionEvent.ACTION_DOWN:
mPosX = event.getX();
mPosY = event.getY();
mode = DRAG;
savedMatrix.set(matrix);
break;
case MotionEvent.ACTION_POINTER_DOWN:
mode = ZOOM;
oldDist = spacing(event);
savedMatrix.set(matrix);
midPoint(mid, event);
break;
// 移动
case MotionEvent.ACTION_MOVE:
if (mode == ZOOM && bitmap != null) {
matrix1.set(savedMatrix);
float newDist = spacing(event);
scale = newDist / oldDist;
scale = scale * scaleTotal < 1 ? 1 / scaleTotal : scale;
scale = scale * scaleTotal > 5 ? 5 / scaleTotal : scale;
matrix1.postScale(scale, scale, mid.x, mid.y);
// 縮放
matrix.set(matrix1);
mImageViewStation.setImageMatrix(matrix);
} else if (mode == DRAG && mLarger) {
matrix1.set(savedMatrix);
float dx = event.getX() - mPosX;
float dy = event.getY() - mPosY;
matrix1.postTranslate(dx, dy);
// 平移
matrix.set(matrix1);
mImageViewStation.setImageMatrix(matrix);
}
break;
// 拿起
case MotionEvent.ACTION_UP:
if (mode == DRAG && !mLarger) {
if (event.getX() - mPosX > 0
&& Math.abs(event.getY() - mPosY) < 100) {// 向右
for (int i = 0;
i < projectInfo.stations.size();
++i) {
if (stationName.equals(projectInfo.stations.get(i).name)
&& i > 0) {
stationName = projectInfo.stations.get(i - 1).name;
mTextViewStationName.setText(stationName);
updatePic();
break;
}
}
} else if (event.getX() - mPosX < 0
&& Math.abs(event.getY() - mPosY) < 100) {// 向左
for (int i = 0;
i < projectInfo.stations.size();
++i) {
if (stationName.equals(projectInfo.stations.get(i).name)
&& i < projectInfo.stations.size() - 1) {
stationName = projectInfo.stations.get(i + 1).name;
mTextViewStationName.setText(stationName);
updatePic();
break;
}
}
} else if (event.getY() - mPosY > 0
&& Math.abs(event.getX() - mPosX) < 100) {// 向下} else if (event.getY() - mPosY < 0
&& Math.abs(event.getX() - mPosX) < 100) {// 向上}
} else if (mode == DRAG) {
////复位图片
//PointF p1=getLeftPointF();
//PointF p2=getRightPointF();
//
////左边界复位
//if(p1.x>0)
//matrix.postTranslate(-p1.x, 0);
////右边界复位
//if(p2.x < mImageViewStation.getWidth())
//matrix.postTranslate(mImageViewStation.getWidth() - p2.x, 0);
////上边界复位
//if (p1.y > 0) matrix.postTranslate(0, -p1.y);
////下边界复位
//if (p2.y < mImageViewStation.getHeight())
//matrix.postTranslate(0, mImageViewStation.getHeight() - p2.y);
////居中
//if(mImageViewStation.getHeight() > (p2.y - p1.y)) {
//float row = (mImageViewStation.getHeight() - (p2.y - p1.y)) / 2;
//matrix.postTranslate(0, row - p1.y);
//}
//if(mImageViewStation.getWidth() > (p2.x - p1.x)){
//float col = (mImageViewStation.getWidth() - (p2.x - p1.x)) / 2;
//matrix.postTranslate(col - p1.x, 0);
//}
//mImageViewStation.setImageMatrix(matrix);
}
break;
case MotionEvent.ACTION_POINTER_UP:
if (mode == ZOOM) {
scaleTotal *= scale;
if (scaleTotal == 1) {
float scale = (float) (viewRect.width() * 1.0 / bitmap.getWidth());
matrix = new Matrix();
matrix.postScale(scale, scale);
matrix.postTranslate(0, (viewRect.height() - bitmap.getHeight() * scale) / 2);
matrix.postRotate(360 - mOrientation, viewRect.width() / 2, viewRect.height() / 2);
// 旋轉
mImageViewStation.setImageMatrix(matrix);
scaleTotal = 1f;
}
mLarger = scaleTotal > 1;
}
mode = NONE;
break;
default:
break;
}
return true;
}
});
}@Override
protected void onDestroy() {
mAlbumOrientationEventListener.disable();
super.onDestroy();
}// 触碰两点间距离
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}// 取手势中心点
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}//获取图片的上坐标
private PointF getLeftPointF() {
float[] values = new float[9];
matrix.getValues(values);
float leftX = values[2];
float leftY = values[5];
return new PointF(leftX, leftY);
}//获取图片的下坐标
private PointF getRightPointF() {
Rect rectTemp = mImageViewStation.getDrawable().getBounds();
float[] values = new float[9];
matrix.getValues(values);
float leftX = values[2] + rectTemp.width() * values[0];
float leftY = values[5] + rectTemp.height() * values[4];
return new PointF(leftX, leftY);
}// 根据手机方向,旋转图片
private class AlbumOrientationEventListener extends OrientationEventListener {
public AlbumOrientationEventListener(Context context) {
super(context);
}public AlbumOrientationEventListener(Context context, int rate) {
super(context, rate);
}@Override
public void onOrientationChanged(int orientation) {
if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
return;
}//保证只返回四个方向
int newOrientation = ((orientation + 45) / 90 * 90) % 360;
if (newOrientation != mOrientation) {
//返回的mOrientation就是手机方向,为0°、90°、180°和270°中的一个
matrix.postRotate(mOrientation - newOrientation, viewRect.width() / 2, viewRect.height() / 2);
// 旋轉
mImageViewStation.setImageMatrix(matrix);
mOrientation = newOrientation;
}
}
}// 显示图片
private void updatePic() {
String filePath = this.getExternalCacheDir().getAbsolutePath() + "/"
+ projectName + "-" + stationName + ".jpg";
File file = new File(filePath);
if (file.exists()) {
bitmap = BitmapFactory.decodeFile(filePath);
float scale = (float) (viewRect.width() * 1.0 / bitmap.getWidth());
matrix = new Matrix();
matrix.postScale(scale, scale);
matrix.postTranslate(0, (viewRect.height() - bitmap.getHeight() * scale) / 2);
mImageViewStation.setImageBitmap(bitmap);
mImageViewStation.setImageMatrix(matrix);
scaleTotal = 1f;
} else {
HttpConnection.getInstance().Add(Defines.REQUEST_GET, Defines.INTERFACE_GET_GRAY,
projectName + "/" + stationName + "/");
Functions.showProgressDialog(StationViewActivity.this, getResources().getString(R.string.loading));
}
}// 保存Bitmap图片到本地
private void saveMyBitmap(Bitmap mBitmap, String path) {
File f = new File(path);
FileOutputStream fOut = null;
try {
fOut = new FileOutputStream(f);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fOut);
try {
if (fOut != null) {
fOut.flush();
fOut.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}// 保存通过HTTP通信获取的图片
private void setGrayPic(String strGrayPic) {
if (strGrayPic != null && !strGrayPic.equals("") && !strGrayPic.equals("success")) {
try {
byte[] byteGrayPic = strGrayPic.getBytes("ISO-8859-1");
Bitmap bitmap = BitmapFactory.decodeByteArray(byteGrayPic, 0, byteGrayPic.length);
String filePath = this.getExternalCacheDir().getAbsolutePath() + "/"
+ projectName + "-" + stationName + ".jpg";
saveMyBitmap(bitmap, filePath);
updatePic();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} else {
Resources res = getResources();
bitmap = BitmapFactory.decodeResource(res, R.drawable.****);
float scale = (float) (viewRect.width() * 1.0 / bitmap.getWidth());
matrix = new Matrix();
matrix.postScale(scale, scale);
matrix.postTranslate(0, (viewRect.height() - bitmap.getHeight() * scale) / 2);
mImageViewStation.setImageBitmap(bitmap);
mImageViewStation.setImageMatrix(matrix);
scaleTotal = 1f;
}
Functions.cancelProgressDialog();
}public Handler mHandlerStation = new Handler() {
public void handleMessage(Message msg) {
String strRecv = msg.getData().getString("Body");
switch (msg.what) {
case Defines.ERROR:
int statusCode = msg.getData().getInt("Status");
new android.support.v7.app.AlertDialog.Builder(StationViewActivity.this).setTitle(
getResources().getString(R.string.error) + "(Error code:" + String.valueOf(statusCode) + ")")
.setIcon(android.R.drawable.ic_dialog_info)
.setCancelable(false)
.setPositiveButton(getResources().getString(R.string.close), new DialogInterface.OnClickListener() {@Override
public void onClick(DialogInterface dialog, int which) {
// 点击“确认”后的操作
Intent intent = new Intent(StationViewActivity.this, MainActivity.class);
//传递退出所有Activity的Tag对应的布尔值为true
intent.putExtra("exist", true);
//启动BaseActivity
startActivity(intent);
}
}).show();
break;
case Defines.INTERFACE_GET_GRAY:
setGrayPic(strRecv);
break;
default:
break;
}
super.handleMessage(msg);
}
};
}
说明
- 实现了在不自定义ImageView的情况下,图片显示、放大、缩小、拖动、旋转和切换功能;
- 布局很简单,一个ImageView和一个TextView,ImageView设置android:scaleType="matrix",代码中通过设置matrix改变图片显示;
- 采用多点触摸放大、缩小,放大的时候滑动是拖动效果,不放大的时候是切换功能;
- 根据手机方向,旋转图片;
- 最开始是想限制拖动范围,后面没有找到好的方法就放弃;
推荐阅读
- Android开发|ViewPager自适应高度问题
- Android|Android 指定销毁一个Activity
- 【Android】简单图片浏览器
- 理解ButterKnife(自动生成绑定资源的代码)
- MAC下搭建Android Studio
- NestedScrollingParent 和NestedScrollingChild 实现嵌套滑动
- android用shape画一条横线
- 华为推送 的坑
- Duplicate class com.alipay.a.a.a found in modules classes.jar (:alipaySdk-15.6.2-20190416165036:) an