question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Erratic behavior when animating/setting padding in GestureImageView

See original GitHub issue

I was trying to come up with a way to vertically offset the image inside a GestureImageView when I noticed an erratic pattern that is not consistent.

Initially I tried to play with .setViewPort(), but that only controls the size of the image, not the position. Then I checked padding and it works, to a certain degree.

If I set the padding manually in the xml layout file the image is exactly positioned as I expect it to be, but because there is UI that overlaps the view and that UI can be toggled with sliding animation I tried to animate the padding as well.

The top and left padding animations work perfectly, but for some reason the bottom and right do not work the same way, it feels like they are being completely ignored.

This video shows a basic example of what I am describing, please ignore the jerkiness/jumps because those are due to the fullscreen entering/exiting and are irrelevant to this example.

gif5

The top and left padding animation are working as expected, however the right and bottom padding values are not. Worse, they seem to be “taken into account” when the values are set back to normal.

This feels like the viewport position is being correctly updated, but the resizing/scale of it is not.

To replicate this problem replace the following code in this location: https://github.com/alexvasilkov/GestureViews/blob/master/sample/src/main/java/com/alexvasilkov/gestures/sample/demo/adapter/PhotoPagerAdapter.java#L66-L78

With this

    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup container) {
        final ViewHolder holder = new ViewHolder(container);

        holder.image.setOnClickListener(view -> {
            onImageClick();

            // here we are simply animating all paddings of the view at the same
            // time to 200px or 0px depending on if there is a padding already set
            boolean show = holder.image.getPaddingTop() == 0;
            ValueAnimator.AnimatorUpdateListener updateListener2 = animation -> {
                holder.image.setPadding(
                    (int) animation.getAnimatedValue(),
                    (int) animation.getAnimatedValue(),
                    (int) animation.getAnimatedValue(),
                    (int) animation.getAnimatedValue()
                );
            };
            ValueAnimator valueAnimator = ObjectAnimator.ofInt(show ? 0 : 200, show ? 200 : 0);
            valueAnimator.setDuration(1000);
            valueAnimator.addUpdateListener(updateListener2);
            valueAnimator.start();
            // end of code modification, everything else is the original untouched code

        });

        settingsController.apply(holder.image);

        holder.image.getController().enableScrollInViewPager(viewPager);
        holder.image.getPositionAnimator().addPositionUpdateListener((position, isLeaving) ->
                holder.progress.setVisibility(position == 1f ? View.VISIBLE : View.INVISIBLE));
        return holder;
    }

Can we get this fixed somehow?


Note: I tried to play with changing the UI heights/real positions (not translations, but actual view repositioning) with the GestureView constrained between them, but this interferes with the gesture behavior since the height adjustments are interpreted as gestures as well if the user is touching the view during the UI transitions. I also tried to just leave the view constrained with no views changing dimensions, but when the enter/leave animation is automatically clipped at the edges of the view (as if the view limits were the device screen limits).

The only working solution that has almost worked is to play with the padding and I cannot think of anything else to try.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:9 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
ParticleCorecommented, Nov 23, 2020

I’ll close this now since the issue has been resolved and it wasn’t technically an issue with the library itself as much as it was not the proper way to do this. Now that I understood your explanation I was able to resolve my predicament and I thank you for it.

0reactions
ParticleCorecommented, Nov 23, 2020

I mentioned the exact fix in my previous comment, just put it right after you set new paddings.

You hack should also work, though it is a little bit less efficient.

In my head I was so far off from understanding something so simple. Yes, following your example it works right away, but the same issue as my hack persists: any zoom is lost between those changes - which you had already noted before - and that is where I got stuck previously.

After this I went about it this way:

  • copy the state before any transformations using .getState().getCopy()
  • modify the view port
  • copy over the old state values to the new state via .getState().set(float...)
  • call .getController().updateState()

Now the zoom is not lost because it is being restored in between viewport changes, same for rotation and translation.

Here is the full code in case it is useful for anyone else in the future:

            // change your paddings according to your needs
            // in my case I only need to make vertical changes
            image.setPadding(
                image.getPaddingStart(),
                myTopPadding,
                image.getPaddingEnd(),
                myBottomPadding
            );
            // copy your current gesture view state prior to any view port changes
            State state = image.getController().getState().copy();
            // update the viewport minus the padding values that were previously set
            image.getController().getSettings().setViewport(
                image.getWidth() - image.getPaddingLeft() - image.getPaddingRight(),
                image.getHeight() - image.getPaddingTop() - image.getPaddingBottom());
            // restore all the state valus prior to view port changes
            image.getController().getState().set(
                state.getX(),
                state.getY(),
                state.getZoom(),
                state.getRotation()
            );
            // instruct the gesture view to update itself using the new values that were set
            image.getController().updateState();

            (...) // make any further changes you want to your UI such as sliding the
                  // toolbar or any details container at the bottom of the screen out of view

Read more comments on GitHub >

github_iconTop Results From Across the Web

ImageView and FrameLayout with gestures control and ...
Erratic behavior when animating/setting padding in GestureImageView. I was trying to come up with a way to vertically offset the image ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found