可移动的ImageView

今天做了一个可移动的ImageView,要点如下:

1 ontouch

2 ongloballayout

3 image放置适当的位置

4 matrix变换(平移,缩放)

代码很简单

activity_main.xml



    


MainActivity.java

package com.none.moveimage;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;

import com.none.view.MoveImage;


public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MoveImage img = (MoveImage)findViewById(R.id.id_img);
        img.setImageResource(R.drawable.dou);
    }
}
MoveImage.java

package com.none.view;

import android.content.Context;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewTreeObserver;
import android.widget.ImageView;

/**
 * Created by pc on 2015/5/11.
 */
public class MoveImage extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener, View.OnTouchListener {

    private boolean mInit;
    private boolean mIsCanMove;
    private float mLastX;
    private float mLastY;
    private Matrix mScaleMatrix;
    private int mMoveSlop;

    public MoveImage(Context context) {
        this(context, null);
    }

    public MoveImage(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MoveImage(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        init(context);
    }

    private void init(Context context) {
        mScaleMatrix = new Matrix();
        mMoveSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        setOnTouchListener(this);
        mIsCanMove = false;
    }

    @Override
    protected void onAttachedToWindow() {
        getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @Override
    protected void onDetachedFromWindow() {
        getViewTreeObserver().removeOnGlobalLayoutListener(this);
    }

    @Override
    public void onGlobalLayout() {
        if (!mInit) {
            Drawable d = getDrawable();
            if (d != null) {
                float scale = 1.0f;

                int dw = d.getIntrinsicWidth();
                int dh = d.getIntrinsicHeight();

                int width = getWidth();
                int height = getHeight();

                if (dw > width && dh < height) {
                    scale = width * 1.0f / dw;
                } else if (dw < width && dh > height) {
                    scale = height * 1.0f / dh;
                } else if (dw < width && dh < height) {
                    scale = Math.min(width * 1.0f / dw, height * 1.0f / dh);
                } else if (dw > width && dh > height) {
                    scale = Math.min(width * 1.0f / dw, height * 1.0f / dh);
                } else {
                    scale = 1.0f;
                }

                int centerX = (width - dw) / 2;
                int centerY = (height - dh) / 2;
                mScaleMatrix.postTranslate(centerX, centerY);
                scale = scale / 2.0f;
                mScaleMatrix.postScale(scale, scale, width / 2, height / 2);
                setImageMatrix(mScaleMatrix);
            }
        }
        mInit = true;
    }

    private RectF getMatrixRectF() {
        RectF rectf = new RectF();
        final Matrix matrix = mScaleMatrix;
        Drawable d = getDrawable();
        if (d != null) {
            rectf.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
            matrix.mapRect(rectf);
        }
        return rectf;
    }

    private boolean isMoveAction(float dx, float dy) {
        return Math.sqrt(dx * dx + dy * dy) > mMoveSlop;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        RectF rectF = getMatrixRectF();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastX = event.getX();
                mLastY = event.getY();
                mIsCanMove = rectF.contains(mLastX, mLastY);
                break;
            case MotionEvent.ACTION_MOVE:
                if (mIsCanMove) {
                    float x = event.getX();
                    float y = event.getY();
                    float deltaX = x - mLastX;
                    float deltaY = y - mLastY;

                    if (isMoveAction(deltaX, deltaY)) {
                        checkBorderWhenMove(deltaX, deltaY, rectF);
                        setImageMatrix(mScaleMatrix);
                    }

                    mLastX = x;
                    mLastY = y;
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mIsCanMove = false;
                break;
        }
        return true;
    }

    private void checkBorderWhenMove(float deltaX, float deltaY, RectF rectF) {
        int width = getWidth();
        int height = getHeight();

        if (rectF.left + deltaX < 0) {
            deltaX = -rectF.left;
        } else if (rectF.right + deltaX > width) {
            deltaX = width - rectF.right;
        }
        if (rectF.top + deltaY < 0) {
            deltaY = -rectF.top;
        } else if (rectF.bottom + deltaY > height) {
            deltaY = height - rectF.bottom;
        }
        mScaleMatrix.postTranslate(deltaX, deltaY);
    }
}

其中图片缩放使用了matrix方式,在xml中需要将imageview的scale方式设置为matrix。

之后在根据ongloballayout中的得到的图片size和屏幕大小进行比例计算,之后使用matrix.postscale对图片进行缩放。

图片的平移使用了matrix.posttranslate,平移的距离可随意指定。

另外还需要获得每次缩放后图片的rectf,也就是图片当前的位置。这个可以使用matrix.maprect获得。

最后在ontouch中控制图片的平移,在Down中对触摸点进行判断,非图片的点击不会对图片产生影响,当点击的是图片时,使用setimagematrix对图片移动进行刷新。

在移动的过程中判断图片是否会移动出屏幕,对上下左右进行判断,防止图片移动出屏幕。


参考http://www.imooc.com/learn/239中对图片伸缩和伸缩和的上下左右位置的处理。



你可能感兴趣的:(Android)