Hold animation state between invalidate

198 Views Asked by At

I'm trying to conserve view state after invalidate and I'm very unsuccessful.

The thing is I have an image, which user can scale (either on right or left side). After he scales it, app will draw points on some locations and after user clicks on some of it, I want it to change (it is map with selectable cities).

The problem is that after clicking the point, I need to call invalidate() to call onDraw() again - to change the point, but after invalidate the map gets to its original state so its "unzoomed" again. Could you please tell me, how to preserve state of an animation applied to view through invalidate method?

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    if (zoomed) {
        Paint p //init Paint
        for (Location l : locations) {
            if (l.selected) {
                canvas.drawCircle(l.calculatedPixels.X, l.calculatedPixels.Y, pxFromDp(getContext(), 10), p);
            } else {
                canvas.drawCircle(l.calculatedPixels.X, l.calculatedPixels.Y, pxFromDp(getContext(), 5), p);
                p.setStyle(Paint.Style.STROKE);
                canvas.drawCircle(l.calculatedPixels.X, l.calculatedPixels.Y, pxFromDp(getContext(), 10), p);
            }
//NOTHING OF THIS WORKS CORRECTLY
        if (scaleByTownTouch && getScaleX() != scaleTo) {
            //canvas.restore();
            setScaleX(scaleTo);
            setScaleY(scaleTo);
            setPivotX(pivotX);
            setPivotY(pivotY);

            /*ScaleAnimation scaleAnimation = new ScaleAnimation(scaleFrom, scaleTo, scaleFrom, scaleTo, pivotX, pivotY);
            scaleAnimation.setDuration(0);
            scaleAnimation.setFillAfter(true);
            this.startAnimation(scaleAnimation);*/
            scaleByTownTouch = false;
        }
    }
}

@Override
public boolean onTouch(View v, MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        if (zoomed) {
            for (Location l : locations) {
                if (l.calculatedPixels.isTouchNearPoint(event.getX(), event.getY(), 50, scaleTo)) {
                    l.selected = !l.selected;
                    scaleByTownTouch = true;
                    //THIS UNZOOMS WHOLE VIEW
                    invalidate();
                    return true;
                }
            }
            zoom(new Point());
        } else {
            float xTouch = event.getX();
            float yTouch = event.getY();
            Point touch = new Point();
            touch.X = xTouch / measuredX * 100;
            touch.Y = 100 - (yTouch / measuredY * 100);
            zoom(touch);
        }
    }
    return false;
}

public void zoom(Point touch) {
    if (!scaleByTownTouch) {
        if (!zoomed) {
            if (!touch.isBelowLine()) {
                pivotX = measuredX;
                pivotY = measuredY;
                scaleTo = 1.7f;
            } else {
                pivotX = 0;
                pivotY = 0;
                scaleTo = 1.5f;
            }
            scaleFrom = 1;
        } else {
            scaleFrom = scaleTo;
            scaleTo = 1;
        }

        final MapImageView miv = this;
        ScaleAnimation scaleAnimation = new ScaleAnimation(scaleFrom, scaleTo, scaleFrom, scaleTo, pivotX, pivotY);
        scaleAnimation.setDuration(1000);
        scaleAnimation.setFillAfter(true);
        scaleAnimation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationEnd(Animation animation) {
                zoomed = !zoomed;
                miv.invalidate();
            }
        });
        this.startAnimation(scaleAnimation);
    }
}
1

There are 1 best solutions below

0
On BEST ANSWER

You should try to use Animator instead of Animation. Animation only change the rendering whereas Animator change the property of the object which will be kept after invalidate.

Take a look at ValueAnimator or ObjectAnimator.