Showing posts with label Android Animation. Show all posts
Showing posts with label Android Animation. Show all posts

Sunday, 29 January 2012

Android animation.Part-II


In this part we will focus on solving advance animation problems in Android. We have done simple animation in our previous tutorial now we will try create a more complex animation in a simpler way. We will create a simple animation that moves a Button from the top left corner of the screen to the center when it is clicked, then remains there, and when clicked again it moves back to its original position.

After you read the documentation http://developer.android.com/guide/topics/resources/animation-resource.h... it may seem easy to solve. We can define the animation relative to the parents size in percent (50%p), and the fillAfter attribute makes the button remain there, instead of jumping back to its original position. We can even define all of this in XML below.

      <?xml version="1.0" encoding="utf-8"?>
2       <translate xmlns:android="http://schemas.android.com/apk/res/android"
3          android:fromXDelta="0%p" android:fromYDelta="0%p"
4          android:toXDelta="50%p" android:toYDelta="50%p"
5          android:duration="1000"
6          android:fillAfter="true" />
But when you try this out, you will face two problems. First, the button will not be properly centered, the buttons top left corner will be in the center. Second, after it moved to the center it won’t be clickable any more. The clickable area of the button does not move with the animation, if you try to click at the original position of the button you will be able to trigger the onclick again. Unfortunately such a simple code, like the xml above will not be enough to fix these simple problem.
To properly center the button we must compute where the buttons top left corner should be. When the button is clicked get the buttons size, and its parent views size, compute where it should move, and create the proper animation by code. Somehow we have to track where the button is, if it is already in the middle, we have to reverse the animation. This can be done like this:
      public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
      final Button button = (Button) findViewById(R.id.button);
        final RelativeLayout mainContainer = (RelativeLayout)findViewById(R.id.mainContainer);
              button.setOnClickListener(new OnClickListener() {
           @Override
            public void onClick(View v) {
          //have to get the sizes here instead of onCreate, in onCreate size is not         //computed yet
          int buttonHeight = button.getHeight();
          int parentHeight = mainContainer.getHeight();
         int buttonWidth = button.getWidth ();
          int parentWidth  = mainContainer.getWidth();
       
        //detect if have to move to center, or already there and have to move back
         boolean isInCenter = button.getLeft()>0;
        final int fromX = isInCenter?(parentWidth/2)-(buttonWidth/2):0;
        final int fromY = isInCenter?(parentHeight/2)-(buttonHeight/2):0;
        final int toX = isInCenter?0:(parentWidth/2)-(buttonWidth/2);
        final int toY = isInCenter?0:(parentHeight/2)-(buttonHeight/2);
       
        //create the animation
            TranslateAnimation moveAnim = new TranslateAnimation(
            TranslateAnimation.ABSOLUTE, fromX, TranslateAnimation.ABSOLUTE, toX,
            TranslateAnimation.ABSOLUTE, fromY, TranslateAnimation.ABSOLUTE, toY);
                    moveAnim.setDuration(1000);
                    moveAnim.setFillAfter(true);

To solve the clickinkig problem we have to really move the button when the animation ended. This can be done by setting up an animation listener to detect the end of the animation. In the listener we set up margins to do the move. Because of this we have to remove this margins the next time we animate button or, the margins will mess it up. So we also add a listener to detect the start of the animation, and remove the margins there.


      moveAnim.setAnimationListener(new AnimationListener() {
        @Override
      public void onAnimationEnd(Animation animation) {
      //when the animation ended the button is really moved, to remain clickable
     LayoutParam params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
     params.leftMargin = toX;
     params.topMargin = toY;
     button.setLayoutParams(params);
          //remove the animation, its no longer needed, since button is really there
     button.clearAnimation();
    }
  
    @Override
    public void onAnimationStart(Animation animation) {
      //remove the margins used to really move the button, or it messes up the animation
    LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    params.leftMargin = 0;
    params.topMargin = 0;
    button.setLayoutParams(params);
    }
    @Override
    public void onAnimationRepeat(Animation animation) {
      //do nothing
    }
  });


Enjoy.... 
Do post your doubts, queries or suggestions in this blog.

Saturday, 28 January 2012

Android basics of animation.Parrt-I

In android we have four  basic types of animations:
  • AlphaAnimation
  • RotateAnimation
  • ScaleAnimation
  • TranslateAnimation
This animations can be highly customized and combined, for example we can set the speed, delay, acceleration, duration of animations, then group them together in an AnimationSet.
Animations can be applyed as Layout animations to ViewGroups, to be triggered when the ViewGroup is created/displayed or applied to any view and be triggered by us any time.
The animations can be definex in XMl or by code. Defining in xml is mutch more clear, but you can not set animation parameters dinamically.
The animation XML files should be created in the res/anim folder and can be accessed using the R class, like R.anim.animation_name.
An animation defined in anim_jump.xml can look like this:
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <set xmlns:android="http://schemas.android.com/apk/res/android">
  3.         <scale android:interpolator="@android:anim/accelerate_decelerate_interpolator"
  4.                 android:fromXScale="0.0" android:toXScale="1.4"android:fromYScale="0.0"
  5.                 android:toYScale="1.4" android:pivotX="50%"android:pivotY="50%"
  6.                 android:fillAfter="false" android:duration="700" />
  7.         <scale android:fromXScale="1.4" android:toXScale="0.8"
  8.                 android:fromYScale="1.4" android:toYScale="0.8"android:pivotX="50%"
  9.                 android:pivotY="50%" android:startOffset="700"android:duration="400"
  10.                 android:fillBefore="false" />
  11. </set>

The set tag can contain one or more animation definitions that will be applied at the same time, so if you want to play them after each other you can set a startOffset value for the second one.
This animation can be played on any view with a code like this:
  1. final Button button3 = (Button) findViewById(R.id.button3);
  2. button3.startAnimation(AnimationUtils.loadAnimation(Main.this, R.anim.anim_jump));

The exapmle below shows the creation of an animation without an XML file:
  1. //parameters set to do a full circle around its center
  2. RotateAnimation rotateAnimation = newRotateAnimation(0,360,Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
  3. rotateAnimation.setDuration(500);
  4. rotateAnimation.setRepeatCount(2);
  5. //you can set many other parameters here
  6. final Button button1 = (Button) findViewById(R.id.button1);
  7. button1.startAnimation(rotateAnimation);

Creating complex animation sets are mutch more clean in XML, the example below creates an animation set from 3 animations by code:
  1. AnimationSet animationSet = new AnimationSet(true);
  2.                                
  3. RotateAnimation rotateAnimation = newRotateAnimation(0,360,Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
  4. rotateAnimation.setDuration(500);
  5. rotateAnimation.setRepeatCount(2);
  6.                                
  7. animationSet.addAnimation(rotateAnimation);
  8.                                
  9. TranslateAnimation translateAnimation = new TranslateAnimation(0, 400, 0, 0);
  10.                                
  11. //setting offset and duration to start after first rotation completed, and end at the same time with the last roration
  12. translateAnimation.setStartOffset(500);
  13. translateAnimation.setDuration(1000);
  14.                                
  15. animationSet.addAnimation(translateAnimation);
  16.                                
  17. AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
  18. alphaAnimation.setStartOffset(500);
  19. alphaAnimation.setDuration(1000);
  20.                                
  21. animationSet.addAnimation(alphaAnimation);
  22. final Button button2 = (Button) findViewById(R.id.button2);
  23. button2.startAnimation(animationSet);

If we want do apply the animation already defined in anim_jump.xml as a layout animation, to play on all element in the group we need one more XML file in the res/anim folder to define this animation as a layout animation. Lets name this file as main_layout_animation.xml:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:animation="@anim/anim_jump&quot; />

After this we can apply this animation to a viewGrop, for example to a LinearLayout:
  1. LinearLayout mainContainer = (LinearLayout) findViewById(R.id.mainContainer);
  2. LayoutAnimationController controller =AnimationUtils.loadLayoutAnimation(this, R.anim.main_layout_animation);
  3. mainContainer.setLayoutAnimation(controller);


Enjoy.... 
Do post your doubts, queries or suggestions in this blog.