free counters
Diberdayakan oleh Blogger.

Rabu, 27 Januari 2016

Custom view With Multiple Value Using Flags attributes on Android

by Unknown  |  in pemrograman at  Rabu, Januari 27, 2016

Most standard Android UI views give us very general usage than can be used in many tasks and many situations. But in some apps we need to be able to customize those standard views to suit our own needs.

We can customizing standard view to create our custom views by extending View or an existing subclass. There are generally 3 three steps to create our custom view:
   1. Extend View by subclassing
   2. Define custom attributes
   3. Add logic based on the attributes

In this article, we will extending TextView to create our custom view. The Custom view, which we called CustomTextView, will be a simple TextView with prefix and suffix. The prefix can be bolded, italized, large, or the combination of those three attributes. We will achieve like picture below:



To have a combination of attribute value, we must use attribute with flags. More on this later.



Extend View by Subclassing

Because we extending TextView we must create our own class, CustomTextView, like this:
  public class CustomTextView extends TextView {  
   public CustomTextview(Context context, AttributeSet attrs) {  
    super(context, attrs);  
   }  
  }  
TextView has many different constructors, but for most purpose it's sufficient to implement just one like the code above. Also for the shake of simplicity of the article, I don't show the rest of the code.

Define Custom Attributes

Our custom view will have attribute to set prefix, suffix, and the text style of suffix. There are 3 text style for prefix: Bold, Italic, and Large. So we need to create three attributes for them like this:
1:  <resources>  
2:    <declare-styleable name="CustomTextView">  
3:     <attr format="string" name="ct_prefix">  
4:     <attr format="string" name="ct_suffix">  
5:     <attr name="ct_prefix_style">  
6:       <flag name="Bold" value="1">  
7:       <flag name="Italic" value="2">  
8:       <flag name="Large" value="4">  
9:     </flag></flag></flag></attr>  
10:    </attr></attr></declare-styleable>  
11:   </resources>  
We use flags because it is the only attribute types that allow us to combine multiple value. It's like when we use android:textStyle, where we can define text as both bold and italic value with android:textStyle="bold|italic". Read more at Android: Custom XML attributes and views .

Maybe you a little confused by the flags values. We use values of 1, 2, and 4 for Bold, Italic, and Large names respectively because it is easier working with when OR-ing them. Those values; 1, 2, and 4 are decimal values from binary values. Please look at the table below:

Decimal Binary
1 0001
2 0010
4 0100

So when OR-ing them like Bold|Italic (Bold = 1, Italic = 2), we will get the value of 3 which is 0011 in decimal. The effect is, we can't lose our flags value!


Add logic Based On The Attributes

To access the attributes from code, we must get the attributes by using obtainStyledAttributes() method like the following code:
 final TypedArray attributes = context.obtainStyledAttributes(attrs,R.styleable.CustomTextView, defStyleAttr, defStyleRes);  

Then we can get each attribute by using the attributes object, like this:
 final CharSequence prefix = attributes.getText(R.styleable.CustomTextView_ct_prefix);  
 final CharSequence suffix = attributes.getText(R.styleable.CustomTextView_ct_suffix);  
 prefixStyle = attributes.getInteger(R.styleable.CustomTextView_ct_prefix_style, 0);  
Remember to give back resource to system by recycle th attributes:
 attributes.recycle();  

After we have all the value from attributes, we do the work based on the value. Here we will work with ct_prefix_style because it's more difficult than other.

Because we working with the chance of combined value from ct_prefix_style flags, we handle it by AND-ing it to get the value.

For everyone who don't remember what is AND-ing, I try to explain it with AND table below, where x is AND-ed with y:

X Y Result
0 0 0
0 1 0
1 0 0
1 1 1

every value AND-ed with 0 will be 0, and only value 1 AND-end with 1 will be 1.

Back to main story. We AND-ing the ct_prefix_style attribute value with each flag value like below:
  if((prefixStyle & PrefixStyle.BOLD) == PrefixStyle.BOLD) {  
   spannableString.setSpan(new TextAppearanceSpan(getContext(), R.style.Bold), 0, prefix.length(), 0);  
  }  
  if((prefixStyle & PrefixStyle.ITALIC) == PrefixStyle.ITALIC) {  
   spannableString.setSpan(new TextAppearanceSpan(getContext(), R.style.Italic), 0, prefix.length(), 0);  
  }  
  if((prefixStyle & PrefixStyle.LARGE) == PrefixStyle.LARGE) {  
   spannableString.setSpan(new TextAppearanceSpan(getContext(), R.style.Large), 0, prefix.length(), 0);  
  }  

where the PrefixStyle variables are from PrefixStyle class:
1:   public class PrefixStyle {  
2:    public static final int BOLD = 1;  
3:    public static final int ITALIC = 2;  
4:    public static final int LARGE = 4;  
5:   }  
Here the prefixStyle is AND-ed to check if flag attribute is used or not.

Then we can apply the style to the text.

To use our CustomTextView, we just add the xml code like below:
1:  <io.github.joielechong.CustomTextView  
2:    android:layout_centerHorizontal="true"  
3:    android:text="10000"  
4:    android:layout_width="wrap_content"  
5:    android:layout_height="wrap_content"  
6:    custom:ct_prefix="$"  
7:    android:textSize="24sp"  
8:    custom:ct_suffix="-"  
9:    custom:ct_prefix_style="Bold|Italic"  
10:  />  

Don't forget to add the following code at your root layout:
 xmlns:custom="http://schemas.android.com/apk/res-auto"  


For the complete library and example source code, you can get at CustomTextView in my github.

Every critiques, suggestions, and correction are really appreciated.

1 komentar:

  1. So the flag values don't necessarily have to be numbers based on a binary values; the important thing is that they keep a one-to-one correspondence with the proper configuration value you want to set, isn't it?

    BalasHapus

Silahkan tinggalkan komentar anda: