안 드 로 이 드 멀 티 터치 기술 실전 사진 자유 크기 조정 및 이동
만약 당신 이 아직 이 글 을 보지 못 했다 면,가능 한 한 먼저 읽 고 나 서 이 글 을 보 세 요.왜냐하면 이번 코드 는 완전히 지난번 의 기초 위 에서 개 발 된 것 이기 때 문 입 니 다.
그럼 지금부터 시작 하 겠 습 니 다.먼저 지난번 PhotoWall Falls Demo 프로젝트 를 열 고 Zoom ImageView 류 를 추가 합 니 다.이 종 류 는 큰 그림 전시 와 다 중 터치 크기 조정 에 사 용 됩 니 다.코드 는 다음 과 같 습 니 다.
public class ZoomImageView extends View {
/**
*
*/
public static final int STATUS_INIT = 1;
/**
*
*/
public static final int STATUS_ZOOM_OUT = 2;
/**
*
*/
public static final int STATUS_ZOOM_IN = 3;
/**
*
*/
public static final int STATUS_MOVE = 4;
/**
*
*/
private Matrix matrix = new Matrix();
/**
* Bitmap
*/
private Bitmap sourceBitmap;
/**
* , STATUS_INIT、STATUS_ZOOM_OUT、STATUS_ZOOM_IN STATUS_MOVE
*/
private int currentStatus;
/**
* ZoomImageView
*/
private int width;
/**
* ZoomImageView
*/
private int height;
/**
* ,
*/
private float centerPointX;
/**
* ,
*/
private float centerPointY;
/**
* , ,
*/
private float currentBitmapWidth;
/**
* , ,
*/
private float currentBitmapHeight;
/**
*
*/
private float lastXMove = -1;
/**
*
*/
private float lastYMove = -1;
/**
*
*/
private float movedDistanceX;
/**
*
*/
private float movedDistanceY;
/**
*
*/
private float totalTranslateX;
/**
*
*/
private float totalTranslateY;
/**
*
*/
private float totalRatio;
/**
*
*/
private float scaledRatio;
/**
*
*/
private float initRatio;
/**
*
*/
private double lastFingerDis;
/**
* ZoomImageView , STATUS_INIT。
*
* @param context
* @param attrs
*/
public ZoomImageView(Context context, AttributeSet attrs) {
super(context, attrs);
currentStatus = STATUS_INIT;
}
/**
* 。
*
* @param bitmap
* Bitmap
*/
public void setImageBitmap(Bitmap bitmap) {
sourceBitmap = bitmap;
invalidate();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (changed) {
// ZoomImageView
width = getWidth();
height = getHeight();
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_POINTER_DOWN:
if (event.getPointerCount() == 2) {
// ,
lastFingerDis = distanceBetweenFingers(event);
}
break;
case MotionEvent.ACTION_MOVE:
if (event.getPointerCount() == 1) {
// ,
float xMove = event.getX();
float yMove = event.getY();
if (lastXMove == -1 && lastYMove == -1) {
lastXMove = xMove;
lastYMove = yMove;
}
currentStatus = STATUS_MOVE;
movedDistanceX = xMove - lastXMove;
movedDistanceY = yMove - lastYMove;
// ,
if (totalTranslateX + movedDistanceX > 0) {
movedDistanceX = 0;
} else if (width - (totalTranslateX + movedDistanceX) > currentBitmapWidth) {
movedDistanceX = 0;
}
if (totalTranslateY + movedDistanceY > 0) {
movedDistanceY = 0;
} else if (height - (totalTranslateY + movedDistanceY) > currentBitmapHeight) {
movedDistanceY = 0;
}
// onDraw()
invalidate();
lastXMove = xMove;
lastYMove = yMove;
} else if (event.getPointerCount() == 2) {
// ,
centerPointBetweenFingers(event);
double fingerDis = distanceBetweenFingers(event);
if (fingerDis > lastFingerDis) {
currentStatus = STATUS_ZOOM_OUT;
} else {
currentStatus = STATUS_ZOOM_IN;
}
// , 4 ,
if ((currentStatus == STATUS_ZOOM_OUT && totalRatio < 4 * initRatio)
|| (currentStatus == STATUS_ZOOM_IN && totalRatio > initRatio)) {
scaledRatio = (float) (fingerDis / lastFingerDis);
totalRatio = totalRatio * scaledRatio;
if (totalRatio > 4 * initRatio) {
totalRatio = 4 * initRatio;
} else if (totalRatio < initRatio) {
totalRatio = initRatio;
}
// onDraw()
invalidate();
lastFingerDis = fingerDis;
}
}
break;
case MotionEvent.ACTION_POINTER_UP:
if (event.getPointerCount() == 2) {
//
lastXMove = -1;
lastYMove = -1;
}
break;
case MotionEvent.ACTION_UP:
//
lastXMove = -1;
lastYMove = -1;
break;
default:
break;
}
return true;
}
/**
* currentStatus 。
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
switch (currentStatus) {
case STATUS_ZOOM_OUT:
case STATUS_ZOOM_IN:
zoom(canvas);
break;
case STATUS_MOVE:
move(canvas);
break;
case STATUS_INIT:
initBitmap(canvas);
default:
canvas.drawBitmap(sourceBitmap, matrix, null);
break;
}
}
/**
* 。
*
* @param canvas
*/
private void zoom(Canvas canvas) {
matrix.reset();
//
matrix.postScale(totalRatio, totalRatio);
float scaledWidth = sourceBitmap.getWidth() * totalRatio;
float scaledHeight = sourceBitmap.getHeight() * totalRatio;
float translateX = 0f;
float translateY = 0f;
// , 。
if (currentBitmapWidth < width) {
translateX = (width - scaledWidth) / 2f;
} else {
translateX = totalTranslateX * scaledRatio + centerPointX * (1 - scaledRatio);
// ,
if (translateX > 0) {
translateX = 0;
} else if (width - translateX > scaledWidth) {
translateX = width - scaledWidth;
}
}
// , 。
if (currentBitmapHeight < height) {
translateY = (height - scaledHeight) / 2f;
} else {
translateY = totalTranslateY * scaledRatio + centerPointY * (1 - scaledRatio);
// ,
if (translateY > 0) {
translateY = 0;
} else if (height - translateY > scaledHeight) {
translateY = height - scaledHeight;
}
}
// ,
matrix.postTranslate(translateX, translateY);
totalTranslateX = translateX;
totalTranslateY = translateY;
currentBitmapWidth = scaledWidth;
currentBitmapHeight = scaledHeight;
canvas.drawBitmap(sourceBitmap, matrix, null);
}
/**
*
*
* @param canvas
*/
private void move(Canvas canvas) {
matrix.reset();
//
float translateX = totalTranslateX + movedDistanceX;
float translateY = totalTranslateY + movedDistanceY;
//
matrix.postScale(totalRatio, totalRatio);
//
matrix.postTranslate(translateX, translateY);
totalTranslateX = translateX;
totalTranslateY = translateY;
canvas.drawBitmap(sourceBitmap, matrix, null);
}
/**
* , , 。
*
* @param canvas
*/
private void initBitmap(Canvas canvas) {
if (sourceBitmap != null) {
matrix.reset();
int bitmapWidth = sourceBitmap.getWidth();
int bitmapHeight = sourceBitmap.getHeight();
if (bitmapWidth > width || bitmapHeight > height) {
if (bitmapWidth - width > bitmapHeight - height) {
// , ,
float ratio = width / (bitmapWidth * 1.0f);
matrix.postScale(ratio, ratio);
float translateY = (height - (bitmapHeight * ratio)) / 2f;
// ,
matrix.postTranslate(0, translateY);
totalTranslateY = translateY;
totalRatio = initRatio = ratio;
} else {
// , ,
float ratio = height / (bitmapHeight * 1.0f);
matrix.postScale(ratio, ratio);
float translateX = (width - (bitmapWidth * ratio)) / 2f;
// ,
matrix.postTranslate(translateX, 0);
totalTranslateX = translateX;
totalRatio = initRatio = ratio;
}
currentBitmapWidth = bitmapWidth * initRatio;
currentBitmapHeight = bitmapHeight * initRatio;
} else {
// ,
float translateX = (width - sourceBitmap.getWidth()) / 2f;
float translateY = (height - sourceBitmap.getHeight()) / 2f;
matrix.postTranslate(translateX, translateY);
totalTranslateX = translateX;
totalTranslateY = translateY;
totalRatio = initRatio = 1f;
currentBitmapWidth = bitmapWidth;
currentBitmapHeight = bitmapHeight;
}
canvas.drawBitmap(sourceBitmap, matrix, null);
}
}
/**
* 。
*
* @param event
* @return
*/
private double distanceBetweenFingers(MotionEvent event) {
float disX = Math.abs(event.getX(0) - event.getX(1));
float disY = Math.abs(event.getY(0) - event.getY(1));
return Math.sqrt(disX * disX + disY * disY);
}
/**
* 。
*
* @param event
*/
private void centerPointBetweenFingers(MotionEvent event) {
float xPoint0 = event.getX(0);
float yPoint0 = event.getY(0);
float xPoint1 = event.getX(1);
float yPoint1 = event.getY(1);
centerPointX = (xPoint0 + xPoint1) / 2;
centerPointY = (yPoint0 + yPoint1) / 2;
}
}
이 종 류 는 전체 멀 티 터치 크기 조정 기능 의 가장 핵심 적 인 유형 이기 때문에 제 가 여기 서 상세 하 게 설명해 드 리 겠 습 니 다.우선 ZoomImageView 에서 우 리 는 네 가지 상 태 를 정 의 했 습 니 다.STATUSINIT、STATUS_ZOOM_OUT、STATUS_ZOOM_IN 과 STATUSMOVE,이 네 가지 상 태 는 각각 초기 화,확대,축소 와 이동 을 나타 내 고 구조 함수 에서 우 리 는 현재 상 태 를 초기 화 상태 로 설정 합 니 다.이 어 setImageBitmap()방법 으로 표시 할 그림 대상 을 전송 할 수 있 습 니 다.이 방법 은 현재 View 를 invalidate 하기 때문에 onDraw()방법 이 실 행 됩 니 다.그리고 onDraw()방법 에서 현재 상태 가 초기 화 상태 임 을 판단 하기 때문에 initBitmap()방법 으로 초기 화 작업 을 합 니 다.그러면 initBitmap()방법 을 살 펴 보 겠 습 니 다.이 방법 에서 먼저 그림 의 크기 를 판단 하 였 습 니 다.그림 의 너비 와 높이 가 화면의 너비 와 높이 보다 작 으 면 이 그림 을 화면 에 표시 할 수 있 도록 직접 오프셋 하 였 습 니 다.만약 에 그림 의 너비 가 화면의 너비 보다 크 거나 그림 의 높이 가 화면의 높이 보다 크 면 그림 을 등 비례 로 압축 하여 그림 의 너비 나 높이 가 화면의 너비 나 높이 와 똑 같 게 하고 초기 화 상태 에서 그림 이 반드시 온전 하 게 표 시 될 수 있 도록 한다.이 곳 의 모든 오프셋 과 크기 조정 작업 은 행렬 을 통 해 이 루어 집 니 다.크기 조정 과 오프셋 할 값 을 행렬 에 저장 한 다음 그림 을 그 릴 때 이 행렬 대상 에 전송 하면 됩 니 다.
그림 초기 화가 완료 되면 그림 크기 를 조정 할 수 있 습 니 다.여기 서 onTouchEvent()방법 으로 클릭 이 벤트 를 판단 합 니 다.두 손가락 이 동시에 화면 에 누 르 는 것 을 발견 하면(event.getPointerCount()로 판단)현재 상 태 를 크기 조정 상태 로 설정 하고 distance Between Fingers()를 호출 하여 두 손가락 사이 의 거 리 를 얻어 크기 조정 비율 을 계산 합 니 다.그리고 invalidate 가 되면 onDraw()방법 에서 zoom()방법 을 호출 합 니 다.그 다음 에 이 방법 에서 현재 크기 조정 비율 과 중심 점 의 위치 에 따라 그림 을 크기 조정 하고 오프셋 합 니 다.구체 적 인 논 리 는 코드 를 자세히 읽 으 십시오.주석 은 이미 매우 명확 하 게 쓰 여 있 습 니 다.
그 다음 에 한 손가락 만 화면 에 눌 렀 을 때 현재 상 태 를 이동 상태 로 설정 한 다음 에 손가락 의 이동 거 리 를 계산 하고 경계 검사 작업 을 처리 하여 그림 이 화면 에서 벗 어 나 지 않도록 합 니 다.그리고 invalidate 는 현재 view 를 보고 onDraw()방법 에 들 어 갑 니 다.현재 이동 상태 임 을 판단 하여 move()방법 을 호출 합 니 다.move()방법 중의 코드 는 매우 간단 하 다.손가락 이 이동 하 는 거리 에 따라 그림 을 오프셋 하면 된다.
ZoomImageView 를 소개 하고 레이아웃 image 를 새로 만 듭 니 다.details.xml,레이아웃 에서 만 든 ZoomImageView 를 직접 참조 합 니 다.
<?xml version="1.0" encoding="utf-8"?>
<com.example.photowallfallsdemo.ZoomImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/zoom_image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000" >
</com.example.photowallfallsdemo.ZoomImageView>
이어서 Activity 를 만 들 고 이 Activity 에 image 를 불 러 옵 니 다.details 레이아웃.새 ImageDetails Activity,코드 는 다음 과 같 습 니 다.
public class ImageDetailsActivity extends Activity {
private ZoomImageView zoomImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.image_details);
zoomImageView = (ZoomImageView) findViewById(R.id.zoom_image_view);
String imagePath = getIntent().getStringExtra("image_path");
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
zoomImageView.setImageBitmap(bitmap);
}
}
먼저 ZoomImageView 의 인 스 턴 스 를 얻 은 다음 Intent 를 통 해 보 여줄 그림 경 로 를 얻 었 습 니 다.이 어 BitmapFactory 를 사용 하여 경로 에 있 는 그림 을 메모리 에 불 러 온 다음 ZoomImageView 의 setImageBitmap()방법 으로 그림 을 전송 하면 이 그림 을 보 여줄 수 있 습 니 다.다음은 사진 벽 에 클릭 이 벤트 를 추가 해서 ImageDetails Activity 를 시작 할 수 있 도록 하 는 방법 을 고려 해 야 한다.사실 이것 도 간단 합 니 다.그림 을 동적 으로 추가 할 때 모든 ImageView 의 인 스 턴 스 에 클릭 이 벤트 를 등록 하면 됩 니 다.MyScrollView 에서 addImage()방법의 코드 를 수정 하면 다음 과 같 습 니 다.
private void addImage(Bitmap bitmap, int imageWidth, int imageHeight) {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(imageWidth,
imageHeight);
if (mImageView != null) {
mImageView.setImageBitmap(bitmap);
} else {
ImageView imageView = new ImageView(getContext());
imageView.setLayoutParams(params);
imageView.setImageBitmap(bitmap);
imageView.setScaleType(ScaleType.FIT_XY);
imageView.setPadding(5, 5, 5, 5);
imageView.setTag(R.string.image_url, mImageUrl);
imageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getContext(), ImageDetailsActivity.class);
intent.putExtra("image_path", getImagePath(mImageUrl));
getContext().startActivity(intent);
}
});
findColumnToAdd(imageView, imageHeight).addView(imageView);
imageViewList.add(imageView);
}
}
이 를 통 해 알 수 있 듯 이 이미지 뷰 의 setOnClickListener()방법 을 사용 하여 그림 에 클릭 이 벤트 를 추가 하고 사용자 가 사진 벽 에 있 는 임의의 그림 을 클릭 하면 이미지 Details Activity 를 시작 하여 그림 의 경 로 를 전달 합 니 다.새로운 Activity 를 추 가 했 기 때문에 AndroidManifest.xml 파일 에 등록 하 는 것 을 잊 지 마 세 요.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.photowallfallsdemo"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.photowallfallsdemo.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.example.photowallfallsdemo.ImageDetailsActivity" >
</activity>
</application>
</manifest>
이렇게 하면 모든 인 코딩 작업 이 이미 완성 되 었 습 니 다.지금 우 리 는 프로그램 을 실행 하면 익숙 한 사진 벽 화면 을 볼 수 있 습 니 다.임의의 그림 을 클릭 하면 해당 하 는 큰 그림 인터페이스 에 들 어 갈 수 있 고 여러 개의 터치 제어 방식 으로 그림 을 확대 할 수 있 습 니 다.확대 한 후에 한 손가락 으로 그림 을 이동 할 수 있 습 니 다.다음 그림 과 같 습 니 다.원본 다운로드:Android 폭포 흐름 사진 벽 구현,불규칙 배열 체험
자,이상 은 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저희 도 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.