2

Can someone please explain to a noob the correct way to animate a View so its touch area and image actually move together?!

I have read lots of posts and questions and tutorials, but none explains what moves the layout and what moves the image such that I can animate a view and then leave it at its new position.

This is an example method I'm working with, trying lots of different combinations to no success. The view is in the parent RelativeLayout. It's a touchable menu of icons, and is animated with an xml resource on a click to slide off screen leaving just a little tab showing, where it needs to stay until clicked again.

public void RetractTools (View v){      
    final ImageView finalImage1 = (ImageView) findViewById(R.id.paintsView);
    Animation slideout = AnimationUtils.loadAnimation(this, R.anim.slideout_tools);
    slideout.setFillAfter(true);
    slideout.setAnimationListener(new AnimationListener() {
        @Override
        public void onAnimationEnd(Animation animation) {
            finalImage1.setEnabled(true);
            optionMenu.showing = false;
            optionMenu.inMotion = false;
            finalImage1.layout(1258, 668, 1697, 752);
            finalImage1.setRight(1280);
            finalImage1.invalidate();
        }

        @Override
        public void onAnimationRepeat(Animation arg0) {
        }

        @Override
        public void onAnimationStart(Animation arg0) {
            finalImage1.setEnabled(false);
        }
    });

    optionMenu.inMotion = true;
    v.startAnimation(slideout);
 }// End RetractMenu

No matter what I try, I encounter problems. setFillAfter does nothing when set in the xml file. Set programmatically, it leaves the image in the right place but the touch controls remain where the menu was. I have tried setLeft and setRight which apparently only move the image, not the view position, and all sorts of different layout options, and fill and no fill and invalidating and not, but can't solve it. I clearly don't undersatnd the underlying mechanics needed to position and render a view! :D

Thanks.

EDIT : Solution

For anyone having similar issues, this is how I have found to work with relative layouts. You create a LayoutParams object with the specified size, and then you can assign it positions. eg.

    final RelativeLayout.LayoutParams position = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);           
    position.leftMargin = 440;

Then assign that to your view

    myView.setLayoutParams(position);

So in summary, you use a LayoutParams object as an interface to your view's position, rather than accessing the view's coordinates directly as I assumed.

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Tickled Pink
  • 969
  • 2
  • 14
  • 26

1 Answers1

2

What you have is basically fine, with two flaws:

  1. You are using setFillAfter(), which is not especially useful

  2. You are calling layout() and setRight() and stuff, which is not especially effective

Instead, in onAnimationEnd(), you need to modify the LayoutParams of the View to reflect the new position you want the widget to be in. The size and position of a widget is dictated by the layout rules it negotiates with its container. Initially, those are set via your layout XML resource. By modifying the LayoutParams at runtime, you are changing what those rules are.

What those LayoutParams are (LinearLayout.LayoutParams, RelativeLayout.LayoutParams, etc.) and what values you should specify in them, we cannot tell you, because we don't know what you are doing.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Thanks. I thought .Layout() changed the layout parameters directly? If I use the same code with the setFillAfter and setRight lines removed, then it works except at the end of the animation there's a one frame glitch where nothing is drawn. the values are for for a fixed function display. It's a private app for my own use on my TF101, so I don't care about using hard coded values. ;) – Tickled Pink Apr 13 '12 at 13:09
  • Also, if I keep the setFillAfter() and remove the .Layout(), the animation is exactly what I want but the view's touch layout remains behind. – Tickled Pink Apr 13 '12 at 13:14
  • @TickledPink: "I thought .Layout() changed the layout parameters directly?" -- they will be replaced by the layout-driven rules. That is why you need to adjust the `LayoutParams`. – CommonsWare Apr 13 '12 at 13:21
  • Okay, so if I understand right, I should do something like add: final RelativeLayout.LayoutParams main = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT) ; main.leftMargin = 1060; main.topMargin = 620; and then call finalImage1.setLayoutParams(main); to position finalimage1? – Tickled Pink Apr 13 '12 at 13:44
  • @TickledPink: Um, I guess so. Figure out what it would look like in a layout XML file if `finalimage1` was in its final position, then set up the `RelativeLayout.LayoutParams` the same way. – CommonsWare Apr 13 '12 at 14:00
  • Okay, thanks. Can't say I'm having much luck, but I'll persevere! ;) – Tickled Pink Apr 13 '12 at 16:00
  • @CommonsWare hi im making my layout animate from xml anim/slide_in as in xml defined animations the values for fromXDelta to toXDelta are in percent, is there any way i can convert these values to pixels so i can apply layout() or layout params after animating to make view shift – Muhammad Babar Apr 08 '13 at 04:37