可滚动显示图片的 ImageView —— PanningImageView

前言

参考这篇博文,在此基础上,做了些改进。比如,用 ValueAnimator 代替 ObjectAnimator, 代码更加简洁(在这种情况下,ValueAnimator 比 ObjectAnimator 更加方便,自定义控件就不自定义属性了)。此外,设置 Animator 的 RepeatMode 为 Reverse,不用如同博客里面的样子切换方向。最后,对各种尺寸的图片的支持。当不 panning 的时候,centerCrop 显示。

原理

简单来说,不断的改变 ImageView 的 Matrix。(所以要setScaleType(ScaleType.MATRIX);)使用 ValueAnimator 做节拍器。剩下的逻辑就是判断控件的尺寸和图像的尺寸,确定要不要滚动显示,并计算出scaleRatiotranslateXtranslateY

效果图

源码

package com.sinaapp.myron.panningimageviewdemo;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.widget.ImageView;

public class PanningImageView extends ImageView implements ValueAnimator.AnimatorUpdateListener {

    private int duration = 15000;

    private float scaleRatio;
    private final Matrix matrix = new Matrix();

    private ValueAnimator animator;

    public PanningImageView(Context context) {
        super(context);
    }

    public PanningImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public PanningImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        init();
    }

    // why this method will be called twice, i reset the matrix to work around it.
    private void init() {
        setScaleType(ScaleType.MATRIX);
        float vWidth = getMeasuredWidth();
        float vHeight = getMeasuredHeight();
        float dWidth = getDrawable().getIntrinsicWidth();
        float dHeight = getDrawable().getIntrinsicHeight();
        if (dWidth / dHeight > vWidth / vHeight) {
            // panning image
            scaleRatio = vHeight / dHeight;
            matrix.reset();
            matrix.postScale(scaleRatio, scaleRatio);
            setImageMatrix(matrix);

//            RectF rectF = new RectF(0, 0, getDrawable().getIntrinsicWidth(), getDrawable().getIntrinsicHeight());
//            matrix.mapRect(rectF);
//        maxTranslateX = rectF.width() - getMeasuredWidth();

//            animator = ValueAnimator.ofFloat(rectF.left, rectF.left-(rectF.right-getMeasuredWidth()));
            animator = ValueAnimator.ofFloat(0, vWidth - dWidth * scaleRatio);
            animator.setDuration(duration);
            animator.setRepeatCount(ValueAnimator.INFINITE);
            animator.setRepeatMode(ValueAnimator.REVERSE);
            animator.addUpdateListener(this);
            post(new Runnable() {
                @Override
                public void run() {
                    animator.start();
                }
            });
        } else {
            // no panning image, looks like 'centerCrop'
            scaleRatio = vWidth / dWidth;
            matrix.reset();
            matrix.postScale(scaleRatio, scaleRatio);
//            RectF rectF = new RectF(0, 0, dWidth, dHeight);
//            matrix.mapRect(rectF);

            float translateY = (dHeight * scaleRatio - vHeight) * 0.5F;
//            float translateY = (rectF.height() - vHeight) * 0.5F;
            matrix.postTranslate(0, -translateY);
            setImageMatrix(matrix);
        }
    }

    @Override
    public void onAnimationUpdate(ValueAnimator valueAnimator) {
        matrix.reset();
        matrix.postScale(scaleRatio, scaleRatio);
        matrix.postTranslate((Float) valueAnimator.getAnimatedValue(), 0);
        setImageMatrix(matrix);
    }
}

TODO

在不显示的时候停止动画。

你可能感兴趣的:(Android)