Android 는 viewPager 에서 두 손가락 으로 그림 크기 를 조정 하고 두 번 클릭 하여 그림 크기 를 조정 합 니 다.
1.그림 크기 조정 을 더 블 클릭 합 니 다.
2.두 손가락 으로 그림 크기 를 조정 합 니 다.
3.한 손가락 으로 그림 을 끌 어 당 긴 다.
이 그림 뷰 어 는 다음 과 같은 기술 을 고려 해 야 합 니 다.
1.그림 크기 조정 을 더 블 클릭:
1.만약 에 그림 의 높이 가 화면의 높이 보다 훨씬 작다 면 그림 을 화면 높이 와 똑 같이 확대 하고 그렇지 않 으 면 특정한 배 수 를 확대 한다.
2.이 배수 에 도 달 했 는 지 여 부 를 어떻게 판단 하여 크기 조정 을 중단 합 니까?
3.판단 이 끝나 고 확대 가 중 단 된 후에 그림 은 이 배수 가 필요 로 하 는 크기 를 초과 할 수 있 습 니 다.어떻게 우리 의 목표 크기 로 돌아 갈 수 있 습 니까?
4.판단 이 끝나 고 축소 가 중 단 된 후에 그림 의 너비 가 화면 너비 보다 작 을 수 있 습 니 다.양쪽 에 공백 을 남 겼 는데 어떻게 원래 의 크기 로 초기 화 할 수 있 습 니까?
두 손가락 크기 조정 그림:
1.두 손가락 크기 를 조정 하고 특정한 배 수 를 확대 하여 정지 합 니 다.
2.이 배수 에 도 달 했 는 지 여 부 를 어떻게 판단 합 니까?
3.확대 가 멈 춘 후에 그림 은 이 배수 에 필요 한 크기 를 초과 하고 우리 의 목표 크기 로 어떻게 돌아 갈 수 있 습 니까?
4.축소 가 멈 춘 후에 그림 의 너비 가 화면 너비 보다 작 을 수도 있 고 양쪽 에 공백 을 남 겼 을 수도 있 습 니 다.어떻게 원래 의 크기 로 초기 화 할 수 있 습 니까?
3.한 손가락 으로 끌 기:
1.그림 의 너비 가 화면 너비 보다 작 거나 같 을 때 좌우 이동 을 금지 하고 그림 의 높이 가 화면 높이 보다 작 을 때 상하 이동 을 금지한다.
2.그림 을 이동 할 때 그림 의 한쪽 과 화면 사이 에 공백 이 있 으 면 손 을 놓 고 복원 하여 그림 의 이쪽 과 화면 경 계 를 겹 치 게 합 니 다.
넷,
어떻게 더 블 클릭 인지,다 중 터치 인지,아니면 한 손가락 으로 판단 합 니까?
다섯,
viewPager 와 의 미끄럼 충돌 을 어떻게 해결 합 니까?그림 이 끝까지 미 끄 러 져 서 미 끄 러 질 수 없 을 때 viewPager 는 이 벤트 를 차단 해 야 합 니 다.
우 리 는 하나씩 해결한다.
public class MyImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener,View.OnTouchListener {
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
super.setScaleType(ScaleType.MATRIX);
setOnTouchListener(this);
/**
*
*/
mGestureDetector = new GestureDetector(context,
new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDoubleTap(MotionEvent e) {
changeViewSize(e);
return true;
}
});
}
그림 크기 조정 은 matrix 를 사용 하기 때문에 먼저 scale Type 을 matrix 로 설정 해 야 합 니 다.손짓 으로 더 블 클릭 행 위 를 판단 하 다.온 터치 에 넣 는 거 잊 지 마 세 요.
if (mGestureDetector.onTouchEvent(event))
return true;
단지 와 다 지 터치 제 어 를 판단 하면 onTouch 에서 판단 하고 이벤트.getAction()&MotionEvent.ACTIONMASK 가 판단 한다.
// , ,
private int mode;
private final static int SINGLE_TOUCH = 1; //
private final static int DOUBLE_TOUCH = 2; //
@Override
public boolean onTouch(View view, MotionEvent event) {
rectF = getMatrixRectF();
if (mGestureDetector.onTouchEvent(event))
return true;
switch (event.getAction() & event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mode = SINGLE_TOUCH;
break;
case MotionEvent.ACTION_MOVE:
if (mode >= DOUBLE_TOUCH) //
{
}
if (mode == SINGLE_TOUCH) //
{
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
mode += 1;break;
case MotionEvent.ACTION_POINTER_UP:
mode -= 1;
break;
case MotionEvent.ACTION_UP:
mode = 0;
break;
// ACTION_MOVE , , ACTION_UP , ACTION_CANCEL
case MotionEvent.ACTION_CANCEL:
mode = 0;
break;
default:
break;
}
return true;
}
다음 과 같은 사건 이 우리 가 사용 해 야 할 것 은:MotionEvent.ACTION_DOWN:첫 번 째 점 이 눌 렸 을 때 터치
MotionEvent.ACTION_UP:화면의 유일한 점 이 열 렸 을 때 터치 합 니 다.
MotionEvent.ACTION_POINTER_DOWN:화면 에 점 이 하나 눌 렸 을 때 다른 점 을 눌 렀 을 때 터치 합 니 다.
MotionEvent.ACTION_POINTER_UP:화면 에 여러 개의 점 이 눌 렸 을 때 한 점 을 풀 었 을 때 터치 합 니 다(즉,마지막 점 이 풀 리 지 않 았 을 때).
MotionEvent.ACTION_MOVE:화면 에서 조금 움 직 일 때 터치 합 니 다.주의해 야 할 것 은 민감 도가 높 고 우리 의 손가락 이 완전히 멈 출 수 없 기 때문에(우리 가 움 직 이 는 것 을 느끼 지 못 하 더 라 도 사실은 우리 의 손가락 이 계속 떨 리 고 있다)실제 상황 은 기본적으로 화면 에 조금 만 있 으 면 이 사건 이 계속 촉발 된다 는 것 이다.
ACTION 에서MOVE 에 서 는 mode 의 크기 를 통 해 단지 인지 양지 인지 판단 한다.
하지만 안 드 로 이 드 자신 에 게 bug 가 있다 는 슬 픈 일이 있 습 니 다.테스트 를 통 해 두 손가락 이 그림 을 교환 할 때 프로그램 이 반 짝 거 리 며 이상 이 발생 합 니 다:pointIndex out of range.안 드 로 이 드 자체 버그 입 니 다.개인 적 으로 가장 좋 은 해결 방법 은 viewPager 를 사용자 정의 한 다음 에 그 안에 다시 쓰 는 것 입 니 다.onTouchEvent,onInterceptTouchEvent,그리고 이상 을 포착 하 는 것 입 니 다.
@Override
public boolean onTouchEvent(MotionEvent ev) {
try {
return super.onTouchEvent(ev);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
try {
return super.onInterceptTouchEvent(ev);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
return false;
}
이렇게 하면 절차 가 물 러 서지 않 을 것 이다.더 블 클릭 으로 확 대 된 코드 를 살 펴 보 자.
/**
*
*/
private void changeViewSize(MotionEvent e) {
//
final float x = e.getX();
final float y = e.getY();
//
if (animator != null && animator.isRunning())
return;
//
if (!isZoomChanged()) {
animator = ValueAnimator.ofFloat(1.0f, 2.0f);
} else {
animator = ValueAnimator.ofFloat(1.0f, 0.0f);
}
animator.setTarget(this);
animator.setDuration(500);
animator.setInterpolator(new DecelerateInterpolator());
animator.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
Float value = (Float) animator.getAnimatedValue();
matrix.postScale(value, value, x, y);
checkBorderAndCenterWhenScale(); //
setImageMatrix(matrix);
/**
*
* , ,
*/
if (checkRestScale()) {
matrix.set(oldMatrix); //oldMatrix matrix
setImageMatrix(matrix);
return;
}
/**
*
* ,
*
*/
if (getMatrixValueX() >= mDoubleClickScale)
{
matrix.postScale(mDoubleClickScale/getMatrixValueX(), mDoubleClickScale/getMatrixValueX(), x, y);
checkBorderAndCenterWhenScale();
setImageMatrix(matrix);
return;
}
}
});
}
확대 상태 인지 축소 상태 인지 판단 하 는 코드:(초기 값 이 아니면 확대 상태 임)
/**
*
*
* @return true , false
*/
private boolean isZoomChanged() {
float[] values = new float[9];
getImageMatrix().getValues(values);
// X
float scale = values[Matrix.MSCALE_X];
// X ,
oldMatrix.getValues(values);
return scale != values[Matrix.MSCALE_X];
}
getMatrixValue()의 코드 는 다음 과 같 습 니 다.현재 의 확대 배 수 를 얻 기 위해 서 입 니 다.처음 그림 에 비해
private float getMatrixValueX()
{
// TODO Auto-generated method stub
float[] values = new float[9];
getImageMatrix().getValues(values);
// X
float scale = values[Matrix.MSCALE_X];
// Matrix X
oldMatrix.getValues(values);
//
return scale / values[Matrix.MSCALE_X];
}
checkRestcale()의 코드 는 다음 과 같 습 니 다.현재 크기 조정 단계 가 초기 크기 조정 단계 보다 작은 지 판단 하기 위해 서 입 니 다.
/**
*
*
* @return ,
*/
private boolean checkRestScale() {
// TODO Auto-generated method stub
float[] values = new float[9];
getImageMatrix().getValues(values);
// X
float scale = values[Matrix.MSCALE_X];
// X ,
oldMatrix.getValues(values);
return scale < values[Matrix.MSCALE_X];
}
checkBorder AndCenter WhenScale()의 코드 는 다음 과 같 습 니 다.그렇지 않 으 면 그림 크기 를 조정 한 후 위치 가 달라 집 니 다.
/**
* ,
*/
private void checkBorderAndCenterWhenScale()
{
RectF rect = getMatrixRectF();
float deltaX = 0;
float deltaY = 0;
int width = getWidth();
int height = getHeight();
// ,
if (rect.width() >= width)
{
if (rect.left > 0)
{
deltaX = -rect.left;
}
if (rect.right < width)
{
deltaX = width - rect.right;
}
}
if (rect.height() >= height)
{
if (rect.top > 0)
{
deltaY = -rect.top;
}
if (rect.bottom < height)
{
deltaY = height - rect.bottom;
}
}
// ,
if (rect.width() < width)
{
deltaX = width * 0.5f - rect.right + 0.5f * rect.width();
}
if (rect.height() < height)
{
deltaY = height * 0.5f - rect.bottom + 0.5f * rect.height();
}
matrix.postTranslate(deltaX, deltaY);
setImageMatrix(matrix);
}
두 손가락 크기 조정 과 한 손가락 드래그 를 받 아 보 세 요.
@Override
public boolean onTouch(View view, MotionEvent event) {
rectF = getMatrixRectF(); //
if (mGestureDetector.onTouchEvent(event))
return true;
switch (event.getAction() & event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
// , , viewPager
if (rectF.width() > getWidth() || rectF.height() > getHeight()) {
getParent().requestDisallowInterceptTouchEvent(true);
}
mode = SINGLE_TOUCH;
x = (int) event.getRawX();
y = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
if (mode >= DOUBLE_TOUCH) //
{
getParent().requestDisallowInterceptTouchEvent(true);
newDist = calculateDist(event); //
Point point = getMiPoint(event); //
if (newDist > oldDist + 1) // ( )
{
changeViewSize(oldDist, newDist, point); //
oldDist = newDist;
}
if (oldDist > newDist + 1) //
{
changeViewSize(oldDist, newDist, point);
oldDist = newDist;
}
}
if (mode == SINGLE_TOUCH) //
{
float dx = event.getRawX() - x;
float dy = event.getRawY() - y;
// , , viewPager
if (rectF.width() > getWidth() || rectF.height() > getHeight()) {
getParent().requestDisallowInterceptTouchEvent(true);
}
// , , viewPager
if (rectF.left >= 0 && dx > 0)
getParent().requestDisallowInterceptTouchEvent(false);
// , , viewPager
if (rectF.right <= getWidth() && dx < 0)
getParent().requestDisallowInterceptTouchEvent(false);
if (getDrawable() != null) {
// ,
if (rectF.width() <= getWidth())
dx = 0;
if (rectF.height() < getHeight())
dy = 0;
// ,
if (rectF.top >= 0 && dy > 0)
dy = 0;
// ,
if (rectF.bottom <= getHeight() && dy < 0)
dy = 0;
// 1 , ACTION_MOVE ,
// , , 。
if (Math.abs(dx) > 1 || Math.abs(dy) > 1)
matrix.postTranslate(dx, dy);
setImageMatrix(matrix);
}
}
x = (int) event.getRawX();
y = (int) event.getRawY();
break;
case MotionEvent.ACTION_POINTER_DOWN:
mode += 1;
oldDist = calculateDist(event); break;
case MotionEvent.ACTION_POINTER_UP:
mode -= 1;
break;
case MotionEvent.ACTION_UP:
backToPosition();
mode = 0;
break;
// ACTION_MOVE , , ACTION_UP , ACTION_CANCEL
case MotionEvent.ACTION_CANCEL:
backToPosition();
mode = 0;
break;
default:
break;
}
return true;
}
먼저 그림 의 matrix 에 따라 그림 의 경계 범 위 를 얻 고 이 범 위 는 rect 에 매 핑 됩 니 다.(이 범위 검 사 는 한 손가락 으로 끌 어 당 기 는 데 쓰 인 다)
/**
* Matrix
*
* @return
*/
private RectF getMatrixRectF()
{
RectF rect = new RectF();
Drawable d = getDrawable();
if (null != d)
{
rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
matrix.mapRect(rect);
}
Log.e("aaaa",""+rect.bottom+" "+rect.left+" "+rect.right+" "+rect.top);
return rect;
}
rect.bottom:그림 아래 경계 에 있 는 세로 좌표rect.left:그림 왼쪽 경계의 가로 좌표
rect.right:그림 오른쪽 경계의 가로 좌표
rect.top:그림 의 경계 에 있 는 세로 좌표
rectF.width():그림 너비
rectf.height():그림 높이
주의해 야 할 것 은 Matrix 가 그림 에 대한 조작 은 모두 ImageView 안의 bitmap 를 조작 하 는 것 입 니 다.ImageView 는 변화 가 없습니다.위 에서 말 한 화면 경 계 는 사실 ImageView 의 경계,getWidth(),getHeight()는 ImageView 의 너비 와 높이 입 니 다.
방법 backToPosition()은 주로 한 손가락 으로 끌 어 당 기 는 기술 점 2 를 실현 합 니 다.손가락 이 빠르게 지나 갈 때 계속 미 끄 러 질 수 없 음 을 감지 하기 전에 그림 경계 와 화면 경계 가 이미 거리 가 나 타 났 기 때문에 손가락 을 풀 었 을 때 원상 태 로 복원 하여 그림 경계 와 화면 경계 가 겹 치 게 해 야 합 니 다.
/**
* ,
* , , ,
* 。
*
*/
private void backToPosition() {
if (rectF.left >= 0) { //
matrix.postTranslate(-rectF.left, 0);
setImageMatrix(matrix);
}
if (rectF.right <= getWidth()) { //
matrix.postTranslate(getWidth() - rectF.right, 0);
setImageMatrix(matrix);
}
if (rectF.top >= 0) { //
matrix.postTranslate(0, -rectF.top);
setImageMatrix(matrix);
}
if (rectF.bottom <= getHeight()) { //
matrix.postTranslate(0, getHeight() - rectF.bottom);
setImageMatrix(matrix);
}
}
두 손가락 사이 의 중심 점 좌 표를 가 져 옵 니 다.
/**
*
*
* @return
*/
private Point getMiPoint(MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
mPoint.set((int) x / 2, (int) y / 2);
return mPoint;
}
두 손가락 터치 점 의 거 리 를 계산 하 다.
/**
*
*/
private float calculateDist(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 changeViewSize(float oldDist, float newDist, Point mPoint) {
float scale = newDist / oldDist; //
matrix.postScale(scale, scale, mPoint.x, mPoint.y);
checkBorderAndCenterWhenScale();
setImageMatrix(matrix);
// ,
reSetMatrix();
// , , ,
if (getMatrixValueX() >= MAX_SCALE)
{
matrix.postScale(MAX_SCALE/getMatrixValueX(), MAX_SCALE/getMatrixValueX(), x, y);
checkBorderAndCenterWhenScale();
setImageMatrix(matrix);
return;
}
}
reSetMatrix()의 코드 는 다음 과 같 습 니 다.
/**
* Matrix
*/
private void reSetMatrix() {
if (checkRestScale()) {
matrix.set(oldMatrix);
setImageMatrix(matrix);
return;
}
}
checkRestcale()의 코드 가 위 에 있 습 니 다.oldMatrix 는 최초의 Matrix 입 니 다.여기 서 아직 끝나 지 않 았 습 니 다.Imageview 의 Scale Type 을 Matrix 로 설정 하면 그림 이 화면 에 맞 게 자동 으로 크기 를 조정 하지 않 고 화면 중간 에 있 지 않 습 니 다.따라서 사용자 정의 ImageView 는 View TreeObserver.OnGlobalLayoutListener 를 계승 해 야 합 니 다.
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@Override
public void onGlobalLayout() {
if (once)
{
Drawable d = getDrawable();
if (d == null)
return;
Log.e("TAG", d.getIntrinsicWidth() + " , " + d.getIntrinsicHeight());
int width = getWidth();
int height = getHeight();
//
int dw = d.getIntrinsicWidth();
int dh = d.getIntrinsicHeight();
float scale = 1.0f;
// ,
if (dw > width && dh <= height)
{
scale = width * 1.0f / dw;
}
if (dh > height && dw <= width)
{
scale = height * 1.0f / dh;
}
// ,
if (dw > width && dh > height)
{
scale = Math.min(width * 1.0f / dw, height * 1.0f / dh);
}
initScale = scale;
Log.e("TAG", "initScale = " + initScale);
matrix.postTranslate((width - dw) / 2, (height - dh) / 2);
matrix.postScale(scale, scale, getWidth() / 2,
getHeight() / 2);
//
setImageMatrix(matrix);
oldMatrix.set(getImageMatrix());
once = false;
RectF rectF=getMatrixRectF();
setDoubleClickScale(rectF);
}
}
//
int dw = d.getIntrinsicWidth();
int dh = d.getIntrinsicHeight();
받 은 그림 의 너비 와 높이 는 bitmap 의 실제 높이 입 니 다.최초의 oldMatrix 는 여기에 설 치 된 다음 에 초기 템 플 릿 으로 그림 이 바 뀌 지 않 은 Matrix 를 대표 합 니 다.방법 setDoubleClickScale(rectF);더 블 클릭 으로 확대 하 는 배 수 를 설정 할 뿐 화면 높이 보다 그림 높이 가 훨씬 작 으 면 화면 높이 와 같은 높이 로 확대 하고 그렇지 않 으 면 특정한 배 수 를 확대 한다.여기에 설정 해 야 합 니 다.여기에서 찾 은 rectf 는 원본 그림 의 경 계 를 반영 할 수 있 기 때 문 입 니 다.이때 그림 을 바 꾸 지 않 았 기 때 문 입 니 다.
/**
*
*/
private void setDoubleClickScale(RectF rectF)
{
if(rectF.height()<getHeight()-100)
{
mDoubleClickScale=getHeight()/rectF.height();
}
else
mDoubleClickScale=2f;
}
여기까지 대충 끝 났 습 니 다.다음은 완전한 코드 를 붙 입 니 다.
package com.example.tangzh.myimageview;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
/**
* Created by TangZH on 2017/5/3.
*/
public class MyImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener,View.OnTouchListener {
private final static int SINGLE_TOUCH = 1; //
private final static int DOUBLE_TOUCH = 2; //
// , ,
private int mode;
//
private float oldDist;
private float newDist;
/**
*
*/
private static final float MAX_SCALE = 5f;
/**
*
*/
private float mDoubleClickScale = 2;
/**
* , , 0
*/
private float initScale = 1.0f;
private boolean once = true;
private RectF rectF;
/**
*
*/
private GestureDetector mGestureDetector;
private int x = 0;
private int y = 0;
private Point mPoint = new Point();
private final Matrix matrix = new Matrix();
private Matrix oldMatrix = new Matrix();
private ValueAnimator animator;
public MyImageView(Context context) {
this(context, null);
}
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
super.setScaleType(ScaleType.MATRIX);
setOnTouchListener(this);
/**
*
*/
mGestureDetector = new GestureDetector(context,
new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDoubleTap(MotionEvent e) {
changeViewSize(e);
return true;
}
});
}
@Override
public boolean onTouch(View view, MotionEvent event) {
rectF = getMatrixRectF(); //
if (mGestureDetector.onTouchEvent(event))
return true;
switch (event.getAction() & event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
// , , viewPager
if (rectF.width() > getWidth() || rectF.height() > getHeight()) {
getParent().requestDisallowInterceptTouchEvent(true);
}
mode = SINGLE_TOUCH;
x = (int) event.getRawX();
y = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
if (mode >= DOUBLE_TOUCH) //
{
getParent().requestDisallowInterceptTouchEvent(true);
newDist = calculateDist(event); //
Point point = getMiPoint(event); //
if (newDist > oldDist + 1) // ( )
{
changeViewSize(oldDist, newDist, point); //
oldDist = newDist;
}
if (oldDist > newDist + 1) //
{
changeViewSize(oldDist, newDist, point);
oldDist = newDist;
}
}
if (mode == SINGLE_TOUCH) //
{
float dx = event.getRawX() - x;
float dy = event.getRawY() - y;
// , , viewPager
if (rectF.width() > getWidth() || rectF.height() > getHeight()) {
getParent().requestDisallowInterceptTouchEvent(true);
}
// , , viewPager
if (rectF.left >= 0 && dx > 0)
getParent().requestDisallowInterceptTouchEvent(false);
// , , viewPager
if (rectF.right <= getWidth() && dx < 0)
getParent().requestDisallowInterceptTouchEvent(false);
if (getDrawable() != null) {
// ,
if (rectF.width() <= getWidth())
dx = 0;
if (rectF.height() < getHeight())
dy = 0;
// ,
if (rectF.top >= 0 && dy > 0)
dy = 0;
// ,
if (rectF.bottom <= getHeight() && dy < 0)
dy = 0;
// 1 , ACTION_MOVE ,
// , , 。
if (Math.abs(dx) > 1 || Math.abs(dy) > 1)
matrix.postTranslate(dx, dy);
setImageMatrix(matrix);
}
}
x = (int) event.getRawX();
y = (int) event.getRawY();
break;
case MotionEvent.ACTION_POINTER_DOWN:
mode += 1;
oldDist = calculateDist(event);
Log.e("q", "" + "a");
Log.e(":::", "" + event.getPointerCount() + " " + event.getActionIndex() + " " + event.findPointerIndex(0));
break;
case MotionEvent.ACTION_POINTER_UP:
mode -= 1;
break;
case MotionEvent.ACTION_UP:
backToPosition();
mode = 0;
break;
// ACTION_MOVE , , ACTION_UP , ACTION_CANCEL
case MotionEvent.ACTION_CANCEL:
backToPosition();
mode = 0;
break;
default:
break;
}
return true;
}
/**
*
*/
private float calculateDist(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);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
getViewTreeObserver().addOnGlobalLayoutListener(this);
}
/**
* ,
* , , ,
* 。
*
*/
private void backToPosition() {
if (rectF.left >= 0) { //
matrix.postTranslate(-rectF.left, 0);
setImageMatrix(matrix);
}
if (rectF.right <= getWidth()) { //
matrix.postTranslate(getWidth() - rectF.right, 0);
setImageMatrix(matrix);
}
if (rectF.top >= 0) { //
matrix.postTranslate(0, -rectF.top);
setImageMatrix(matrix);
}
if (rectF.bottom <= getHeight()) { //
matrix.postTranslate(0, getHeight() - rectF.bottom);
setImageMatrix(matrix);
}
}
/**
*
*
* @return
*/
private Point getMiPoint(MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
mPoint.set((int) x / 2, (int) y / 2);
return mPoint;
}
/**
*
*/
private void changeViewSize(float oldDist, float newDist, Point mPoint) {
float scale = newDist / oldDist; //
matrix.postScale(scale, scale, mPoint.x, mPoint.y);
checkBorderAndCenterWhenScale();
setImageMatrix(matrix);
// ,
reSetMatrix();
// , , ,
if (getMatrixValueX() >= MAX_SCALE)
{
matrix.postScale(MAX_SCALE/getMatrixValueX(), MAX_SCALE/getMatrixValueX(), x, y);
checkBorderAndCenterWhenScale();
setImageMatrix(matrix);
return;
}
}
/**
*
*/
private void changeViewSize(MotionEvent e) {
//
final float x = e.getX();
final float y = e.getY();
//
if (animator != null && animator.isRunning())
return;
//
if (!isZoomChanged()) {
animator = ValueAnimator.ofFloat(1.0f, 2.0f);
} else {
animator = ValueAnimator.ofFloat(1.0f, 0.0f);
}
animator.setTarget(this);
animator.setDuration(500);
animator.setInterpolator(new DecelerateInterpolator());
animator.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
Float value = (Float) animator.getAnimatedValue();
matrix.postScale(value, value, x, y);
checkBorderAndCenterWhenScale();
setImageMatrix(matrix);
/**
*
* , ,
*/
if (checkRestScale()) {
matrix.set(oldMatrix);
setImageMatrix(matrix);
return;
}
/**
*
* ,
*
*/
if (getMatrixValueX() >= mDoubleClickScale)
{
matrix.postScale(mDoubleClickScale/getMatrixValueX(), mDoubleClickScale/getMatrixValueX(), x, y);
checkBorderAndCenterWhenScale();
setImageMatrix(matrix);
return;
}
}
});
}
/**
*
*
* @return true , false
*/
private boolean isZoomChanged() {
float[] values = new float[9];
getImageMatrix().getValues(values);
// X
float scale = values[Matrix.MSCALE_X];
// X ,
oldMatrix.getValues(values);
return scale != values[Matrix.MSCALE_X];
}
/**
* Matrix
*/
private void reSetMatrix() {
if (checkRestScale()) {
matrix.set(oldMatrix);
setImageMatrix(matrix);
return;
}
}
/**
*
*/
private void setDoubleClickScale(RectF rectF)
{
if(rectF.height()<getHeight()-100)
{
mDoubleClickScale=getHeight()/rectF.height();
}
else
mDoubleClickScale=2f;
}
/**
*
*
* @return ,
*/
private boolean checkRestScale() {
// TODO Auto-generated method stub
float[] values = new float[9];
getImageMatrix().getValues(values);
// X
float scale = values[Matrix.MSCALE_X];
// X ,
oldMatrix.getValues(values);
return scale < values[Matrix.MSCALE_X];
}
private float getMatrixValueX()
{
// TODO Auto-generated method stub
float[] values = new float[9];
getImageMatrix().getValues(values);
// X
float scale = values[Matrix.MSCALE_X];
// X ,
oldMatrix.getValues(values);
return scale / values[Matrix.MSCALE_X];
}
/**
* ,
*/
private void checkBorderAndCenterWhenScale()
{
RectF rect = getMatrixRectF();
float deltaX = 0;
float deltaY = 0;
int width = getWidth();
int height = getHeight();
// ,
if (rect.width() >= width)
{
if (rect.left > 0)
{
deltaX = -rect.left;
}
if (rect.right < width)
{
deltaX = width - rect.right;
}
}
if (rect.height() >= height)
{
if (rect.top > 0)
{
deltaY = -rect.top;
}
if (rect.bottom < height)
{
deltaY = height - rect.bottom;
}
}
// ,
if (rect.width() < width)
{
deltaX = width * 0.5f - rect.right + 0.5f * rect.width();
}
if (rect.height() < height)
{
deltaY = height * 0.5f - rect.bottom + 0.5f * rect.height();
}
Log.e("TAG", "deltaX = " + deltaX + " , deltaY = " + deltaY);
matrix.postTranslate(deltaX, deltaY);
setImageMatrix(matrix);
}
/**
* Matrix
*
* @return
*/
private RectF getMatrixRectF()
{
RectF rect = new RectF();
Drawable d = getDrawable();
if (null != d)
{
rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
matrix.mapRect(rect); // , Log 。
}
Log.e("aaaa",""+rect.bottom+" "+rect.left+" "+rect.right+" "+rect.top);
return rect;
}
@Override
public void onGlobalLayout() {
if (once)
{
Drawable d = getDrawable();
if (d == null)
return;
Log.e("TAG", d.getIntrinsicWidth() + " , " + d.getIntrinsicHeight());
int width = getWidth();
int height = getHeight();
//
int dw = d.getIntrinsicWidth();
int dh = d.getIntrinsicHeight();
float scale = 1.0f;
// ,
if (dw > width && dh <= height)
{
scale = width * 1.0f / dw;
}
if (dh > height && dw <= width)
{
scale = height * 1.0f / dh;
}
// ,
if (dw > width && dh > height)
{
scale = Math.min(width * 1.0f / dw, height * 1.0f / dh);
}
initScale = scale;
Log.e("TAG", "initScale = " + initScale);
matrix.postTranslate((width - dw) / 2, (height - dh) / 2);
matrix.postScale(scale, scale, getWidth() / 2,
getHeight() / 2);
//
setImageMatrix(matrix);
oldMatrix.set(getImageMatrix());
once = false;
RectF rectF=getMatrixRectF();
setDoubleClickScale(rectF);
}
}
}
에이,이미 다 썼 지만 해결 되 지 않 은 문제 가 하나 더 있 습 니 다.바로 그림 을 끝까지 이동 하 는 것 입 니 다.이때 손 을 놓 지 말고 반대 방향 으로 이동 하면 문제 가 발생 합 니 다.그림 의 반대 방향 부분 이 가 려 져 서 볼 수 없습니다.그리고 이동 할 때 그림 을 직접 자 르 고 그림 을 계속 이동 하지 않 습 니 다.이 문 제 는 그림 을 끝까지 이동 할 때 사건 을 viewpager 에 맡 기 고 그림 을 반대 방향 으로 이동 하 더 라 도 viewpager 는 사건 을 계속 차단 하기 때 문 입 니 다.현재 해결 되 지 않 았 다.위 에서 말 한 것 은 작은 편집자 가 여러분 에 게 소개 한 viewPager 에서 두 손가락 으로 그림 을 축소 하고 두 손가락 으로 그림 을 축소 하 는 것 은 한 손가락 으로 그림 을 끌 어 당 기 는 실현 방향 입 니 다.여러분 에 게 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 메 시 지 를 남 겨 주세요.작은 편집자 가 신속하게 답 해 드 리 겠 습 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.