沈阳关键词优化公司,东莞网络seo推广,网络建设解决方案专业公司,提升审美网站经历过了前面一系列的讲解#xff0c;下面我们直接来看看系统里面的CheckBox与CompoundButton类的源码文件。你肯定会发现很多熟悉的地方。 结合下面源码#xff0c;我们对它们进行解析解析#xff0c;它里面使用的就是自定义drawable state。
我们首先直接看CheckBox的源…经历过了前面一系列的讲解下面我们直接来看看系统里面的CheckBox与CompoundButton类的源码文件。你肯定会发现很多熟悉的地方。 结合下面源码我们对它们进行解析解析它里面使用的就是自定义drawable state。
我们首先直接看CheckBox的源码
public class CheckBox extends CompoundButton {public CheckBox(Context context) {this(context, null);}public CheckBox(Context context, AttributeSet attrs) {this(context, attrs, com.android.internal.R.attr.checkboxStyle);}public CheckBox(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}Overridepublic void onInitializeAccessibilityEvent(AccessibilityEvent event) {super.onInitializeAccessibilityEvent(event);event.setClassName(CheckBox.class.getName());}Overridepublic void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {super.onInitializeAccessibilityNodeInfo(info);info.setClassName(CheckBox.class.getName());}
}
我们可以看到它里面并没有做什么因为它的操作都是继承自CompoundButton.
我们先来看看下面一个普通的布局文件
RelativeLayout xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:toolshttp://schemas.android.com/toolsandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:paddingLeftdimen/activity_horizontal_marginandroid:paddingRightdimen/activity_horizontal_marginandroid:paddingTopdimen/activity_vertical_marginandroid:paddingBottomdimen/activity_vertical_margintools:context.MainActivityCheckBoxandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:textCheckBox//RelativeLayout
在上面的这个相对布局中就写了一个CheckBox我们什么都不做直接运行代码就会看到下面的运行界面
当我们单击这个CheckBox,我们发现他会被选中那么它内部到底是怎么实现的呢 其实使用过drawable state的人应该对这个并不陌生我们经常这样做
1、在res/drawable文件下创建selector.xml示例代码如下
?xml version1.0 encodingutf-8?
selector xmlns:androidhttp://schemas.android.com/apk/res/androiditemandroid:state_pressedfalseandroid:drawabledrawable/title_button_back/itemitemandroid:state_pressedtrueandroid:drawabledrawable/title_button_back_h/itemitemandroid:state_window_focusedfalseandroid:drawabledrawable/title_button_back/item
/selector
2、编写布局文件为布局文件中的ImageButton设置selector示例代码如下
?xml version1.0 encodingutf-8?
RelativeLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_heightwrap_content android:layout_widthfill_parent ImageButton android:idid/title_IBandroid:layout_heightwrap_content android:layout_widthwrap_content android:background#00000000 android:layout_marginRight4dp android:layout_centerVerticaltrue android:srcdrawable/selector/ImageButton
/RelativeLayout
当我们单击这个图片按钮的时候图片按钮的图片就会发生变化其实CheckBox也是这样做的只是这些系统为我们做了。
下面我们来看看系统实现源码 上面在布局文件中直接写了一个CheckBox,布局文件被解析后就会实例化这个CheckBox对象就会执行CheckBox的构造函数
public CheckBox(Context context, AttributeSet attrs) {this(context, attrs, com.android.internal.R.attr.checkboxStyle);
}public CheckBox(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);
}
从上面我们可以知道两点 1、CheckBox的默认样式是com.android.internal.R.attr.checkboxStyle 2、最终执行的时候CompoundButton的构造函数
在frameworks/base/core/res/res/values/themes.xml文件中已经初始化了checkBoxStyle样式
item namecheckboxStyleandroid:style/Widget.CompoundButton.CheckBox/item
在frameworks/base/core/res/res/values/styles.xml文件我们来看看它的样式是什么
style nameWidget.CompoundButton.CheckBoxitem nameandroid:button?android:attr/listChoiceIndicatorMultiple/item
/style
在frameworks/base/core/res/res/values/themes.xml文件
item namelistChoiceIndicatorMultipleandroid:drawable/btn_check/item
可以看到CheckBox的默认样式就是给它的button属性赋值了一个btn_check,我们来看看btn_check文件里面的具体内容。
在frameworks/base/core/res/res/drawable/btn_check.xml
?xml version1.0 encodingutf-8?
selector xmlns:androidhttp://schemas.android.com/apk/res/android!-- Enabled states --item android:state_checkedtrue android:state_window_focusedfalseandroid:state_enabledtrueandroid:drawabledrawable/btn_check_on /item android:state_checkedfalse android:state_window_focusedfalseandroid:state_enabledtrueandroid:drawabledrawable/btn_check_off /item android:state_checkedtrue android:state_pressedtrueandroid:state_enabledtrueandroid:drawabledrawable/btn_check_on_pressed /item android:state_checkedfalse android:state_pressedtrueandroid:state_enabledtrueandroid:drawabledrawable/btn_check_off_pressed /item android:state_checkedtrue android:state_focusedtrueandroid:state_enabledtrueandroid:drawabledrawable/btn_check_on_selected /item android:state_checkedfalse android:state_focusedtrueandroid:state_enabledtrueandroid:drawabledrawable/btn_check_off_selected /item android:state_checkedfalseandroid:state_enabledtrueandroid:drawabledrawable/btn_check_off /item android:state_checkedtrueandroid:state_enabledtrueandroid:drawabledrawable/btn_check_on /!-- Disabled states --item android:state_checkedtrue android:state_window_focusedfalseandroid:drawabledrawable/btn_check_on_disable /item android:state_checkedfalse android:state_window_focusedfalseandroid:drawabledrawable/btn_check_off_disable /item android:state_checkedtrue android:state_focusedtrueandroid:drawabledrawable/btn_check_on_disable_focused /item android:state_checkedfalse android:state_focusedtrueandroid:drawabledrawable/btn_check_off_disable_focused /item android:state_checkedfalse android:drawabledrawable/btn_check_off_disable /item android:state_checkedtrue android:drawabledrawable/btn_check_on_disable //selector
我们看到state_checked为true的时候drawable”drawable/btn_check_on”state_checked为false的时候,drawable”drawable/btn_check_off”. drawable/btn_check_on图片和drawable/btn_check_off图片在frameworks/base/core/res/res/drawable我们可以找到
我们可以看到其实就是根据不同的状态为button属性赋值了不同的图片资源这就是我们看到的效果。
state_checked这个状态的定义在下面进行了定义
declare-styleable nameDrawableStates!-- State value for {link android.graphics.drawable.StateListDrawable StateListDrawable},set when a view has input focus. --attr namestate_focused formatboolean /!-- State value for {link android.graphics.drawable.StateListDrawable StateListDrawable},set when a views window has input focus. --attr namestate_window_focused formatboolean /!-- State value for {link android.graphics.drawable.StateListDrawable StateListDrawable},set when a view is enabled. --attr namestate_enabled formatboolean /!-- State identifier indicating that the object varmay/var display a check mark.See {link R.attr#state_checked} for the identifier that indicates whether it isactually checked. --attr namestate_checkable formatboolean/!-- State identifier indicating that the object is currently checked. See{link R.attr#state_checkable} for an additional identifier that can indicate ifany object may ever display a check, regardless of whether state_checked iscurrently set. --attr namestate_checked formatboolean/!-- State value for {link android.graphics.drawable.StateListDrawable StateListDrawable},set when a view (or one of its parents) is currently selected. --attr namestate_selected formatboolean /!-- State value for {link android.graphics.drawable.StateListDrawable StateListDrawable},set when the user is pressing down in a view. --attr namestate_pressed formatboolean /!-- State value for {link android.graphics.drawable.StateListDrawable StateListDrawable},set when a view or its parent has been activated meaning the user has currentlymarked it as being of interest. This is an alternative representation ofstate_checked for when the state should be propagated down the view hierarchy. --attr namestate_activated formatboolean /!-- State value for {link android.graphics.drawable.StateListDrawable StateListDrawable}.--attr namestate_active formatboolean /!-- State value for {link android.graphics.drawable.StateListDrawable StateListDrawable}.--attr namestate_single formatboolean /!-- State value for {link android.graphics.drawable.StateListDrawable StateListDrawable}.--attr namestate_first formatboolean /!-- State value for {link android.graphics.drawable.StateListDrawable StateListDrawable}.--attr namestate_middle formatboolean /!-- State value for {link android.graphics.drawable.StateListDrawable StateListDrawable}.--attr namestate_last formatboolean /!-- State value for {link android.graphics.drawable.StateListDrawable StateListDrawable},indicating that the Drawable is in a view that is hardware accelerated.This means that the device can at least render a full-screen scaledbitmap with one layer of text and bitmaps composited on top of itat 60fps. When this is set, the colorBackgroundCacheHint will beignored even if it specifies a solid color, since that optimizationis not needed. --attr namestate_accelerated formatboolean /!-- State value for {link android.graphics.drawable.StateListDrawable StateListDrawable},set when a pointer is hovering over the view. --attr namestate_hovered formatboolean /!-- State for {link android.graphics.drawable.StateListDrawable StateListDrawable}indicating that the Drawable is in a view that is capable of accepting a drop ofthe content currently being manipulated in a drag-and-drop operation. --attr namestate_drag_can_accept formatboolean /!-- State for {link android.graphics.drawable.StateListDrawable StateListDrawable}indicating that a drag operation (for which the Drawables view is a valid recipient)is currently positioned over the Drawable. --attr namestate_drag_hovered formatboolean /!-- State for {link android.graphics.drawable.StateListDrawable StateListDrawable}indicating that a View has accessibility focus. --attr namestate_accessibility_focused formatboolean /
/declare-styleable
我们可以看到attr namestate_checked formatboolean/
下面我们看看CompoundButton的构造函数因为CheckBox最终执行的是它的构造函数。
public CompoundButton(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);TypedArray a context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.CompoundButton, defStyle, 0);Drawable d a.getDrawable(com.android.internal.R.styleable.CompoundButton_button);if (d ! null) {setButtonDrawable(d);}boolean checked a.getBoolean(com.android.internal.R.styleable.CompoundButton_checked, false);setChecked(checked);a.recycle();
}
我们可以知道CompoundButton自定义了两个属性进入frameworks/base/core/res/res/values/attrs.xml文件
declare-styleable nameCompoundButton!-- Indicates the initial checked state of this button. --attr namechecked formatboolean /!-- Drawable used for the button graphic (e.g. checkbox, radio button, etc). --attr namebutton formatreference/
/declare-styleable
我们可以看到它定义了两个属性checkedbutton一个存放的是一个boolean类型的值表示是否被选中一个存放的是引用类型对应的是一个图片。 在构造函数中我们获取到了这两个属性值。上面就是对button这个属性进行了默认赋值然后我们这里就可以获取到上面的btn_check这个xml文件的drawable。 也就是说Drawable d a.getDrawable(com.android.internal.R.styleable.CompoundButton_button)中的d的到的就是btn_check这个xml文件的drawable。
然后分别调用了setButtonDrawable(d)和setChecked(checked)来对我们自定义的控件进行了设置。
我们来看看setButtonDrawable(d)函数
public void setButtonDrawable(Drawable d) {if (d ! null) {if (mButtonDrawable ! null) {mButtonDrawable.setCallback(null);unscheduleDrawable(mButtonDrawable);}//这里设置Callback的原因就是refreshDrawableState刷新的时候可以回调到invalidateDrawable//这样就可以重绘这个我们在#详解refreshDrawableList()的执行流程#这篇文件讲过d.setCallback(this);d.setVisible(getVisibility() VISIBLE, false);mButtonDrawable d;setMinHeight(mButtonDrawable.getIntrinsicHeight());}refreshDrawableState();
}
最后调用了refreshDrawableState这个方法这个执行过程我们也分析过整个执行思路都是一样不过不同的是里面的很多方法都被覆盖了。
这里我们再来把整个思路走一走。
refreshDrawableState执行的还是View里面的这个方法直接看源码。
public void refreshDrawableState() {//首先把标志设置为PFLAG_DRAWABLE_STATE_DIRTYmPrivateFlags | PFLAG_DRAWABLE_STATE_DIRTY;drawableStateChanged();ViewParent parent mParent;if (parent ! null) {parent.childDrawableStateChanged(this);}
}
drawableStateChanged这个方法不在执行View里面的这个方法因为CompoundButton里面有这个方法我们看看CompoundButton的这个方法。
Override
protected void drawableStateChanged() {super.drawableStateChanged();if (mButtonDrawable ! null) {int[] myDrawableState getDrawableState();// Set the state of the DrawablemButtonDrawable.setState(myDrawableState);invalidate();}
}getDrawableState这个函数还是调用的View的这个函数。
public final int[] getDrawableState() {//PFLAG_DRAWABLE_STATE_DIRTY是前面refreshDrawableState设置的//如果mDrawableState不为空并且不需要刷新状态则直接返回否则重新进行获取if ((mDrawableState ! null) ((mPrivateFlags PFLAG_DRAWABLE_STATE_DIRTY) 0)) {return mDrawableState;} else {//这里就是重新得到视图状态并将其返回mDrawableState onCreateDrawableState(0);//清除前面refreshDrawableState设置的标识mPrivateFlags ~PFLAG_DRAWABLE_STATE_DIRTY;return mDrawableState;}
}
下面调用到了onCreateDrawableState这个方法这个方法也不在是执行View里面的这个方法因为CompoundButton里面也有这个方法。
Override
protected int[] onCreateDrawableState(int extraSpace) {final int[] drawableState super.onCreateDrawableState(extraSpace 1);if (isChecked()) {mergeDrawableStates(drawableState, CHECKED_STATE_SET);}return drawableState;
}
结合之前我们详解refreshDrawableList()的执行流程的分析。这个方法就是在之前的基础上加入了一个判断如果isChekced为真就把我们自定义的这个状态加进去这样当前状态里面就有我们的自定义的状态后面在状态二维数组中查询的时候就可以找到对应的drawable图片进行设置了。
这个函数执行完了就会回到上面的getDrawableState函数然后把当前的状态返回到drawableStateChanged函数中接着看里面的代码。
接着执行mButtonDrawable.setState(myDrawableState)把得到的当前状态数组设置进去。里面的执行过去前面详解refreshDrawableList()的执行流程的分析也说过是完全一样的我们就省略,不明白就再看看最后会执行invalidateSelf函数。
这个函数就会得到前面我们设置的Callback回调调用它的invalidateDrawable方法。
public void invalidateSelf() {final Callback callback getCallback();if (callback ! null) {callback.invalidateDrawable(this);}
}
跟前面一样因为View实现了这个回调所以它执行的是View里面的实现方法。在这个方法里面执行了invalidate函数所以会执行onDraw方法. 在CompoundButton里面实现了这个方法它不再直接执行View里面的这个方法了。
protected void onDraw(Canvas canvas) {super.onDraw(canvas);final Drawable buttonDrawable mButtonDrawable;if (buttonDrawable ! null) {final int verticalGravity getGravity() Gravity.VERTICAL_GRAVITY_MASK;final int drawableHeight buttonDrawable.getIntrinsicHeight();final int drawableWidth buttonDrawable.getIntrinsicWidth();int top 0;switch (verticalGravity) {case Gravity.BOTTOM:top getHeight() - drawableHeight;break;case Gravity.CENTER_VERTICAL:top (getHeight() - drawableHeight) / 2;break;}int bottom top drawableHeight;int left isLayoutRtl() ? getWidth() - drawableWidth : 0;int right isLayoutRtl() ? getWidth() : drawableWidth;buttonDrawable.setBounds(left, top, right, bottom);buttonDrawable.draw(canvas);}
}
这样这个图片就绘制出来了从btn_check里面我们可以看到最开始显示的图片是btn_check_off当我们单击这个CheckBox的时候会执行performClick函数。
Override
public boolean performClick() {/** XXX: These are tiny, need some surrounding expanded touch area,* which will need to be implemented in Button if we only override* performClick()*//* When clicked, toggle the state */toggle();return super.performClick();
}
接着执行toggle函数。
public void toggle() {setChecked(!mChecked);
}
这里面就把当前的状态设置为与之前相反的状态刚开始为false,这个时候就为true.
接着我们看看setChecked函数。
public void setChecked(boolean checked) {if (mChecked ! checked) {mChecked checked;refreshDrawableState();notifyViewAccessibilityStateChangedIfNeeded(AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);// Avoid infinite recursions if setChecked() is called from a listenerif (mBroadcasting) {return;}mBroadcasting true;if (mOnCheckedChangeListener ! null) {mOnCheckedChangeListener.onCheckedChanged(this, mChecked);}if (mOnCheckedChangeWidgetListener ! null) {mOnCheckedChangeWidgetListener.onCheckedChanged(this, mChecked);}mBroadcasting false; }
}
在这个里面又执行了refreshDrawableState函数同样把上面的refreshDrawableState过程又执行了一遍执行在到onCreateDrawableState就不一样了。 我们在来看看这个函数
protected int[] onCreateDrawableState(int extraSpace) {final int[] drawableState super.onCreateDrawableState(extraSpace 1);if (isChecked()) {mergeDrawableStates(drawableState, CHECKED_STATE_SET);}return drawableState;
}
第一次执行的时候isChecked为false,自定义的这个状态没有合进去这次就把自定义的这个状态合进去这样就可以查询到我们的状态所以就可以找到定义的drawable,所以图片发生改变为btn_check_on。
最后把完整的CompoundButton源码贴出来可以对照上面将的然后再根据前面讲的详解refreshDrawableList()的执行流程这个过程理解理解。
/** Copyright (C) 2007 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the License);* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an AS IS BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package android.widget;import com.android.internal.R;import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.ViewDebug;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;/*** p* A button with two states, checked and unchecked. When the button is pressed* or clicked, the state changes automatically.* /p** pstrongXML attributes/strong/p* p* See {link android.R.styleable#CompoundButton* CompoundButton Attributes}, {link android.R.styleable#Button Button* Attributes}, {link android.R.styleable#TextView TextView Attributes}, {link* android.R.styleable#View View Attributes}* /p*/
public abstract class CompoundButton extends Button implements Checkable {private boolean mChecked;private int mButtonResource;private boolean mBroadcasting;private Drawable mButtonDrawable;private OnCheckedChangeListener mOnCheckedChangeListener;private OnCheckedChangeListener mOnCheckedChangeWidgetListener;private static final int[] CHECKED_STATE_SET {R.attr.state_checked};public CompoundButton(Context context) {this(context, null);}public CompoundButton(Context context, AttributeSet attrs) {this(context, attrs, 0);}public CompoundButton(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);TypedArray a context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.CompoundButton, defStyle, 0);Drawable d a.getDrawable(com.android.internal.R.styleable.CompoundButton_button);if (d ! null) {setButtonDrawable(d);}boolean checked a.getBoolean(com.android.internal.R.styleable.CompoundButton_checked, false);setChecked(checked);a.recycle();}public void toggle() {setChecked(!mChecked);}Overridepublic boolean performClick() {/** XXX: These are tiny, need some surrounding expanded touch area,* which will need to be implemented in Button if we only override* performClick()*//* When clicked, toggle the state */toggle();return super.performClick();}ViewDebug.ExportedPropertypublic boolean isChecked() {return mChecked;}/*** pChanges the checked state of this button./p** param checked true to check the button, false to uncheck it*/public void setChecked(boolean checked) {if (mChecked ! checked) {mChecked checked;refreshDrawableState();notifyViewAccessibilityStateChangedIfNeeded(AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);// Avoid infinite recursions if setChecked() is called from a listenerif (mBroadcasting) {return;}mBroadcasting true;if (mOnCheckedChangeListener ! null) {mOnCheckedChangeListener.onCheckedChanged(this, mChecked);}if (mOnCheckedChangeWidgetListener ! null) {mOnCheckedChangeWidgetListener.onCheckedChanged(this, mChecked);}mBroadcasting false; }}/*** Register a callback to be invoked when the checked state of this button* changes.** param listener the callback to call on checked state change*/public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {mOnCheckedChangeListener listener;}/*** Register a callback to be invoked when the checked state of this button* changes. This callback is used for internal purpose only.** param listener the callback to call on checked state change* hide*/void setOnCheckedChangeWidgetListener(OnCheckedChangeListener listener) {mOnCheckedChangeWidgetListener listener;}/*** Interface definition for a callback to be invoked when the checked state* of a compound button changed.*/public static interface OnCheckedChangeListener {/*** Called when the checked state of a compound button has changed.** param buttonView The compound button view whose state has changed.* param isChecked The new checked state of buttonView.*/void onCheckedChanged(CompoundButton buttonView, boolean isChecked);}/*** Set the background to a given Drawable, identified by its resource id.** param resid the resource id of the drawable to use as the background */public void setButtonDrawable(int resid) {if (resid ! 0 resid mButtonResource) {return;}mButtonResource resid;Drawable d null;if (mButtonResource ! 0) {d getResources().getDrawable(mButtonResource);}setButtonDrawable(d);}/*** Set the background to a given Drawable** param d The Drawable to use as the background*/public void setButtonDrawable(Drawable d) {if (d ! null) {if (mButtonDrawable ! null) {mButtonDrawable.setCallback(null);unscheduleDrawable(mButtonDrawable);}d.setCallback(this);d.setVisible(getVisibility() VISIBLE, false);mButtonDrawable d;setMinHeight(mButtonDrawable.getIntrinsicHeight());}refreshDrawableState();}Overridepublic void onInitializeAccessibilityEvent(AccessibilityEvent event) {super.onInitializeAccessibilityEvent(event);event.setClassName(CompoundButton.class.getName());event.setChecked(mChecked);}Overridepublic void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {super.onInitializeAccessibilityNodeInfo(info);info.setClassName(CompoundButton.class.getName());info.setCheckable(true);info.setChecked(mChecked);}Overridepublic int getCompoundPaddingLeft() {int padding super.getCompoundPaddingLeft();if (!isLayoutRtl()) {final Drawable buttonDrawable mButtonDrawable;if (buttonDrawable ! null) {padding buttonDrawable.getIntrinsicWidth();}}return padding;}Overridepublic int getCompoundPaddingRight() {int padding super.getCompoundPaddingRight();if (isLayoutRtl()) {final Drawable buttonDrawable mButtonDrawable;if (buttonDrawable ! null) {padding buttonDrawable.getIntrinsicWidth();}}return padding;}/*** hide*/Overridepublic int getHorizontalOffsetForDrawables() {final Drawable buttonDrawable mButtonDrawable;return (buttonDrawable ! null) ? buttonDrawable.getIntrinsicWidth() : 0;}Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);final Drawable buttonDrawable mButtonDrawable;if (buttonDrawable ! null) {final int verticalGravity getGravity() Gravity.VERTICAL_GRAVITY_MASK;final int drawableHeight buttonDrawable.getIntrinsicHeight();final int drawableWidth buttonDrawable.getIntrinsicWidth();int top 0;switch (verticalGravity) {case Gravity.BOTTOM:top getHeight() - drawableHeight;break;case Gravity.CENTER_VERTICAL:top (getHeight() - drawableHeight) / 2;break;}int bottom top drawableHeight;int left isLayoutRtl() ? getWidth() - drawableWidth : 0;int right isLayoutRtl() ? getWidth() : drawableWidth;buttonDrawable.setBounds(left, top, right, bottom);buttonDrawable.draw(canvas);}}Overrideprotected int[] onCreateDrawableState(int extraSpace) {final int[] drawableState super.onCreateDrawableState(extraSpace 1);if (isChecked()) {mergeDrawableStates(drawableState, CHECKED_STATE_SET);}return drawableState;}Overrideprotected void drawableStateChanged() {super.drawableStateChanged();if (mButtonDrawable ! null) {int[] myDrawableState getDrawableState();// Set the state of the DrawablemButtonDrawable.setState(myDrawableState);invalidate();}}Overrideprotected boolean verifyDrawable(Drawable who) {return super.verifyDrawable(who) || who mButtonDrawable;}Overridepublic void jumpDrawablesToCurrentState() {super.jumpDrawablesToCurrentState();if (mButtonDrawable ! null) mButtonDrawable.jumpToCurrentState();}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);}Overridepublic void writeToParcel(Parcel out, int flags) {super.writeToParcel(out, flags);out.writeValue(checked);}Overridepublic String toString() {return CompoundButton.SavedState{ Integer.toHexString(System.identityHashCode(this)) checked checked };}public static final Parcelable.CreatorSavedState CREATOR new Parcelable.CreatorSavedState() {public SavedState createFromParcel(Parcel in) {return new SavedState(in);}public SavedState[] newArray(int size) {return new SavedState[size];}};}Overridepublic Parcelable onSaveInstanceState() {// Force our ancestor class to save its statesetFreezesText(true);Parcelable superState super.onSaveInstanceState();SavedState ss new SavedState(superState);ss.checked isChecked();return ss;}Overridepublic void onRestoreInstanceState(Parcelable state) {SavedState ss (SavedState) state;super.onRestoreInstanceState(ss.getSuperState());setChecked(ss.checked);requestLayout();}
} 文章转载自: http://www.morning.twwzk.cn.gov.cn.twwzk.cn http://www.morning.rckmz.cn.gov.cn.rckmz.cn http://www.morning.qztdz.cn.gov.cn.qztdz.cn http://www.morning.lhptg.cn.gov.cn.lhptg.cn http://www.morning.pbwcq.cn.gov.cn.pbwcq.cn http://www.morning.jhwqp.cn.gov.cn.jhwqp.cn http://www.morning.yfcyh.cn.gov.cn.yfcyh.cn http://www.morning.smwlr.cn.gov.cn.smwlr.cn http://www.morning.qnzk.cn.gov.cn.qnzk.cn http://www.morning.zsrdp.cn.gov.cn.zsrdp.cn http://www.morning.hdqqr.cn.gov.cn.hdqqr.cn http://www.morning.zthln.cn.gov.cn.zthln.cn http://www.morning.drggr.cn.gov.cn.drggr.cn http://www.morning.chbcj.cn.gov.cn.chbcj.cn http://www.morning.nfnxp.cn.gov.cn.nfnxp.cn http://www.morning.ysbrz.cn.gov.cn.ysbrz.cn http://www.morning.wqbzt.cn.gov.cn.wqbzt.cn http://www.morning.bxqtq.cn.gov.cn.bxqtq.cn http://www.morning.tktyh.cn.gov.cn.tktyh.cn http://www.morning.nsrlb.cn.gov.cn.nsrlb.cn http://www.morning.zsrdp.cn.gov.cn.zsrdp.cn http://www.morning.thrcj.cn.gov.cn.thrcj.cn http://www.morning.rkgyx.cn.gov.cn.rkgyx.cn http://www.morning.ssqwr.cn.gov.cn.ssqwr.cn http://www.morning.bcjbm.cn.gov.cn.bcjbm.cn http://www.morning.rfxyk.cn.gov.cn.rfxyk.cn http://www.morning.mqffm.cn.gov.cn.mqffm.cn http://www.morning.wmqrn.cn.gov.cn.wmqrn.cn http://www.morning.kysport1102.cn.gov.cn.kysport1102.cn http://www.morning.sjsks.cn.gov.cn.sjsks.cn http://www.morning.lhxdq.cn.gov.cn.lhxdq.cn http://www.morning.qmxsx.cn.gov.cn.qmxsx.cn http://www.morning.lwhsp.cn.gov.cn.lwhsp.cn http://www.morning.fbjnr.cn.gov.cn.fbjnr.cn http://www.morning.gwsfq.cn.gov.cn.gwsfq.cn http://www.morning.tndxg.cn.gov.cn.tndxg.cn http://www.morning.wqbfd.cn.gov.cn.wqbfd.cn http://www.morning.qlsbz.cn.gov.cn.qlsbz.cn http://www.morning.lqypx.cn.gov.cn.lqypx.cn http://www.morning.nyzmm.cn.gov.cn.nyzmm.cn http://www.morning.fosfox.com.gov.cn.fosfox.com http://www.morning.bpwdc.cn.gov.cn.bpwdc.cn http://www.morning.lmmyl.cn.gov.cn.lmmyl.cn http://www.morning.lkpzx.cn.gov.cn.lkpzx.cn http://www.morning.trsdm.cn.gov.cn.trsdm.cn http://www.morning.bkqdg.cn.gov.cn.bkqdg.cn http://www.morning.knzdt.cn.gov.cn.knzdt.cn http://www.morning.htfnz.cn.gov.cn.htfnz.cn http://www.morning.nzlqt.cn.gov.cn.nzlqt.cn http://www.morning.wctqc.cn.gov.cn.wctqc.cn http://www.morning.benqc.com.gov.cn.benqc.com http://www.morning.mnsmb.cn.gov.cn.mnsmb.cn http://www.morning.ns3nt8.cn.gov.cn.ns3nt8.cn http://www.morning.gyylt.cn.gov.cn.gyylt.cn http://www.morning.rykw.cn.gov.cn.rykw.cn http://www.morning.nxhjg.cn.gov.cn.nxhjg.cn http://www.morning.ftrpvh.cn.gov.cn.ftrpvh.cn http://www.morning.tbqdm.cn.gov.cn.tbqdm.cn http://www.morning.nqnqz.cn.gov.cn.nqnqz.cn http://www.morning.sgbss.cn.gov.cn.sgbss.cn http://www.morning.trjr.cn.gov.cn.trjr.cn http://www.morning.rnds.cn.gov.cn.rnds.cn http://www.morning.bnxfj.cn.gov.cn.bnxfj.cn http://www.morning.lgsfb.cn.gov.cn.lgsfb.cn http://www.morning.jyznn.cn.gov.cn.jyznn.cn http://www.morning.rcrnw.cn.gov.cn.rcrnw.cn http://www.morning.jrrqs.cn.gov.cn.jrrqs.cn http://www.morning.plxhq.cn.gov.cn.plxhq.cn http://www.morning.lrjtx.cn.gov.cn.lrjtx.cn http://www.morning.bsghk.cn.gov.cn.bsghk.cn http://www.morning.tktcr.cn.gov.cn.tktcr.cn http://www.morning.ggcjf.cn.gov.cn.ggcjf.cn http://www.morning.bsjpd.cn.gov.cn.bsjpd.cn http://www.morning.zkdmk.cn.gov.cn.zkdmk.cn http://www.morning.qgdsd.cn.gov.cn.qgdsd.cn http://www.morning.xqltq.cn.gov.cn.xqltq.cn http://www.morning.hnk25076he.cn.gov.cn.hnk25076he.cn http://www.morning.mmxnb.cn.gov.cn.mmxnb.cn http://www.morning.jqhrk.cn.gov.cn.jqhrk.cn http://www.morning.jpwmk.cn.gov.cn.jpwmk.cn