× {{alert.msg}} Never ask again
Get notified about new tutorials RECEIVE NEW TUTORIALS

How to define a screen-size specific animation in XML

Xaver Kapeller
Mar 13, 2015
<h1>1) Regarding the bounty:</h1> <blockquote> <p><a href="http://stackoverflow.com/questions/4932462/animate-the-transition-between-fragments"><strong>Existing answers on SO</strong></a> suggest subclassing the FrameLayout...</p> </blockquote> <p>If you want to use an <code>ObjectAnimator</code> you have no choice but to subclass the <code>View</code> you want to animate. You need to provide the <code>ObjectAnimator</code> with the necessary getter and setter methods to do its magic as it essentially just calls those getter and setter methods to perform the <code>Animation</code>.</p> <p>The question you are linking to (<strong><a href="http://stackoverflow.com/questions/4932462/animate-the-transition-between-fragments">Animate the transition between fragments</a></strong>) is subclassing <code>FrameLayout</code> to add a <code>setXFraction()</code> and a <code>getXFraction()</code> method. They are implemented in a way to set the x value relative to the width of the <code>FrameLayout</code>. Only by doing this can the <code>ObjectAnimator</code> do anything else besides animating between absolute values.</p> <p>So to summarise, the <code>ObjectAnimator</code> itself doesn't actually do much animating, it just calls getter and setter methods through reflection. </p> <blockquote> <p>Is there really no way to get the actual screen pixel dimensions (not just dp) into the xml file?</p> </blockquote> <p>With an <code>ObjectAnimator</code> there is no way to achieve that. <code>ObjectAnimators</code> just interpolate from a start value to and end value. As I explained above, the setter method defines what actually happens.</p> <blockquote> <p>For example, calling a custom function that returns the width would be fine, or defining a constant that code can set, having code set said constant to equal the screen width, then accessing that constant from the xml would be equally useful.</p> </blockquote> <p>You cannot insert any value from code into any xml resource. Everything contained in your xml files is compiled into your APK when you build it and <strong>cannot</strong> be changed at runtime. And that is also an answer to your other question: There is no resource or constant or anything which would be accessible in xml which contains the current screen size. Dynamic values like the screen size of the device the app is installed on cannot be a part of those resources since everything in them is compiled into your app when you build it.</p> <hr> <h1>2) Possible Solution: View Animations</h1> <p>One possible solution is to use view animations instead of an <code>ObjectAnimator</code>. With view animations you can specify fractions instead of just absolute values:</p> <pre><code>&lt;set xmlns:android="http://schemas.android.com/apk/res/android"&gt; &lt;translate android:fromYDelta="-100%" android:toYDelta="0%" android:duration="1000"/&gt; &lt;/set&gt; </code></pre> <p>This would animate a <code>View</code> from <code>-100%</code> to <code>0%</code> of the screen height. In other words from completely of the screen to the position of the <code>View</code>. You can use it like this:</p> <pre><code>Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.slide_down); view.startAnimation(animation); </code></pre> <p>I realise that this might not be of any help to you. There are cases in which one has to use <code>ObjectAnimators</code> and cannot use view animations. But as long as you are able to use view animations this should pretty much solve your problem.</p> <ul> <li><a href="http://developer.android.com/guide/topics/graphics/view-animation.html"><strong>Link to documentation</strong></a></li> <li><a href="http://stackoverflow.com/a/19766034/2310866"><strong>Related question</strong></a></li> </ul> <hr> <h1>3) Best practice</h1> <p>What we really should be addressing here is what I think is a misconception on your part. As you already noticed every animation you define in xml has absolute start and end values. Those values are static and cannot be changed after compiling your app.</p> <p>If you look at how the resources work with the many available selectors and also with dp, sp... then you will realise that it is designed to do one thing:<br> You can for example define an animation that moves a <code>View</code> by 100dp. Dp is a measurement of physical size, 100dp will be the exact same physical size one any screen with any pixel density. Through selectors you could alter this animation for devices with smaller or bigger screens where the animation may be moving the <code>View</code> too much or too little. But you can only fill in static values. Aside from working with selectors you cannot customise the animation for each device.</p> <p>So you see, the resources are really just designed for anything that's static and unchanging. It works great for dimensions or string translations but sometimes with animations it can be a bit of a pain. As I said above only view animations provide a way around the static nature by providing the option of specifying fractions instead of absolute values. But in general you cannot define anything dynamic in xml.</p> <p>To futher corroborate this argument look at Google's excellent DevBytes videos about animation:</p> <ul> <li><a href="https://www.youtube.com/watch?v=_UWXqFBF86U"><strong>View Animations</strong></a></li> <li><a href="https://www.youtube.com/watch?v=CPxkoe2MraA"><strong>Custom Activity Animations</strong></a></li> <li><a href="https://www.youtube.com/watch?v=pMcu35-tVls"><strong>Cardflip Animation</strong></a></li> <li><a href="https://www.youtube.com/watch?v=3UbJhmkeSig"><strong>Property Animations</strong></a></li> <li><a href="https://www.youtube.com/watch?v=8MIfSxgsHIs"><strong>ListView Animations</strong></a></li> </ul> <p>Then you will notice that not a single animation in those examples is ever defined in xml. Sure one could argue that they don't define them in xml because they want to have an easier time explaining and showing the code, but in my opinion this once again proves one point:</p> <p><strong>You cannot define an animation in static resources which depends on a purely dynamic value</strong></p> <p>Since the screen width/height will be different from device to device you need different animations for each device. Only view animations provide a way around that since they allow you to define fractions instead of absolute values. In any other case you are going to need to define the animations programmatically. Fortunately that's not difficult with <code>ObjectAnimators</code>:</p> <pre><code>Animator animator = ObjectAnimator.ofFloat(view, View.X, startValue, endValue); animator.start(); </code></pre> <p>This would animate the x position of the <code>View</code> from the start to the end value in pixels. You can pass in the width of the <code>View</code> to animate it like you want to:</p> <pre><code>Animator animator = ObjectAnimator.ofFloat(view, View.X, -view.getWidth(), 0.0f); animator.start(); </code></pre> <p>This would animate the <code>View</code> to slide in from the left. It starts completely off screen and stops in its final position. You could also just do this:</p> <pre><code>view.animate().x(targetValue); </code></pre> <p>This would animate the <code>View</code> from its current x position to the target x value. </p> <p>But please don't misunderstand me, you should still try to define as much as possible - be it animations or anything else - in the resources. Hardcoding animations or any other value should be avoided as much as possible, unless it's necessary like in your case.</p> <hr> <h1>4) Summary</h1> <p>So to summarise:</p> <ul> <li>You cannot do what you want to do with <code>ObjectAnimators</code> without adding the getter and setter methods you need to the <code>View</code> you want to animate.</li> <li>If possible use <a href="http://developer.android.com/guide/topics/graphics/view-animation.html"><strong>view animations</strong></a>. With them you can define animations based on fractions of the width or height of the <code>View</code>.</li> <li>If the above doesn't work or is not applicable to your situation then define the animations <a href="http://developer.android.com/guide/topics/graphics/prop-animation.html#object-animator"><strong>programmatically</strong></a>, this will work in any case.</li> </ul> <p>I hope I could help you and if you have any further questions feel free to ask!</p> <p>This tip was originally posted on <a href="http://stackoverflow.com/questions/15881555/How%20to%20define%20a%20screen-size%20specific%20animation%20in%20XML/24482870">Stack Overflow</a>.</p>
comments powered by Disqus