Android imageview画像のスケーリングを実現
18153 ワード
一、Matrix詳細
Androidでは、Matrixで画像処理をしたことがあれば、Matrixというクラスを知っているに違いありません.AndroidのMatrixは3 x 3の行列で、その内容は以下の通りです.
Matrixの画像に対する処理は4種類の基本変換に分けられる.
Translateパン変換
Rotate回転変換
スケール変換
Skew正接変換
マトリクス内のMSCALEはスケーリング変換の処理に用いられ、MSKEWはタンジェント変換の処理に用いられ、MTRANSはパン変換の処理に用いられ、MPERSPはピボット変換の処理に用いられる.実际には、Matrixを完全に文字通りに理解することはできません.また,Androidの文書では,Matrixによる透視変換に関する説明は見られないため,本稿ではこの点についても議論しない.
Androidは、変換ごとにpre、set、postの3つの操作方法を提供しています.内
setは、Matrixの値を設定します.
preは先乗であり,行列の乗算は交換則を満たさないため,先乗,後乗は厳密に区別しなければならない.先乗はマトリクス演算の右乗に相当します.
postは後乗であり,行列の乗算は交換則を満たさないため,先乗,後乗は厳密に区別しなければならない.後乗はマトリクス演算の左乗に相当します.
トランスレーション変換(Translate)に加えて、回転変換(Rotate)、スケール変換(Scale)、およびスキュー変換(Skew)は、1つの中心点の周りで行うことができ、指定しない場合、デフォルトでは(0,0)の周りで対応する変換を行うことができます.
二、ImageViewの画像の4つの座標を取得する方法
画像の四角座標を取得するには、imageのMatrixと境界Rectを組み合わせて処理する必要があります.
その後、上記の情報に基づいて四角座標を取得することができます.
三、詳細実装コード
1レイアウトファイル
2画像表示コンポーネント
注意:ImageView設定の幅がmatch_であるためparentですので、提示画像が中央にある問題を処理する場合は、まずscaleTypeをcenterに設定し、その後画像処理を行う場合はscaleTypeをmatrixに動的に設定できます
四、参考資料
1 http://blog.csdn.net/flash129/article/details/8234599
2 http://www.cnblogs.com/linjzong/p/4211661.html
Androidでは、Matrixで画像処理をしたことがあれば、Matrixというクラスを知っているに違いありません.AndroidのMatrixは3 x 3の行列で、その内容は以下の通りです.
Matrixの画像に対する処理は4種類の基本変換に分けられる.
Translateパン変換
Rotate回転変換
スケール変換
Skew正接変換
マトリクス内のMSCALEはスケーリング変換の処理に用いられ、MSKEWはタンジェント変換の処理に用いられ、MTRANSはパン変換の処理に用いられ、MPERSPはピボット変換の処理に用いられる.実际には、Matrixを完全に文字通りに理解することはできません.また,Androidの文書では,Matrixによる透視変換に関する説明は見られないため,本稿ではこの点についても議論しない.
Androidは、変換ごとにpre、set、postの3つの操作方法を提供しています.内
setは、Matrixの値を設定します.
preは先乗であり,行列の乗算は交換則を満たさないため,先乗,後乗は厳密に区別しなければならない.先乗はマトリクス演算の右乗に相当します.
postは後乗であり,行列の乗算は交換則を満たさないため,先乗,後乗は厳密に区別しなければならない.後乗はマトリクス演算の左乗に相当します.
トランスレーション変換(Translate)に加えて、回転変換(Rotate)、スケール変換(Scale)、およびスキュー変換(Skew)は、1つの中心点の周りで行うことができ、指定しない場合、デフォルトでは(0,0)の周りで対応する変換を行うことができます.
二、ImageViewの画像の4つの座標を取得する方法
画像の四角座標を取得するには、imageのMatrixと境界Rectを組み合わせて処理する必要があります.
// image
Rect rect = imageView.getDrawable().getBounds();
// Matrix
mMatrix.set(imageView.getImageMatrix());
// Matrix 9 values
float[] values = new float[9];
mMatrix.getValues(values);
その後、上記の情報に基づいて四角座標を取得することができます.
//
float leftTopX = values[Matrix.MTRANS_X];
float leftTopY = values[Matrix.MTRANS_Y];
float leftBottomX = values[Matrix.MTRANS_X];
float leftBottomY = values[Matrix.MTRANS_Y] + rect.height() * values[Matrix.MSCALE_Y];
float rightTopX = values[Matrix.MTRANS_X] + rect.width() * values[Matrix.MSCALE_X];
float rightTopY = values[Matrix.MTRANS_Y];
float rightBottomX = values[Matrix.MTRANS_X] + rect.width() * values[Matrix.MSCALE_X];
float rightBottomY = values[Matrix.MTRANS_Y] + rect.height() * values[Matrix.MSCALE_Y];
三、詳細実装コード
1レイアウトファイル
2画像表示コンポーネント
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.NavUtils;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.jyy.lzn.supportdesigntest.R;
import com.jyy.lzn.supportdesigntest.news.bean.Node;
import com.jyy.lzn.supportdesigntest.util.DisplayUtil;
import com.squareup.picasso.Picasso;
/**
* Created by HP on 2016/9/22.
*/
public class NewsImageViewerFragment extends Fragment {
public static final String TAG = "NewsImageViewerFragment";
private ViewPager mViewPager;
private Node mNode;
private ImageView imageView;
//
private float mFingerDistance = 0;
//
private int mOperateMode = -1;
private static final int MOVE = 0;
private static final int ZOOM = 1;
//
private PointF mCurrentPointF = new PointF();
//
private PointF mMidPointF = new PointF();
private Matrix mMatrix = new Matrix();
private Matrix mCurrentMatrix = new Matrix();
//
private static final float MAX_SCALE = 3f;
private float MIN_SCALE = 1f;
private boolean mIsReachMinScale = true;
private boolean mIsReachMaxScale = false;
//
private static final float MIN_FINGER_DISTANCE = 10f;
//
private int requestedWidth;
private int requestedHeight;
private GestureDetector mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener());
public static Fragment newInstance(Node node) {
NewsImageViewerFragment newsImageViewerFragment = new NewsImageViewerFragment();
Bundle bundle = new Bundle();
bundle.putSerializable(TAG, node);
newsImageViewerFragment.setArguments(bundle);
return newsImageViewerFragment;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNode = (Node) getArguments().getSerializable(TAG);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_news_image_viewer, container, false);
mViewPager = ((ViewPager) getActivity().findViewById(R.id.news_image_view_pager));
mGestureDetector.setOnDoubleTapListener(mOnDoubleTapListener);
//
imageView = (ImageView) view.findViewById(R.id.news_image_view);
imageView.setOnTouchListener(onTouchListener);
// ImageView
requestedWidth = DisplayUtil.windowWidth(getContext());
requestedHeight = (int) (requestedWidth / mNode.getAspectRatio());
Picasso.with(getActivity()).load(mNode.getValue()).config(Bitmap.Config.ARGB_8888).resize(requestedWidth, requestedHeight).placeholder(R.drawable.imageview_default_bg).tag(TAG).into(imageView);
return view;
}
private View.OnTouchListener onTouchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
imageView.setScaleType(ImageView.ScaleType.MATRIX);
if (mGestureDetector.onTouchEvent(event)) {
return true;
}
switch (event.getAction() & MotionEvent.ACTION_MASK) {
//
case MotionEvent.ACTION_DOWN:
mOperateMode = MOVE;
//
mCurrentPointF.set(event.getX(), event.getY());
mCurrentMatrix.set(imageView.getImageMatrix());
break;
//
case MotionEvent.ACTION_MOVE:
mViewPager.requestDisallowInterceptTouchEvent(true);
if (mOperateMode == MOVE) {
drag(event);
} else if (mOperateMode == ZOOM) {
float endFingerDistance = fingerDistance(event);
if (endFingerDistance > MIN_FINGER_DISTANCE) {
float scale = endFingerDistance / mFingerDistance;
zoom(scale);
}
}
break;
//
case MotionEvent.ACTION_POINTER_DOWN:
mOperateMode = ZOOM;
//
mFingerDistance = fingerDistance(event);
if (mFingerDistance > MIN_FINGER_DISTANCE) {
mCurrentPointF.set(event.getX(), event.getY());
mCurrentMatrix.set(imageView.getImageMatrix());
midFingerDistance(event);
} else {
mOperateMode = MOVE;
}
break;
//
case MotionEvent.ACTION_UP:
mOperateMode = -1;
break;
//
case MotionEvent.ACTION_POINTER_UP:
mOperateMode = -1;
adjustPosition();
break;
}
return true;
}
};
/**
*
*/
private void adjustPosition() {
if (mIsReachMinScale) {
imageView.setScaleType(ImageView.ScaleType.CENTER);
}
int screenWidth = DisplayUtil.windowWidth(getContext());
Rect rect = imageView.getDrawable().getBounds();
mMatrix.set(imageView.getImageMatrix());
float[] values = new float[9];
mMatrix.getValues(values);
float leftTopX = values[Matrix.MTRANS_X];
float rightTopX = values[Matrix.MTRANS_X] + rect.width() * values[Matrix.MSCALE_X];
if (leftTopX > 0) {
values[Matrix.MTRANS_X] = 0f;
} else if (rightTopX < screenWidth) {
values[Matrix.MTRANS_X] = screenWidth - (rect.width() * values[Matrix.MSCALE_X]);
}
//
float dy = DisplayUtil.windowHeight(getContext()) - DisplayUtil.getSystemStatueBarHeight(getContext()) - rect.height() * values[Matrix.MSCALE_Y];
values[Matrix.MTRANS_Y] = dy / 2;
//
mMatrix.setValues(values);
imageView.setImageMatrix(mMatrix);
}
/**
*
*
* @param event
*/
private void drag(MotionEvent event) {
if (mIsReachMinScale) {
mViewPager.requestDisallowInterceptTouchEvent(false);
return;
}
boolean isFullScreen;
int screenWidth = DisplayUtil.windowWidth(getContext());
int screenHeight = DisplayUtil.windowHeight(getContext());
float transX = event.getX() - mCurrentPointF.x;
float transY = event.getY() - mCurrentPointF.y;
Rect rect = imageView.getDrawable().getBounds();
float[] intiValues = new float[9];
mCurrentMatrix.getValues(intiValues);
float height = rect.height() * intiValues[Matrix.MSCALE_Y];
// y
if (height < screenHeight) {
isFullScreen = false;
transY = 0;
} else {
isFullScreen = true;
}
mMatrix.set(mCurrentMatrix);
mMatrix.postTranslate(transX, transY);
float[] values = new float[9];
mMatrix.getValues(values);
//
float leftTopX = values[Matrix.MTRANS_X];
float leftTopY = values[Matrix.MTRANS_Y];
float leftBottomX = values[Matrix.MTRANS_X];
float leftBottomY = values[Matrix.MTRANS_Y] + rect.height() * values[Matrix.MSCALE_Y];
float rightTopX = values[Matrix.MTRANS_X] + rect.width() * values[Matrix.MSCALE_X];
float rightTopY = values[Matrix.MTRANS_Y];
float rightBottomX = values[Matrix.MTRANS_X] + rect.width() * values[Matrix.MSCALE_X];
float rightBottomY = values[Matrix.MTRANS_Y] + rect.height() * values[Matrix.MSCALE_Y];
if (isFullScreen) { //
//
if (leftTopX > 0 && leftTopY > 0) {
values[Matrix.MTRANS_X] = 0f;
values[Matrix.MTRANS_Y] = 0f;
mViewPager.requestDisallowInterceptTouchEvent(false);
} else if (leftTopX > 0 && leftTopY < 0) {
values[Matrix.MTRANS_X] = 0f;
mViewPager.requestDisallowInterceptTouchEvent(false);
} else if (leftTopX < 0 && leftTopY > 0) {
values[Matrix.MTRANS_Y] = 0f;
}
//
if (leftBottomX > 0 && leftBottomY < screenHeight) {
values[Matrix.MTRANS_X] = 0f;
values[Matrix.MTRANS_Y] = screenHeight - (rect.height() * values[Matrix.MSCALE_Y]);
mViewPager.requestDisallowInterceptTouchEvent(false);
} else if (leftBottomX > 0 && leftBottomY > screenHeight) {
values[Matrix.MTRANS_X] = 0f;
mViewPager.requestDisallowInterceptTouchEvent(false);
} else if (leftBottomX < 0 && leftBottomX > screenHeight) {
values[Matrix.MTRANS_Y] = screenHeight - (rect.height() * values[Matrix.MSCALE_Y]);
}
//
if (rightTopX < screenWidth && rightTopY > 0) {
values[Matrix.MTRANS_X] = screenWidth - (rect.width() * values[Matrix.MSCALE_X]);
values[Matrix.MTRANS_Y] = 0;
mViewPager.requestDisallowInterceptTouchEvent(false);
} else if (rightTopX < screenWidth && rightTopY < 0) {
values[Matrix.MTRANS_X] = screenWidth - (rect.width() * values[Matrix.MSCALE_X]);
mViewPager.requestDisallowInterceptTouchEvent(false);
} else if (rightTopX > screenWidth && rightTopY > 0) {
values[Matrix.MTRANS_Y] = 0;
}
//
if (rightBottomX < screenWidth && rightBottomY < screenHeight) {
values[Matrix.MTRANS_X] = screenWidth - (rect.width() * values[Matrix.MSCALE_X]);
values[Matrix.MTRANS_Y] = screenHeight - (rect.height() * values[Matrix.MSCALE_Y]);
mViewPager.requestDisallowInterceptTouchEvent(false);
} else if (rightBottomX < screenWidth && rightBottomY > screenHeight) {
values[Matrix.MTRANS_X] = screenWidth - (rect.width() * values[Matrix.MSCALE_X]);
mViewPager.requestDisallowInterceptTouchEvent(false);
} else if (rightBottomX > screenWidth && rightBottomY < screenHeight) {
values[Matrix.MTRANS_Y] = screenHeight - (rect.height() * values[Matrix.MSCALE_Y]);
}
} else { //
if (leftTopX > 0) {
values[Matrix.MTRANS_X] = 0f;
mViewPager.requestDisallowInterceptTouchEvent(false);
} else if (rightBottomX < screenWidth) {
values[Matrix.MTRANS_X] = screenWidth - (rect.width() * values[Matrix.MSCALE_X]);
mViewPager.requestDisallowInterceptTouchEvent(false);
}
}
mMatrix.setValues(values);
imageView.setImageMatrix(mMatrix);
}
/**
*
*
* @param scale
*/
private void zoom(float scale) {
if (mIsReachMaxScale && scale > 1 || mIsReachMinScale && scale < 1) {
return;
}
mMatrix.set(mCurrentMatrix);
mMatrix.postScale(scale, scale, DisplayUtil.windowWidth(getContext()) / 2, DisplayUtil.windowHeight(getContext()) / 2 - DisplayUtil.getSystemStatueBarHeight(getContext()) / 2);
float[] values = new float[9];
mMatrix.getValues(values);
if (values[Matrix.MSCALE_X] >= MAX_SCALE) {
mIsReachMinScale = false;
mIsReachMaxScale = true;
values[Matrix.MSCALE_X] = MAX_SCALE;
values[Matrix.MSCALE_Y] = MAX_SCALE;
} else if (values[Matrix.MSCALE_X] <= MIN_SCALE) {
mIsReachMinScale = true;
mIsReachMaxScale = false;
values[Matrix.MSCALE_X] = MIN_SCALE;
values[Matrix.MSCALE_Y] = MIN_SCALE;
} else {
mIsReachMinScale = false;
mIsReachMaxScale = false;
}
mMatrix.setValues(values);
imageView.setImageMatrix(mMatrix);
}
/**
*
*
* @param event
* @return
*/
private float fingerDistance(MotionEvent event) {
try {
float dx = event.getX(1) - event.getX(0);
float dy = event.getY(1) - event.getX(0);
return (float) Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
return 0;
}
/**
*
*
* @param event
*/
private void midFingerDistance(MotionEvent event) {
try {
float dx = event.getX(1) + event.getX(0);
float dy = event.getY(1) + event.getX(0);
mMidPointF.set(dx / 2, dy / 2);
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
private GestureDetector.OnDoubleTapListener mOnDoubleTapListener = new GestureDetector.OnDoubleTapListener() {
@Override
public boolean onSingleTapConfirmed(MotionEvent motionEvent) {
if (NavUtils.getParentActivityName(getActivity()) != null) {
NavUtils.navigateUpFromSameTask(getActivity());
}
return true;
}
@Override
public boolean onDoubleTap(MotionEvent motionEvent) {
mMatrix.set(imageView.getImageMatrix());
if (mIsReachMinScale) {
mMatrix.postScale(MAX_SCALE, MAX_SCALE, DisplayUtil.windowWidth(getContext()) / 2, DisplayUtil.windowHeight(getContext()) / 2 - DisplayUtil.getSystemStatueBarHeight(getContext()) / 2);
imageView.setImageMatrix(mMatrix);
mIsReachMinScale = false;
mIsReachMaxScale = true;
float[] values = new float[9];
mMatrix.getValues(values);
Log.d(TAG, "y: " + values[Matrix.MTRANS_Y]);
} else {
mMatrix.postScale(MIN_SCALE, MIN_SCALE, DisplayUtil.windowWidth(getContext()) / 2, DisplayUtil.windowHeight(getContext()) / 2);
imageView.setImageMatrix(mMatrix);
imageView.setScaleType(ImageView.ScaleType.CENTER);
mIsReachMinScale = true;
mIsReachMaxScale = false;
}
return true;
}
@Override
public boolean onDoubleTapEvent(MotionEvent motionEvent) {
return true;
}
};
}
注意:ImageView設定の幅がmatch_であるためparentですので、提示画像が中央にある問題を処理する場合は、まずscaleTypeをcenterに設定し、その後画像処理を行う場合はscaleTypeをmatrixに動的に設定できます
四、参考資料
1 http://blog.csdn.net/flash129/article/details/8234599
2 http://www.cnblogs.com/linjzong/p/4211661.html