2014年5月21日 星期三

Android 開發 (四十六) Decorate Pattern and SpannableString

在開發app的時候常常會遇到一些特殊的文字,例如
$2000 , $2000 or...

通常遇到這些需求時,會用最簡單的做法去解決問題,使用Utils class專為這個需求
寫一個method,然後呢...然後就完成了,就這樣過了一陣子之後會發現,越來越多的Utils class
在處理這些特殊字元,然後等到要做refactor時就發現,這邊一些code,那邊一些code,以為改完了,結果發現又漏了一些沒改到,其實我們可以在開始的時候就將問題先narrow down,


Decorate Pattern

此pattern主要的特色就是你可以在你原本的東西上面任意加上想要的配料。
怎麼說呢?  例如手搖飲料店,今天我想喝珍珠 + 椰果 + 仙草 + 奶茶。
我總不可能為了他寫一個Utils class吧。那如果有人要點
珍珠 + 椰果 + 仙草 + 奶茶 去 仙草, 那我的程式碼不就重複了。

最好的做法是甚麼?

珍珠,椰果,仙草,這些配料我可以隨意添加,然後最後在配上我的茶類即可。
這就是Decorate Pattern的概念。

回到原本的需求,為了達到這個目標,我目前會有三個class
RedString , Image, 可以把這些當作任意添加的配料,然後最終還是得配上 String

所以,依照這樣的配置,我會寫出類似下面的code


public interface EndDecorate {
 public CharSequence getCharSequence();

 public static class MyEndDecorate implements EndDecorate{
  private String str;
  public MyEndDecorate(String _str){
   str = _str;
  }
  
  @Override
  public CharSequence getCharSequence() {
   SpannableString span = new SpannableString(str);   
   return span;
  }
  
 }
 
 public static class StringDecorate implements EndDecorate {
  private EndDecorate nexDecorate;
  public StringDecorate(EndDecorate _nexDecorate){
   nexDecorate = _nexDecorate;
  }
  
  @Override
  public CharSequence getCharSequence() {

   return nexDecorate.getCharSequence();
  }

 }
 
 public static class AddStringDecorate extends StringDecorate{
  private String newString;
  public AddStringDecorate(EndDecorate _nexDecorate,String _newString) {
   super(_nexDecorate);
   newString = _newString;
  }
  
  @Override
  public CharSequence getCharSequence() {
   SpannableString span = new SpannableString(newString);   
   return TextUtils.concat(super.getCharSequence(),span); 
  }  
 }
 
 public static class RedStringDecorate extends StringDecorate{
  private String RedString;
  public RedStringDecorate(EndDecorate _nexDecorate,String _RedString) {
   super(_nexDecorate);
   RedString = _RedString;
  }
  
  @Override
  public CharSequence getCharSequence() {
   SpannableString span = new SpannableString(RedString);
   span.setSpan(new ForegroundColorSpan(Color.RED), 0, span.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
   return TextUtils.concat(super.getCharSequence(),span); 
  }
 }
 
 public static class ImageDecorate extends StringDecorate{
  Drawable drawable;
  public ImageDecorate(EndDecorate _nexDecorate,Drawable _drawable) {
   super(_nexDecorate);
   drawable = _drawable;
  }
  
  @Override
  public CharSequence getCharSequence() {
   SpannableString spannable = new SpannableString(" ");
   ImageSpan span = new ImageSpan(drawable, ImageSpan.ALIGN_BASELINE);
   spannable.setSpan(span, 0,
     spannable.length(),
     Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
   return TextUtils.concat(super.getCharSequence(),spannable);
  }
  
 }
}


接著要怎麼使用呢

   Drawable draw = getResources().getDrawable(android.R.drawable.ic_menu_search);    
   draw.setBounds(0, 0, 70, 70);   
   EndDecorate img = new ImageDecorate(myend,draw);
   EndDecorate add = new AddStringDecorate(img," searchButton ");
   ((EditText)rootView.findViewById(R.id.textview)).setHint(add.getCharSequence());

這樣就可以將想要的圖片和字套用到我的textview中了,
用起來很方便,而且維護起來也很容易,每個class 都只負責自己該添加的東西,

不過目前有遇到圖片無法自動置中的問題,我也還沒有解決的方法,或許之後會找到解決方法再提供給大家。

沒有留言:

張貼留言