左側にチェックがあるリスト、CheckedTextView のカスタマイズで実装する方法、
長いので分けて投稿します。今日は、準備編
今回は、ライブラリ化しません。使用するプロジェクト内に
カスタマイズの CheckedTextView と、attr.xml を用意すれうば、半分の作業が終わりです。
(1)
attrs.xml という名前のリソースXML を res/values/ に以下のように
チェックボックスの属性を定義する規則を書きます。
declare-styleable に、作成するカスタマイズの CheckedTextView名称を指定する
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="LeftCheckedTextView">
<attr name="checked" format="boolean" />
<attr name="checkMark" format="reference" />
<attr name="drawablePadding" format="dimension" />
</declare-styleable>
</resources>
この、attrs.xml により、
カスタマイズの LeftCheckedTextView をレイアウトXMLで記述する時に指定する。
app:checked false|true でチェックの初期状態
app:checkMark チェックマークのリファレンス
OS標準の四角いチェックボックの場合、
app:checkMark="?android:attr/listChoiceIndicatorMultiple"
OS標準のラジオボタンの場合、
app:checkMark="?android:attr/listChoiceIndicatorSingle"
app:drawablePadding チェックマークとテキストの間の隙間
以下が、カスタマイズの CheckedTextView
左側にチェックボックスを置く CheckedTextView です。
package uran.sample;
import uran.sample.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.accessibility.AccessibilityEvent;
import android.widget.Checkable;
import android.widget.TextView;
/**
* LeftCheckedTextView
*/
public class LeftCheckedTextView extends TextView implements Checkable{
private int mDrawablePadding;
private boolean mChecked;
private int mCheckMarkResource;
private Drawable mCheckMarkDrawable;
private int mBasePaddingRight;
private int mCheckMarkWidth;
private static final int CHECKED_STATE_SET = {
android.R.attr.state_checked
};
public LeftCheckedTextView(Context context){
this(context,null);
}
public LeftCheckedTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LeftCheckedTextView(Context context,AttributeSet attrs,int defStyle){
super(context,attrs,defStyle);
TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.LeftCheckedTextView, defStyle, 0);
mDrawablePadding = a.getDimensionPixelSize(R.styleable.LeftCheckedTextView_drawablePadding, 0);
Drawable d = a.getDrawable(R.styleable.LeftCheckedTextView_checkMark);
if (d != null){
setCheckMarkDrawable(d);
}
boolean checked = a.getBoolean(R.styleable.LeftCheckedTextView_checked, false);
setChecked(checked);
a.recycle();
}
@Override
public void toggle() {
setChecked(!mChecked);
}
@Override
public boolean isChecked(){
return mChecked;
}
/**
* Changes the checked state of this text view.
* @param checked true to check the text, false to uncheck it
*/
@Override
public void setChecked(boolean checked){
if (mChecked != checked){
mChecked = checked;
refreshDrawableState();
}
}
/**
* Set the checkmark to a given Drawable, identified by its resourece id. This will be drawn
* @param resid The Drawable to use for the checkmark.
*/
public void setCheckMarkDrawable(int resid){
if (resid != 0 && resid==mCheckMarkResource){
return;
}
mCheckMarkResource = resid;
Drawable d = null;
if (mCheckMarkResource != 0){
d = getResources().getDrawable(mCheckMarkResource);
}
setCheckMarkDrawable(d);
}
/**
* Set the checkmark to a given Drawable. This will be drawn when {@link #isChecked()} is true.
* @param d The Drawable to use for the checkmark.
*/
public void setCheckMarkDrawable(Drawable d){
if (mCheckMarkDrawable != null){
mCheckMarkDrawable.setCallback(null);
unscheduleDrawable(mCheckMarkDrawable);
}
if (d != null){
d.setCallback(this);
d.setVisible(getVisibility() == VISIBLE, false);
d.setState(CHECKED_STATE_SET);
setMinHeight(d.getIntrinsicHeight());
mCheckMarkWidth = d.getIntrinsicWidth();
mBasePaddingRight = getPaddingLeft();
super.setPadding(getPaddingLeft() + mCheckMarkWidth + mDrawablePadding
,getPaddingTop(), getPaddingRight(), getPaddingBottom());
d.setState(getDrawableState());
}
mCheckMarkDrawable = d;
requestLayout();
}
@Override
public void setPadding(int left, int top, int right, int bottom) {
if (mCheckMarkDrawable != null){
mBasePaddingRight = left;
super.setPadding(getPaddingLeft() + mCheckMarkWidth + mDrawablePadding
,getPaddingTop(), getPaddingRight(), getPaddingBottom());
}else{
super.setPadding(left, top, right, bottom);
}
}
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
final Drawable checkMarkDrawable = mCheckMarkDrawable;
if (checkMarkDrawable != null){
final int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK;
final int height = checkMarkDrawable.getIntrinsicHeight();
int y = 0;
switch(verticalGravity){
case Gravity.BOTTOM:
y = getHeight() - height;
break;
case Gravity.CENTER_VERTICAL:
y = (getHeight() - height) / 2;
break;
}
checkMarkDrawable.setBounds(mBasePaddingRight
,y
,mBasePaddingRight + mCheckMarkWidth
,y + height
);
checkMarkDrawable.draw(canvas);
}
}
@Override
protected int onCreateDrawableState(int extraSpace){
final int drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()){
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
}
return drawableState;
}
@Override
protected void drawableStateChanged(){
super.drawableStateChanged();
if (mCheckMarkDrawable != null){
int myDrawableState = getDrawableState();
// Set the state of the Drawable
mCheckMarkDrawable.setState(myDrawableState);
invalidate();
}
}
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event){
boolean populated = super.dispatchPopulateAccessibilityEvent(event);
if (!populated){
event.setChecked(mChecked);
}
return populated;
}
}
次回は、この使い方。。