图片浏览
包括图片获取、缓存、显示、放大、缩小、拖动、旋转和切换功能。
布局
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.****.**.Projects.StationViewActivity">
<ImageView
android:id="@+id/imageViewStation"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="16dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_marginTop="16dp"
android:contentDescription="@string/gray_picture"
android:scaleType="matrix"
app:layout_constraintBottom_toTopOf="@+id/textViewStationName"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@android:color/background_light" />
<TextView
android:id="@+id/textViewStationName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/nothing"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</android.support.constraint.ConstraintLayout>
代码
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改变图片显示;
- 采用多点触摸放大、缩小,放大的时候滑动是拖动效果,不放大的时候是切换功能;
- 根据手机方向,旋转图片;
- 最开始是想限制拖动范围,后面没有找到好的方法就放弃;