从零开发一个完整的Android项目(九)——图片浏览

图片浏览

包括图片获取、缓存、显示、放大、缩小、拖动、旋转和切换功能。

布局




    

    

代码

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开发)