Since Android 3.0 (API level 11), a lot of effort has gone into improving the visual appeal of the operating system. In addition to adding eye candy to the builtin software, Google also introduced new features in the Android development frameworks that make it easier for third-party developers to improve the look and feel of their own applications. One such improvement is the ability to add animations to existing ViewGroup
elements (i.e. every layout object) without having to write the code by hand.
When using the android:animateLayoutChanges attribute with a ViewGroup
, a set of default animations are registered on the ViewGroup
‘s child views during layout changes. By default, visibility and size modifications are taken into account. The first produces a fading effect and the second produces a sliding animation.
These two default effects can be used together with a LinearLayout
to make a nice transition between two states of the same widget:
In the video above, my widget has two different presentation modes: one for user selection and the other for drag-and-drop interaction. The latter mode is triggered by a user action (starting the drag).
Here is the relevant part of my layout XML for the widget skeleton:
<LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="16dp" android:layout_marginTop="16dp" android:layout_marginRight="16dp" android:animateLayoutChanges="true" android:id="@+id/animatedLayout"> <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="7dp" android:id="@+id/mode1"> <!-- Widget mode 1 layout --> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_width="wrap_content" android:layout_height="1px" android:layout_gravity="center" android:id="@+id/mode2"> <!-- Widget mode 2 layout --> </LinearLayout> </LinearLayout>
The outer LinearLayout
is the one that contains the android:animateLayoutChanges
attribute. Both widget modes are also LinearLayout
objects.
Since the first mode is the one shown by default, its layout height is set to wrap_content
whereas the second mode layout is artificially hidden by setting its height to 1 pixel.
To go from mode 1 to mode 2, I use the following code in the drag started event handler:
var parms = mode2.LayoutParameters as LinearLayout.LayoutParams; parms = new LinearLayout.LayoutParams (parms) { Height = ViewGroup.LayoutParams.WrapContent, Gravity = GravityFlags.Center }; mode2.LayoutParameters = parms; mode1.Visibility = ViewStates.Gone;
And to go the other way, we simply restore the XML state we had beforehand with a similar code:
mode1.Visibility = ViewStates.Visible; var parms = mode2.LayoutParameters as LinearLayout.LayoutParams; parms = new LinearLayout.LayoutParams (parms) { Height = 1, Gravity = GravityFlags.Center }; mode2.LayoutParameters = parms;