app/src/main/java/com/sqh/market/activity/ShowImageActivity.java
<reponame>1278882181/for-android-pythonpackage com.sqh.market.activity;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.ProgressBar;

import com.sqh.market.R;
import com.sqh.market.callbacks.ImageActivityCallback;
import com.sqh.market.widget.MyImageView;

import org.apache.commons.lang3.StringUtils;

public class ShowImageActivity extends Activity implements View.OnTouchListener, View.OnClickListener {
    private float lastX[] = {0, 0};//用来记录上一次两个触点的横坐标
    private float lastY[] = {0, 0};//用来记录上一次两个触点的纵坐标

    private float windowWidth, windowHeight;//当前窗口的宽和高
    private float imageHeight, imageWidth;//imageview中图片的宽高（注意：不是imageview的宽和高）

    /**
     * 图片控件
     */
    private MyImageView imageView;

    /**
     * temp bitmap
     */
    private Bitmap bitmap = null;

    /**
     * 返回按钮
     */
    private ImageView mBtnBack;

    /**
     * 进度条
     */
    private ProgressBar mProgressBar;

    private static Matrix currentMatrix = new Matrix();//保存当前窗口显示的矩阵
    private Matrix touchMatrix, mmatrix;
    private boolean flag = false;//用来标记是否进行过移动前的首次点击
    private float moveLastX, moveLastY;//进行移动时用来记录上一个触点的坐标

    private static float max_scale = 4f;//缩放的最大值
    private static float min_scale = 0.8f;//缩放的最小值

    private ImageActivityCallback mCallback = new ImageActivityCallback() {
        @Override
        public void onSuccess() {
            uiHandler.sendEmptyMessage(1);
        }

        @Override
        public void onFail() {
            imageView.setImageDrawable(getDrawable(R.drawable.no_img));
        }

        @Override
        public void sendMessage(Object obj) {
            bitmap = (Bitmap) obj;
        }
    };

    /**
     * 修改ui用的handler
     */
    private Handler uiHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case -1:
                    //失败时
                    break;
                case 1:
                    //成功时
                    //成功时，将图片居中
                    center(bitmap);

                    //取消动画显示，显示Layout
                    mProgressBar.setVisibility(View.GONE);
                    imageView.setVisibility(View.VISIBLE);

                    break;
            }
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_show_image);
        //获取窗口的宽高
        WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        windowWidth = windowManager.getDefaultDisplay().getWidth();
        windowHeight = windowManager.getDefaultDisplay().getHeight();

        //初始化绑定控件
        init();

        //初始化ImageView
        initImageView(getIntent());

        //将图片居中
        center(bitmap);
    }

    /**
     * 初始化绑定控件
     */
    private void init() {
        imageView = findViewById(R.id.imageView);
        imageView.setOnTouchListener(this);
        mBtnBack = findViewById(R.id.img_back);
        mBtnBack.setOnClickListener(this);
        mProgressBar = findViewById(R.id.progress);
    }

    /**
     * 初始化ImageView控件
     *
     * @param intent 父页面传入的图片url
     */
    private void initImageView(Intent intent) {
        String imageUrl = intent.getStringExtra("imgUrl");
        if (StringUtils.isNotBlank(imageUrl)) {
            //如果图片url合法，则从网络地址加载图片
            imageView.setImageURL(imageUrl, mCallback);
        } else {
            //否则显示默认图片
        }
    }

    /**
     * 开始时将图片居中显示
     */
    private void center(Bitmap bitmap) {

        //获取imageView中图片的实际高度
        if (bitmap == null) {
            bitmap = ((BitmapDrawable) (imageView).getDrawable()).getBitmap();
        }

        imageHeight = bitmap.getHeight();
        imageWidth = bitmap.getWidth();

        //变换矩阵，使其移动到屏幕中央
        Matrix matrix = new Matrix();
        matrix.postTranslate(windowWidth / 2 - imageWidth / 2, windowHeight / 2 - imageHeight / 2);
        //保存到currentMatrix
        currentMatrix.set(matrix);
        imageView.setImageMatrix(matrix);
    }

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        //注意这一句的写法，用在多点触控中
        switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
            // 在这里解释一下，在程序中我们将单点控制移动和双点控制缩放区分开（但是双点也是可以
            // 控制移动的)flag 的作用很简单，主要是用在单点移动时判断是否此次点击是否将要移动（不好描述，请读者自行细想一下）
            // 否则容易与双点操作混乱在一起，给用户带来较差的用户体验

            case MotionEvent.ACTION_DOWN://第一个触点按下，将第一次的坐标保存下来
                lastX[0] = motionEvent.getX(0);
                lastY[0] = motionEvent.getY(0);
                moveLastX = motionEvent.getX();
                moveLastY = motionEvent.getY();
                flag = true;//第一次点击，说明有可能要进行单点移动，flag设为true
                break;
            case MotionEvent.ACTION_POINTER_DOWN://第二个触点按下，保存下来
                lastX[1] = motionEvent.getX(1);
                lastY[1] = motionEvent.getY(1);
                flag = false;//第二次点击，说明要进行双点操作,而不是单点移动，所以设为false
                break;
            case MotionEvent.ACTION_MOVE:
                //计算上一次触点间的距离
                float lastDistance = getDistance(lastX[0], lastY[0], lastX[1], lastY[1]);

                //如果有两个触点，进行放缩操作
                if (motionEvent.getPointerCount() == 2) {
                    //得到当前触点之间的距离
                    float currentDistance = getDistance(motionEvent.getX(0), motionEvent.getY(0), motionEvent.getX(1), motionEvent.getY(1));
                    touchMatrix = new Matrix();
                    //矩阵初始化为当前矩阵
                    touchMatrix.set(currentMatrix);

                    float pp[] = new float[9];
                    touchMatrix.getValues(pp);
                    float leftPosition = pp[2];//图片左边的位置
                    float upPostion = pp[5];//图片顶部的位置
                    /*
                     * 缩放之前对图片进行平移，将缩放中心平移到将要缩放的位置
                     * */

                    float l = (motionEvent.getX(0) + motionEvent.getX(1)) / 2 - leftPosition;
                    float t = (motionEvent.getY(0) + motionEvent.getY(1)) / 2 - upPostion;

                    touchMatrix.postTranslate(-(currentDistance / lastDistance - 1) * l,
                            -(currentDistance / lastDistance - 1) * t);
                    float p[] = new float[9];
                    touchMatrix.getValues(p);
                    //根据判断当前缩放的大小来判断是否达到缩放边界
                    if (p[0] * currentDistance / lastDistance < min_scale || p[0] * currentDistance / lastDistance > max_scale) {
                        //超过边界值时，设置为先前记录的矩阵
                        touchMatrix.set(mmatrix);
                        imageView.setImageMatrix(touchMatrix);
                    } else {
                        //图像缩放
                        touchMatrix.preScale(currentDistance / lastDistance, currentDistance / lastDistance);

                        //根据两个触点移动的距离实现位移（双触点平移）
                        float movex = (motionEvent.getX(0) - lastX[0] + motionEvent.getX(1) - lastX[1]) / 2;
                        float movey = (motionEvent.getY(0) - lastY[0] + motionEvent.getY(1) - lastY[1]) / 2;
                        touchMatrix.postTranslate(movex, movey);
                        //保存最后的矩阵，当缩放超过边界值时就设置为此矩阵
                        mmatrix = touchMatrix;
                        imageView.setImageMatrix(touchMatrix);
                    }

                } else {
                    if (flag) {

                        //只有一个触点时进行位移
                        Matrix tmp = new Matrix();//临时矩阵用来判断此次平移是否会导致平移越界
                        tmp.set(currentMatrix);
                        tmp.postTranslate(-moveLastX + motionEvent.getX(0), -moveLastY + motionEvent.getY(0));

                        if (!isTranslateOver(tmp)) {
                            //如果不越界就进行平移
                            touchMatrix = new Matrix();
                            touchMatrix.set(currentMatrix);
                            touchMatrix.postTranslate(-moveLastX + motionEvent.getX(0), -moveLastY + motionEvent.getY(0));
                            imageView.setImageMatrix(touchMatrix);
                        } else {
                            //如果会越界就保存当前位置，并且不进行矩阵变换
                            currentMatrix = touchMatrix;
                            moveLastX = motionEvent.getX(0);
                            moveLastY = motionEvent.getY(0);
                            imageView.setImageMatrix(touchMatrix);
                        }


                    }

                }
                break;
            case MotionEvent.ACTION_POINTER_UP:
            case MotionEvent.ACTION_UP:

                //松开手时，保存当前矩阵，此时的位置保存下来
                //flag设为控制
                currentMatrix = touchMatrix;
                moveLastX = motionEvent.getX(0);
                moveLastY = motionEvent.getY(0);
                flag = false;

                break;
        }
        return true;
    }

    /**
     * 得到两点之间的距离
     *
     * @param x1
     * @param y1
     * @param x2
     * @param y2
     * @return
     */
    private float getDistance(float x1, float y1, float x2, float y2) {
        return (float) Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
    }

    /**
     * 判断平移是否越界
     *
     * @param matrix
     * @return
     */
    private boolean isTranslateOver(Matrix matrix) {
        float p[] = new float[9];
        matrix.getValues(p);
        float leftPosition = p[2];
        float rightPosition = (p[2] + imageWidth * p[0]);

        float upPostion = p[5];
        float downPostion = p[5] + imageHeight * p[0];

        float leftSide, rightSide, upSide, downSide;
        leftSide = windowWidth / 4;
        rightSide = windowWidth / 4 * 3;
        upSide = windowHeight / 4;
        downSide = windowHeight / 4 * 3;
        return (leftPosition > rightSide || rightPosition < leftSide || upPostion > downSide || downPostion < upSide);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            //返回按钮点击事件
            case R.id.img_back:
                finish();
                break;
            default:
                break;
        }
    }
}
