Wednesday, June 3, 2015

MyNotes: ColorFilterToolbar Pt. 1

XML Resource Updates

This entry is going to focus on the XML resource changes for the update.

New UI

A lot of the heavy lifting for the new UI is actually done in the XML resources which makes the code a lot simpler compared to old design.   This includes a nice alpha effect that occurs on all supported versions of android.  It also includes an elevation transition when a filter is enabled/disabled and a ripple animation on press.  Unfortunately, these only occur on Lollipop.

Enter video caption here

Drawable Selector: Alpha Change

To get the alpha effect I updated the xml drawable selectors to include a new translucent color as the default selector.

drawable/blue_button_selector.xml:

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <selector xmlns:android="http://schemas.android.com/apk/res/android"> 
  3.  
  4.     <item android:state_checked="true" 
  5.           android:drawable="@color/note_blue" /> 
  6.  
  7.     <item android:drawable="@color/note_blue_translucent" /> 
  8. </selector> 

values/colors_note.xml:






  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <resources> 
  3.     <item name="note_blue" type="color">#99CCFF</item> 
  4.     <item name="note_blue_translucent" type="color">#5599CCFF</item> 
  5.  
  6.     <item name="note_gray" type="color">#C4C4C4</item> 
  7.     <item name="note_gray_translucent" type="color">#55C4C4C4</item> 
  8.  
  9.     <item name="note_green" type="color">#9BED9B</item> 
  10.     <item name="note_green_translucent" type="color">#559BED9B</item> 
  11.  
  12.     <item name="note_pink" type="color">#FFB2D1</item> 
  13.     <item name="note_pink_translucent" type="color">#55FFB2D1</item> 
  14.  
  15.     <item name="note_purple" type="color">#D1B2F0</item> 
  16.     <item name="note_purple_translucent" type="color">#55D1B2F0</item> 
  17.  
  18.     <item name="note_yellow" type="color">#FFFF99</item> 
  19.     <item name="note_yellow_translucent" type="color">#55FFFF99</item> 
  20. </resources> 

The selector switches the drawable used based on the state of the View.  In this case, my View is a ToggleButton so it supports the checked state. 


Elevation Change


This is done using a State List Animator that translates the View along the Z-Axis on a state change.


animator/color_filter_item_selector.xml:


All this does is change the elevation level based on the checked state of the View using the






  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <!-- animate the elevation change when the color filter item is selected vs unselected. --> 
  3. <selector xmlns:android="http://schemas.android.com/apk/res/android"> 
  4.     <item android:state_checked="true"> 
  5.         <objectAnimator 
  6.             android:duration="@android:integer/config_shortAnimTime" 
  7.             android:propertyName="translationZ" 
  8.             android:valueFrom="@dimen/color_filter_item_off_elevation" 
  9.             android:valueTo="@dimen/color_filter_item_on_elevation" 
  10.             android:valueType="floatType"/> 
  11.     </item> 
  12.  
  13.     <item> 
  14.         <objectAnimator 
  15.             android:duration="@android:integer/config_shortAnimTime" 
  16.             android:propertyName="translationZ" 
  17.             android:valueFrom="@dimen/color_filter_item_off_elevation" 
  18.             android:valueTo="@dimen/color_filter_item_on_elevation" 
  19.             android:valueType="floatType"/> 
  20.     </item> 
  21. </selector> 

All this does is change the elevation level based on the checked state of the View.


The next step is where things get tricky.  Since I am supporting pre-Lollipop devices I wanted to use the StateListAnimator without getting a bunch of warnings.  To get around this I defined three Styles:


values/styles.xml:






  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <resources> 
  3. ...  
  4.     <!-- The common attributes for the color filter items --> 
  5.     <style name="ColorFilterItemParent"> 
  6.         <item name="android:textOn"></item> 
  7.         <item name="android:textOff"></item> 
  8.     </style> 
  9. ...  
  10. </resources> 

This file contains the base styles.  The base styles contain the common attributes across all of the versions.  Then I derive the base style in styles_derived.xml.


values/styles_derived.xml






  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <!-- This file contains the unique configurations for the derived styles from styles.xml  
  3.      In this case there aren't any additional details but this file exists to prevent the need  
  4.      to reduce the need to branch the layout folders. --> 
  5. <resources> 
  6.     ...  
  7.     <style name="ColorFilterItem" parent="ColorFilterItemParent" /> 
  8.     ...  
  9. </resources> 

This file isn’t that interesting because nothing really fun happens before Lollipop.  The lollipop specific attributes are in values-21/styles_derived.xml.


values-21/styles_derived.xml:







  1. <?xml version="1.0" encoding="utf-8"?> 
  2.  
  3. <!-- This file contains the unique configurations for the lollipop derived styles from styles.xml  
  4.      This file primarily exists to prevent the need to reduce the need to branch the layout  
  5.      folders. --> 
  6. <resources> 
  7.     ...  
  8.     <style name="ColorFilterItem" parent="ColorFilterItemParent"> 
  9.         <item name="android:stateListAnimator">@animator/color_filter_item_selector</item> 
  10.     </style> 
  11.     ...  
  12. </resources> 

This comes together in the layout file.


layout/recycler_item_color_filter_item.xml:






  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <ToggleButton 
  3.     android:id="@+id/recycler_item_color_filter_check_view" 
  4.     xmlns:android="http://schemas.android.com/apk/res/android" 
  5.     style="@style/ColorFilterItem" 
  6.     android:layout_width="match_parent" 
  7.     android:layout_height="@dimen/color_filter_item_long_side" /> 

The style attribute will pick the correct style for the SDK version being run on the device.  This way only the Lollipop versions get the stateListAnimator and I don’t get a bunch of warnings in the xml.


Ripple Animation


This is only supported in Lollipop, but I want a common background resource.  To fix this I take advantage of the different resource configurations.  The ripple is in the v21 drawable folders.


drawable-v21/blue_color_filter_background.xml:






  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <ripple xmlns:android="http://schemas.android.com/apk/res/android" 
  3.         android:color="@android:color/white"> 
  4.     <item android:drawable="@drawable/blue_note_selector"/> 
  5. </ripple> 

What this is doing is creating a white ripple on press.  I still want my normal selector to work, so I specified that as the item drawable.


Since this only works in Lollipop, I created a version of the blue_color_filter_background.xml drawable for the pre-Lollipop builds:


drawable/blue_color_filter_background.xml:






  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <!-- Exists to support Pre-Lollipop Versions with a single NoteColors enum --> 
  3. <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> 
  4.     <item android:drawable="@drawable/blue_note_selector"/> 
  5. </layer-list> 

Commit


The commit for these changes can be found at https://github.com/fsk-software/mynotes/commit/e24614e2557ab6791e2f00617895c0fd4e726526.

No comments :

Post a Comment