안 드 로 이 드 멀 티 터치 기술 실전 사진 자유 크기 조정 및 이동

18628 단어 Android멀 티 터치
지난 글 에서 저 는 여러분 을 데 리 고 안 드 로 이 드 폭포 흐름 사진 벽의 효 과 를 실 현 했 습 니 다.이런 효 과 는 매우 멋 있 지만 사실은 반제품 이 라 고 할 수 있 습 니 다.사진 벽 에 있 는 모든 사진 은 볼 수 밖 에 없 기 때 문 입 니 다.따라서 이 글 에서 우 리 는 이 기능 을 보완 하고 그림 을 클릭 하면 큰 그림 을 조회 할 수 있 는 기능 을 추가 하 며 큰 그림 을 조회 할 때 여러 개의 터치 제어 방식 으로 그림 을 확대 할 수 있다.
만약 당신 이 아직 이 글 을 보지 못 했다 면,가능 한 한 먼저 읽 고 나 서 이 글 을 보 세 요.왜냐하면 이번 코드 는 완전히 지난번 의 기초 위 에서 개 발 된 것 이기 때 문 입 니 다.
그럼 지금부터 시작 하 겠 습 니 다.먼저 지난번 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 폭포 흐름 사진 벽 구현,불규칙 배열 체험
자,이상 은 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저희 도 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기