2014年3月21日金曜日

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

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

public class RoundImageView extends ImageView { ... }

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

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

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

public class RoundImageView extends ImageView { Paint mMaskedPaint; Paint mCopyPaint; Drawable mMaskDrawable; public RoundImageView(Context context) { this(context, null); } public RoundImageView(Context context, AttributeSet attrs) { super(context, attrs); mMaskedPaint = new Paint(); mMaskedPaint.setXfermode(new PorterDuffXfermode( PorterDuff.Mode.SRC_ATOP)); mCopyPaint = new Paint(); mMaskDrawable = getResources().getDrawable(R.drawable.mask); } Rect mBounds; RectF mBoundsF; protected void onSizeChanged(int w, int h, int oldw, int oldh) { mBounds = new Rect(0, 0, w, h); mBoundsF = new RectF(mBounds); } @Override protected void onDraw(Canvas canvas) { int sc = canvas.saveLayer(mBoundsF, mCopyPaint, Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG); mMaskDrawable.setBounds(mBounds); mMaskDrawable.draw(canvas); canvas.saveLayer(mBoundsF, mMaskedPaint, 0); super.onDraw(canvas); canvas.restoreToCount(sc); } }

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

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <com.example.roundimage.RoundImageView android:layout_width="96dp" android:layout_height="96dp" android:src="@drawable/image1" /> </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 364 @Override 365 public Parcelable onSaveInstanceState() { 366 // Force our ancestor class to save its state 367 setFreezesText(true); 368 Parcelable superState = super.onSaveInstanceState(); 369 370 SavedState ss = new SavedState(superState); 371 372 ss.checked = isChecked(); 373 return ss; 374 } 375 376 @Override 377 public void onRestoreInstanceState(Parcelable state) { 378 SavedState ss = (SavedState) state; 379 380 super.onRestoreInstanceState(ss.getSuperState()); 381 setChecked(ss.checked); 382 requestLayout(); 383 } 一方、CheckedTextViewではそのような処理は見あたりません。
http://tools.oesf.biz/android-4.4.2_r1.0/xref/frameworks/base/core/java/android/widget/CheckedTextView.java

なのでCheckedTextViewを継承して上記の処理を移植すれば、チェック状態を保持してくれるようになります。 public class CheckedTextView2 extends CheckedTextView { public CheckedTextView2(Context context) { super(context); } public CheckedTextView2(Context context, AttributeSet attrs) { super(context, attrs); } public CheckedTextView2(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } static class SavedState extends BaseSavedState { boolean checked; /** * Constructor called from {@link CompoundButton#onSaveInstanceState()} */ SavedState(Parcelable superState) { super(superState); } /** * Constructor called from {@link #CREATOR} */ private SavedState(Parcel in) { super(in); checked = (Boolean) in.readValue(null); } @Override public void writeToParcel(Parcel out, int flags) { super.writeToParcel(out, flags); out.writeValue(checked); } @Override public String toString() { return "CheckedTextView2.SavedState{" + Integer.toHexString(System.identityHashCode(this)) + " checked=" + checked + "}"; } public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() { public SavedState createFromParcel(Parcel in) { return new SavedState(in); } public SavedState[] newArray(int size) { return new SavedState[size]; } }; } @Override public Parcelable onSaveInstanceState() { // Force our ancestor class to save its state setFreezesText(true); Parcelable superState = super.onSaveInstanceState(); SavedState ss = new SavedState(superState); ss.checked = isChecked(); return ss; } @Override public void onRestoreInstanceState(Parcelable state) { SavedState ss = (SavedState) state; super.onRestoreInstanceState(ss.getSuperState()); setChecked(ss.checked); requestLayout(); } }