2015-11-26 15 views
6

Tôi đang sử dụng https://github.com/chrisbanes/PhotoView và cố gắng tạo hoạt ảnh cho chiều cao của nó.Animate Android PhotoView height

Tôi sử dụng ValueAnimator và cập nhật chiều cao bố cục, để kích hoạt nội bộ PhotoViewAttacheronGlobalLayout để biến đổi ma trận.

Có cách nào khác để ngăn không cho tỷ lệ và vị trí y không thay đổi, như tôi có thể cập nhật ma trận bản thân để giữ cho vị trí của hình ảnh Y và scaleX/scaleY không thay đổi? Bây giờ chúng được đặt lại về tỷ lệ trung tâm vị trí 1.0 và y của hình ảnh.

đang Animation:

ValueAnimator animator = ValueAnimator.ofInt(start, end).setDuration(300); 

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 
     @Override 
     public void onAnimationUpdate(ValueAnimator animation) { 
      mImageView.getLayoutParams().height = (int) animation.getAnimatedValue(); 
      mImageView.requestLayout(); 
     } 
    }); 

animator.start(); 
+0

Bạn có thể gửi mã hoạt hình? –

Trả lời

1

Điều này phức tạp hơn suy nghĩ đầu tiên. Thư viện dường như không có API công khai để làm việc này, do đó, đây là giải pháp thay thế bằng cách sử dụng các phương thức và trường riêng tư. Giải pháp sau dường như hoạt động với các trường hợp của tôi, nơi tôi có thể thay đổi chiều cao thực tế của PhotoView và tỷ lệ vị trí + y không thay đổi trong quá trình hoạt ảnh.

Đầu tiên mở rộng PhotoView và viết mã sau:

// Private fields and methods 
private Matrix mBaseMatrix; 
private Field mAttacher; 
private Method mGetDrawMatrix; 
private Method mSetImageViewMatrix; 
private Method mCheckMatrixBounds; 

... 

@Override 
protected void init() { 
    super.init(); 

    getViewTreeObserver().removeOnGlobalLayoutListener(
      (ViewTreeObserver.OnGlobalLayoutListener) getIPhotoViewImplementation()); 

    getViewTreeObserver().addOnGlobalLayoutListener(
      new ViewTreeObserver.OnGlobalLayoutListener() { 
       @Override 
       public void onGlobalLayout() { 
        updateBaseMatrix(); 
       } 
      }); 
} 

private void updateBaseMatrix() { 
    try { 
     if (mBaseMatrix == null) { 
      mBaseMatrix = getMatrix("mBaseMatrix"); 
     } 

     if (mBaseMatrix != null) { 
      mBaseMatrix.setValues(new float[]{ 
        1.0f, 0.0f, 0.0f, 
        0.0f, 1.0f, 0.0f, 
        0.0f, 0.0f, 1.0f 
      }); 
     } 

     if (mAttacher == null) { 
      mAttacher = PhotoView.class.getDeclaredField("mAttacher"); 
      mAttacher.setAccessible(true); 
     } 

     if (mGetDrawMatrix == null) { 
      mGetDrawMatrix = PhotoViewAttacher.class.getDeclaredMethod("getDrawMatrix"); 
      mGetDrawMatrix.setAccessible(true); 
     } 

     Matrix drawMatrix = (Matrix) mGetDrawMatrix.invoke(mAttacher.get(this)); 

     if (mSetImageViewMatrix == null) { 
      mSetImageViewMatrix = PhotoViewAttacher.class 
        .getDeclaredMethod("setImageViewMatrix", Matrix.class); 
      mSetImageViewMatrix.setAccessible(true); 
     } 

     mSetImageViewMatrix.invoke(mAttacher.get(this), drawMatrix); 

     if (mCheckMatrixBounds == null) { 
      mCheckMatrixBounds = PhotoViewAttacher.class.getDeclaredMethod("checkMatrixBounds"); 
      mCheckMatrixBounds.setAccessible(true); 
     } 

     mCheckMatrixBounds.invoke(mAttacher.get(this)); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

private Matrix getMatrix(String fieldName) { 
    try { 
     Field f = PhotoView.class.getDeclaredField("mAttacher"); 
     f.setAccessible(true); 

     PhotoViewAttacher a = (PhotoViewAttacher) f.get(this); 

     f = PhotoViewAttacher.class.getDeclaredField(fieldName); 
     f.setAccessible(true); 

     return (Matrix) f.get(a); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

    return null; 
} 
3

tôi đã đi qua mã nguồn, nhưng đã không kiểm tra đoạn mã sau. Từ những gì tôi có thể nói, bạn muốn chặn cuộc gọi đến onGlobalLayout() trong thời lượng hoạt ảnh. Sau đây nên đạt được điều đó:

onAnimationStart():

mPhotoView.getViewTreeObserver() 
    .removeOnGlobalLayoutListener((PhotoViewAttacher)mPhotoView.getIPhotoViewImplementation()); 

onAnimationEnd():

mPhotoView.getViewTreeObserver() 
    .addOnGlobalLayoutListener((PhotoViewAttacher)mPhotoView.getIPhotoViewImplementation()); 

Lưu ý rằng removeOnGlobalLayoutListener(OnGlobalLayoutListener) hiện có sẵn cho các phiên bản API> = 16. Trước đó, bạn sẽ sử dụng removeGlobalOnLayoutListener(OnGlobalLayoutListener).

onAnimationStart()onAnimationEnd() gọi lại có sẵn bằng cách thêm ValueAnimator.AnimatorUpdateListener vào ValueAnimator của bạn.

Một lần nữa, tôi không biết điều này có hiệu quả hay không - có vẻ như nó sẽ xảy ra.

Edit:

Sau đây là độc lập với mã ở trên.

Thay vì tạo hoạt ảnh height trong số PhotoView, bạn có thể tạo ảnh động top & bottom thuộc tính của mình. Trong các thử nghiệm của tôi, sinh động các đặc tính này không thiết lập lại vị trí y, hoặc thay đổi scaleX/giá trị scaleY:

int mOrigImageViewTop, mOrigImageViewBottom; 

void crunchImageView() { 
    // Hold on to original values 
    if (mOrigImageViewTop == 0) { 
     mOrigImageViewTop = mImageView.getTop(); 
     mOrigImageViewBottom = mImageView.getBottom(); 
    } 

    // Top 
    ObjectAnimator objectAnimatorTop = ObjectAnimator.ofInt(mImageView, 
      "top", mOrigImageViewTop, 
      mOrigImageViewTop + 200 /*should be calculated dynamically*/); 

    // Bottom 
    ObjectAnimator objectAnimatorBottom = ObjectAnimator.ofInt(mImageView, 
      "bottom", mOrigImageViewBottom, 
      mOrigImageViewBottom - 200 /*should be calculated dynamically*/); 

    AnimatorSet animatorSet = new AnimatorSet(); 
    animatorSet.playTogether(objectAnimatorTop, objectAnimatorBottom); 
    animatorSet.setDuration(5000L); 
    animatorSet.start(); 
} 

Nếu bạn đang hoạt cảnh height để nhường chỗ cho quan điểm khác trên hoặc dưới PhotoView, hiệu ứng động top/bottom sẽ không giúp ích gì. Trong trường hợp này, hãy sử dụng số FrameLayout để lưu trữ PhotoView & khác Views và việc kiểm soát chế độ hiển thị của chúng có thể là một tùy chọn.

+0

Cách tiếp cận này có nhiều vấn đề, trước tiên tỷ lệ thang đo và vị trí y được định lại khi hoạt ảnh kết thúc. Ngoài ra, nếu bạn cuộn phần xem hình ảnh dưới đáy, sau đó tạo hiệu ứng cho chiều cao của nó, ma trận hiển thị sẽ được cập nhật đúng chỉ sau hoạt ảnh. – Niko

+0

@Niko Từ câu hỏi của bạn, tôi thu thập được rằng bạn không muốn 'PhotoView' cập nhật (điều chỉnh thay đổi về' chiều cao') trong khi hoạt ảnh. Vì giả định của tôi là/là sai, bạn có thể giải thích hành vi mong đợi là gì không. – Vikram

+0

Có Tôi muốn chiều cao được điều chỉnh, nhưng tôi cũng muốn quy mô và vị trí y không thay đổi. Có lẽ lời giải thích hơi khó hiểu – Niko