2015-11-26 5 views
6

Я использую https://github.com/chrisbanes/PhotoView и пытаюсь оживить его высоту.Animate Android PhotoView height

Я использую ValueAnimator и обновляю высоту компоновки, чтобы запускать внутренние и onGlobalLayout, которые преобразуют матрицу.

Есть ли какое-либо обходное решение для предотвращения изменения масштаба и положения y, так как я мог бы как-то обновить матрицу самостоятельно, чтобы сохранить положение Y изображения и scaleX/scaleY без изменений? Теперь они сбрасываются в масштаб 1.0 и y позиционный центр изображения.

код анимации:

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

Вы можете разместить код анимации? –

ответ

1

Это было более сложно, чем первая мысль. У библиотеки, похоже, нет открытых API-интерфейсов, чтобы заставить это работать, поэтому это временное решение, использующее частные методы и поля. Следующее решение, похоже, работает с моими случаями, когда я могу изменить фактическую высоту PhotoView, а масштабная позиция y остается неизменной во время анимации.

Первый продлить PhotoView и написать следующий код:

// 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

Я пошел через исходный код, но не тестировал следующий код. Из того, что я могу сказать, вы хотите заблокировать вызов до onGlobalLayout() на время анимации. Следующие должны достичь этого:

onAnimationStart():

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

onAnimationEnd():

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

Заметьте, что removeOnGlobalLayoutListener(OnGlobalLayoutListener) доступен для версий API> = 16. Перед этим вы будете использовать removeGlobalOnLayoutListener(OnGlobalLayoutListener).

onAnimationStart() и onAnimationEnd() обратные вызовы можно получить, добавив ValueAnimator.AnimatorUpdateListener к вашему ValueAnimator.

Опять же, я не знаю, будет ли это работать - похоже, должно.

Edit:

После независим от кода выше.

Вместо того, чтобы анимировать height из PhotoView, вы могли бы оживить его top & bottom свойства. В моих тестах, анимировать эти свойства не сбросить y позиции, или изменить Scalex/значение 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(); 
} 

Если вы оживляющий height, чтобы освободить место для других точек зрения выше или ниже PhotoView, оживляющего top/bottom не поможет. В этом случае использование FrameLayout для размещения PhotoView & другого Views и контроль за их видимостью может быть опцией.

+0

Этот подход имеет несколько проблем: сначала коэффициент масштабирования и позиция y сбрасываются при завершении анимации. Также, если вы прокрутите изображение вниз, а затем измените его высоту, матрица дисплея будет правильно обновляться только после анимации. – Niko

+0

@Niko Из вашего вопроса, я понял, что вы не хотите, чтобы 'PhotoView' обновлялся (приспосабливался к изменению в' height') во время анимации. Поскольку мое предположение было/неверно, можете ли вы объяснить, каково ожидаемое поведение. – Vikram

+0

Да, я хочу, чтобы высота была отрегулирована, но я также хочу, чтобы шкала и позиция y не изменялись. Может быть, объяснение было немного запутанным. – Niko