2014年3月21日金曜日

Android ImageViewの領域を角丸にする方法

1. ImageViewを継承したクラスを用意する

  1. public class RoundImageView extends ImageView {  
  2.     ...  
  3. }  


2. 角丸の黒い9patch画像もしくはshapeを用意する

res/drawable/mask.xml
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <shape xmlns:android="http://schemas.android.com/apk/res/android" >  
  3.     <corners android:radius="32dp" />  
  4.     <solid android:color="#000000" />  
  5. </shape>  


3. onDraw()で SRC_ATOP を使ってくりぬく

  1. public class RoundImageView extends ImageView {  
  2.   
  3.     Paint mMaskedPaint;  
  4.     Paint mCopyPaint;  
  5.     Drawable mMaskDrawable;  
  6.   
  7.     public RoundImageView(Context context) {  
  8.         this(context, null);  
  9.     }  
  10.   
  11.     public RoundImageView(Context context, AttributeSet attrs) {  
  12.         super(context, attrs);  
  13.   
  14.         mMaskedPaint = new Paint();  
  15.         mMaskedPaint.setXfermode(new PorterDuffXfermode(  
  16.                 PorterDuff.Mode.SRC_ATOP));  
  17.   
  18.         mCopyPaint = new Paint();  
  19.         mMaskDrawable = getResources().getDrawable(R.drawable.mask);  
  20.     }  
  21.   
  22.     Rect mBounds;  
  23.     RectF mBoundsF;  
  24.   
  25.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
  26.         mBounds = new Rect(00, w, h);  
  27.         mBoundsF = new RectF(mBounds);  
  28.     }  
  29.   
  30.     @Override  
  31.     protected void onDraw(Canvas canvas) {  
  32.         int sc = canvas.saveLayer(mBoundsF, mCopyPaint,  
  33.                 Canvas.HAS_ALPHA_LAYER_SAVE_FLAG  
  34.                         | Canvas.FULL_COLOR_LAYER_SAVE_FLAG);  
  35.   
  36.         mMaskDrawable.setBounds(mBounds);  
  37.         mMaskDrawable.draw(canvas);  
  38.   
  39.         canvas.saveLayer(mBoundsF, mMaskedPaint, 0);  
  40.   
  41.         super.onDraw(canvas);  
  42.   
  43.         canvas.restoreToCount(sc);  
  44.     }  
  45. }  


4. カスタムビューとして使う

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:paddingBottom="@dimen/activity_vertical_margin"  
  6.     android:paddingLeft="@dimen/activity_horizontal_margin"  
  7.     android:paddingRight="@dimen/activity_horizontal_margin"  
  8.     android:paddingTop="@dimen/activity_vertical_margin"  
  9.     tools:context=".MainActivity" >  
  10.   
  11.     <com.example.roundimage.RoundImageView  
  12.         android:layout_width="96dp"  
  13.         android:layout_height="96dp"  
  14.         android:src="@drawable/image1" />  
  15.   
  16. </RelativeLayout>  


2014年3月13日木曜日

Android Pattern Cookbookを執筆しました。

3月20日発売です。

念願のフルカラー本を出すことができました!やったー!
(今週中には表紙画像が載るはず)

3月21日のAndroid Bazaar and Conference 2014 Springのインプレスジャパンさんのブースで直売&サイン会をします。

タブレット対応のパターンとかいろいろ書きました。参考になればと思います。


目次
  • 1章 : Structure - アプリの構成と階層
  • 2章 : Branding - オリジナリティを出す
  • 3章 : Helps - ユーザーを導く
  • 4章 : ViewPager - 画面切り替えの定番
  • 5章 : Support Tablet - 柔軟性のあるレイアウト
  • 6章 : CustomView - 思い通りのレイアウト
  • 7章 : Advanced - 1つ上のカスタマイズ


2014年3月7日金曜日

Android CheckedTextViewでチェック状態を保持させる

CheckBoxやRadioButtonはチェック状態を保持するけどCheckedTextViewはしてくれません。

CheckBoxやRadioButtonはCompoundButtonを継承しているのですが、このコードを見ると以下のようにonSaveInstanceState()とonRestoreInstanceState()できちんと処理されています。

http://tools.oesf.biz/android-4.4.2_r1.0/xref/frameworks/base/core/java/android/widget/CompoundButton.java#364
  1. 364     @Override  
  2. 365     public Parcelable onSaveInstanceState() {  
  3. 366         // Force our ancestor class to save its state  
  4. 367         setFreezesText(true);  
  5. 368         Parcelable superState = super.onSaveInstanceState();  
  6. 369   
  7. 370         SavedState ss = new SavedState(superState);  
  8. 371   
  9. 372         ss.checked = isChecked();  
  10. 373         return ss;  
  11. 374     }  
  12. 375   
  13. 376     @Override  
  14. 377     public void onRestoreInstanceState(Parcelable state) {  
  15. 378         SavedState ss = (SavedState) state;  
  16. 379   
  17. 380         super.onRestoreInstanceState(ss.getSuperState());  
  18. 381         setChecked(ss.checked);  
  19. 382         requestLayout();  
  20. 383     }  
一方、CheckedTextViewではそのような処理は見あたりません。
http://tools.oesf.biz/android-4.4.2_r1.0/xref/frameworks/base/core/java/android/widget/CheckedTextView.java

なのでCheckedTextViewを継承して上記の処理を移植すれば、チェック状態を保持してくれるようになります。
  1. public class CheckedTextView2 extends CheckedTextView {  
  2.   
  3.     public CheckedTextView2(Context context) {  
  4.         super(context);  
  5.     }  
  6.   
  7.     public CheckedTextView2(Context context, AttributeSet attrs) {  
  8.         super(context, attrs);  
  9.     }  
  10.   
  11.     public CheckedTextView2(Context context, AttributeSet attrs, int defStyle) {  
  12.         super(context, attrs, defStyle);  
  13.     }  
  14.   
  15.     static class SavedState extends BaseSavedState {  
  16.         boolean checked;  
  17.   
  18.         /** 
  19.          * Constructor called from {@link CompoundButton#onSaveInstanceState()} 
  20.          */  
  21.         SavedState(Parcelable superState) {  
  22.             super(superState);  
  23.         }  
  24.   
  25.         /** 
  26.          * Constructor called from {@link #CREATOR} 
  27.          */  
  28.         private SavedState(Parcel in) {  
  29.             super(in);  
  30.             checked = (Boolean) in.readValue(null);  
  31.         }  
  32.   
  33.         @Override  
  34.         public void writeToParcel(Parcel out, int flags) {  
  35.             super.writeToParcel(out, flags);  
  36.             out.writeValue(checked);  
  37.         }  
  38.   
  39.         @Override  
  40.         public String toString() {  
  41.             return "CheckedTextView2.SavedState{"  
  42.                     + Integer.toHexString(System.identityHashCode(this))  
  43.                     + " checked=" + checked + "}";  
  44.         }  
  45.   
  46.         public static final Parcelable.Creator<SavedState> CREATOR  
  47.              = new Parcelable.Creator<SavedState>() {  
  48.             public SavedState createFromParcel(Parcel in) {  
  49.                 return new SavedState(in);  
  50.             }  
  51.   
  52.             public SavedState[] newArray(int size) {  
  53.                 return new SavedState[size];  
  54.             }  
  55.         };  
  56.     }  
  57.   
  58.     @Override  
  59.     public Parcelable onSaveInstanceState() {  
  60.         // Force our ancestor class to save its state  
  61.         setFreezesText(true);  
  62.         Parcelable superState = super.onSaveInstanceState();  
  63.   
  64.         SavedState ss = new SavedState(superState);  
  65.   
  66.         ss.checked = isChecked();  
  67.         return ss;  
  68.     }  
  69.   
  70.     @Override  
  71.     public void onRestoreInstanceState(Parcelable state) {  
  72.         SavedState ss = (SavedState) state;  
  73.   
  74.         super.onRestoreInstanceState(ss.getSuperState());  
  75.         setChecked(ss.checked);  
  76.         requestLayout();  
  77.     }  
  78. }