滑动的Button
在介绍SwitchButton之前,先来看一下系统Button是如何实现的。源码如下:
- @RemoteView
- public class Button extends TextView {
- public Button(Context context) {
- this(context, null);
- }
- public Button(Context context, AttributeSet attrs) {
- this(context, attrs, com.android.internal.R.attr.buttonStyle);
- }
- public Button(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
- @Override
- public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
- super.onInitializeAccessibilityEvent(event);
- event.setClassName(Button. class.getName());
- }
- @Override
- public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(info);
- info.setClassName(Button. class.getName());
- }
- }
@RemoteView
public class Button extends TextView {
public Button(Context context) {
this(context, null);
} public Button(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.buttonStyle);
} public Button(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
} @Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(Button. class.getName());
} @Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(Button. class.getName());
}
}
- /**
- * <p>
- * A button with two states, checked and unchecked. When the button is pressed
- * or clicked, the state changes automatically.
- * </p>
- *
- * <p><strong>XML 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);
- }
- @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();
- }
- @ViewDebug.ExportedProperty
- public boolean isChecked() {
- return mChecked ;
- }
- /**
- * <p>Changes 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 listener
- if (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();
- }
- @Override
- public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
- super.onInitializeAccessibilityEvent(event);
- event.setClassName(CompoundButton.class .getName());
- event.setChecked( mChecked);
- }
- @Override
- public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(info);
- info.setClassName(CompoundButton.class .getName());
- info.setCheckable( true);
- info.setChecked( mChecked);
- }
- @Override
- public int getCompoundPaddingLeft() {
- int padding = super.getCompoundPaddingLeft();
- if (!isLayoutRtl()) {
- final Drawable buttonDrawable = mButtonDrawable;
- if (buttonDrawable != null) {
- padding += buttonDrawable.getIntrinsicWidth();
- }
- }
- return padding;
- }
- @Override
- public int getCompoundPaddingRight() {
- int padding = super.getCompoundPaddingRight();
- if (isLayoutRtl()) {
- final Drawable buttonDrawable = mButtonDrawable;
- if (buttonDrawable != null) {
- padding += buttonDrawable.getIntrinsicWidth();
- }
- }
- return padding;
- }
- /**
- * @hide
- */
- @Override
- public int getHorizontalOffsetForDrawables() {
- final Drawable buttonDrawable = mButtonDrawable ;
- return (buttonDrawable != null) ? buttonDrawable.getIntrinsicWidth() : 0;
- }
- @Override
- 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);
- }
- }
- @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 (mButtonDrawable != null) {
- int[] myDrawableState = getDrawableState();
- // Set the state of the Drawable
- mButtonDrawable.setState(myDrawableState);
- invalidate();
- }
- }
- @Override
- protected boolean verifyDrawable(Drawable who) {
- return super .verifyDrawable(who) || who == mButtonDrawable;
- }
- @Override
- public 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);
- }
- @Override
- public void writeToParcel(Parcel out, int flags) {
- super.writeToParcel(out, flags);
- out.writeValue( checked);
- }
- @Override
- public String toString() {
- return "CompoundButton.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();
- }
- }
/**
* <p>
* A button with two states, checked and unchecked. When the button is pressed
* or clicked, the state changes automatically.
* </p>
*
* <p><strong>XML 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);
} @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();
} @ViewDebug.ExportedProperty
public boolean isChecked() {
return mChecked ;
} /**
* <p>Changes 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 listener
if (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();
} @Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(CompoundButton.class .getName());
event.setChecked( mChecked);
} @Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(CompoundButton.class .getName());
info.setCheckable( true);
info.setChecked( mChecked);
} @Override
public int getCompoundPaddingLeft() {
int padding = super.getCompoundPaddingLeft();
if (!isLayoutRtl()) {
final Drawable buttonDrawable = mButtonDrawable;
if (buttonDrawable != null) {
padding += buttonDrawable.getIntrinsicWidth();
}
}
return padding;
} @Override
public int getCompoundPaddingRight() {
int padding = super.getCompoundPaddingRight();
if (isLayoutRtl()) {
final Drawable buttonDrawable = mButtonDrawable;
if (buttonDrawable != null) {
padding += buttonDrawable.getIntrinsicWidth();
}
}
return padding;
} /**
* @hide
*/
@Override
public int getHorizontalOffsetForDrawables() {
final Drawable buttonDrawable = mButtonDrawable ;
return (buttonDrawable != null) ? buttonDrawable.getIntrinsicWidth() : 0;
} @Override
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);
}
} @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 (mButtonDrawable != null) {
int[] myDrawableState = getDrawableState(); // Set the state of the Drawable
mButtonDrawable.setState(myDrawableState); invalidate();
}
} @Override
protected boolean verifyDrawable(Drawable who) {
return super .verifyDrawable(who) || who == mButtonDrawable;
} @Override
public 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);
} @Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeValue( checked);
} @Override
public String toString() {
return "CompoundButton.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();
}
}
先从构造方法开始,在构造方法中,
- 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 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();
}
先是从attrs中读取定义的属性,一个是Drawable用于设置背景;一个是布尔类型变量用于判断是否check过。设置背景使用的是setButtonDrawable()方法,代码如下:
- /**
- * 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();
- }
/**
* 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();
}
这个方法写的就比较完善,可以作为一个学习的典范。首先判断传递过来的Drawable是否为空,如果不为空并且默认的Drawable也不为空,那么取消默认Drawable的callback,然后调用unscheduleDrawable方法。这个方法代码如下:
- /**
- * Unschedule any events associated with the given Drawable. This can be
- * used when selecting a new Drawable into a view, so that the previous
- * one is completely unscheduled.
- *
- * @param who The Drawable to unschedule.
- *
- * @see #drawableStateChanged
- */
- public void unscheduleDrawable(Drawable who) {
- if (mAttachInfo != null && who != null) {
- mAttachInfo.mViewRootImpl .mChoreographer.removeCallbacks(
- Choreographer.CALLBACK_ANIMATION, null, who);
- }
- }
/**
* Unschedule any events associated with the given Drawable. This can be
* used when selecting a new Drawable into a view, so that the previous
* one is completely unscheduled.
*
* @param who The Drawable to unschedule.
*
* @see #drawableStateChanged
*/
public void unscheduleDrawable(Drawable who) {
if (mAttachInfo != null && who != null) {
mAttachInfo.mViewRootImpl .mChoreographer.removeCallbacks(
Choreographer.CALLBACK_ANIMATION, null, who);
}
}
从方法注释中可以看出它的用途,正是更换Drawable时候使用的。接下来开始重新设置Drawable,包括回调、可见性、最小高度。最后调用refreshDrawableState()方法,这个是View类的方法,用于更新Drawable状态。
- /**
- * <p>Changes 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 listener
- if (mBroadcasting ) {
- return;
- }
- mBroadcasting = true ;
- if (mOnCheckedChangeListener != null) {
- mOnCheckedChangeListener.onCheckedChanged(this, mChecked);
- }
- if (mOnCheckedChangeWidgetListener != null) {
- mOnCheckedChangeWidgetListener .onCheckedChanged(this, mChecked);
- }
- mBroadcasting = false ;
- }
- }
/**
* <p>Changes 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 listener
if (mBroadcasting ) {
return;
} mBroadcasting = true ;
if (mOnCheckedChangeListener != null) {
mOnCheckedChangeListener.onCheckedChanged(this, mChecked);
}
if (mOnCheckedChangeWidgetListener != null) {
mOnCheckedChangeWidgetListener .onCheckedChanged(this, mChecked);
}
mBroadcasting = false ;
}
}
- /**
- * 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);
- }
/**
* 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);
}
- @Override
- 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);
- }
- }
@Override
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);
}
}
- 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);
- }
- @Override
- public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
- super.onInitializeAccessibilityEvent(event);
- event.setClassName(CheckBox. class.getName());
- }
- @Override
- public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(info);
- info.setClassName(CheckBox. class.getName());
- }
- }
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);
} @Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(CheckBox. class.getName());
} @Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(CheckBox. class.getName());
}
}
- public class RadioButton extends CompoundButton {
- public RadioButton(Context context) {
- this(context, null);
- }
- public RadioButton(Context context, AttributeSet attrs) {
- this(context, attrs, com.android.internal.R.attr.radioButtonStyle);
- }
- public RadioButton(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
- /**
- * {@inheritDoc}
- * <p>
- * If the radio button is already checked, this method will not toggle the radio button.
- */
- @Override
- public void toggle() {
- // we override to prevent toggle when the radio is already
- // checked (as opposed to check boxes widgets)
- if (!isChecked()) {
- super.toggle();
- }
- }
- @Override
- public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
- super.onInitializeAccessibilityEvent(event);
- event.setClassName(RadioButton. class.getName());
- }
- @Override
- public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(info);
- info.setClassName(RadioButton. class.getName());
- }
- }
public class RadioButton extends CompoundButton { public RadioButton(Context context) {
this(context, null);
} public RadioButton(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.radioButtonStyle);
} public RadioButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
} /**
* {@inheritDoc}
* <p>
* If the radio button is already checked, this method will not toggle the radio button.
*/
@Override
public void toggle() {
// we override to prevent toggle when the radio is already
// checked (as opposed to check boxes widgets)
if (!isChecked()) {
super.toggle();
}
} @Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(RadioButton. class.getName());
} @Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(RadioButton. class.getName());
}
}
和CheckBox实现差不多,区别在于多重写了一个方法,用于防止按钮被重复点击。另外还有ToggleButton以及Switch,前者实现也比较简单,后者稍微麻烦了一些,感兴趣可以自己分析。
- /**
- *
- */
- package com.kince.slidebutton;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.graphics.Canvas;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.MotionEvent;
- import android.view.View;
- /**
- * @author kince
- * @category 左右手势滑动button
- * @serial 1.0.0
- * @since 2014.5.17
- * @see http://blog.csdn.net/wangjinyu501
- *
- */
- public class SlideButton extends View {
- private Bitmap slideBitMap;// 滑动图片
- private Bitmap switchBitMap;// 背景图片
- private int slideBitMapWidth;// 滑动图片宽度
- private int switchBitMapWidth;// 背景图片宽度
- private int switchBitMapHeight;// 背景图片高度
- private boolean currentState;// 开关状态
- private boolean isSliding = false; // 是否正在滑动中
- private int currentX; // 当前开关的位置
- private OnToggleStateChangedListener mChangedListener;// 回调接口
- /**
- * @param context
- * 在java代码中直接调用使用此构造方法
- */
- public SlideButton(Context context) {
- this(context, null);
- // TODO Auto-generated constructor stub
- }
- /**
- * @param context
- * @param attrs
- * 在xml中使用要用到这个方法
- */
- public SlideButton(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- // TODO Auto-generated constructor stub
- }
- /**
- * @param context
- * @param attrs
- * @param defStyleAttr
- * 指定一个样式
- */
- public SlideButton(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- initBitmap();
- }
- /**
- * @category 加载背景图片以及开关图片 然后获取各自的宽高
- *
- */
- private void initBitmap() {
- // TODO Auto-generated method stub
- slideBitMap = BitmapFactory.decodeResource(getResources(),
- R.drawable.slide_button_background);
- switchBitMap = BitmapFactory.decodeResource(getResources(),
- R.drawable.switch_background);
- slideBitMapWidth = slideBitMap.getWidth();
- switchBitMapWidth = switchBitMap.getWidth();
- switchBitMapHeight = switchBitMap.getHeight();
- Log.i("switchBitMapWidth", switchBitMapWidth + "");
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- // TODO Auto-generated method stub
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- setMeasuredDimension(switchBitMapWidth, switchBitMapHeight);// 设置控件的宽高
- }
- @Override
- protected void onDraw(Canvas canvas) {
- // 绘制button背景图片
- canvas.drawBitmap(switchBitMap, 0, 0, null);
- // 绘制滑动开关
- if (isSliding) {// 如果当前状态是滑动中 则动态绘制开关
- int dis = currentX - slideBitMapWidth / 2;
- if (dis < 0) {
- dis = 0;
- } else if (dis > switchBitMapWidth - slideBitMapWidth) {
- dis = switchBitMapWidth - slideBitMapWidth;
- }
- canvas.drawBitmap(slideBitMap, dis, 0, null);
- } else {
- if (currentState) { // 绘制开关为开的状态
- canvas.drawBitmap(slideBitMap, switchBitMapWidth
- - slideBitMapWidth, 0, null);
- } else { // 绘制开关为关的状态
- canvas.drawBitmap(slideBitMap, 0, 0, null);
- }
- }
- super.onDraw(canvas);
- }
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- // 手势识别 判断滑动方向
- int action = event.getAction();
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- isSliding = true;
- currentX = (int) event.getX();
- break;
- case MotionEvent.ACTION_MOVE:
- currentX = (int) event.getX();
- Log.i("currentX", currentX + "");
- break;
- case MotionEvent.ACTION_UP:
- isSliding = false;
- int bgCenter = switchBitMapWidth / 2;
- boolean state = currentX > bgCenter; // 改变后的状态
- if (state != currentState && mChangedListener != null) {// 添加回调
- mChangedListener.onToggleStateChanged(state);
- }
- currentState = state;
- break;
- default:
- break;
- }
- invalidate();
- return true;
- }
- public OnToggleStateChangedListener getmChangedListener() {
- return mChangedListener;
- }
- public void setmChangedListener(
- OnToggleStateChangedListener mChangedListener) {
- this.mChangedListener = mChangedListener;
- }
- public boolean isToggleState() {
- return currentState;
- }
- public void setToggleState(boolean currentState) {
- this.currentState = currentState;
- }
- }
/**
*
*/
package com.kince.slidebutton; import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View; /**
* @author kince
* @category 左右手势滑动button
* @serial 1.0.0
* @since 2014.5.17
* @see http://blog.csdn.net/wangjinyu501
*
*/
public class SlideButton extends View { private Bitmap slideBitMap;// 滑动图片
private Bitmap switchBitMap;// 背景图片 private int slideBitMapWidth;// 滑动图片宽度
private int switchBitMapWidth;// 背景图片宽度
private int switchBitMapHeight;// 背景图片高度 private boolean currentState;// 开关状态
private boolean isSliding = false; // 是否正在滑动中 private int currentX; // 当前开关的位置 private OnToggleStateChangedListener mChangedListener;// 回调接口 /**
* @param context
* 在java代码中直接调用使用此构造方法
*/
public SlideButton(Context context) {
this(context, null);
// TODO Auto-generated constructor stub
} /**
* @param context
* @param attrs
* 在xml中使用要用到这个方法
*/
public SlideButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
// TODO Auto-generated constructor stub
} /**
* @param context
* @param attrs
* @param defStyleAttr
* 指定一个样式
*/
public SlideButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initBitmap();
} /**
* @category 加载背景图片以及开关图片 然后获取各自的宽高
*
*/
private void initBitmap() {
// TODO Auto-generated method stub
slideBitMap = BitmapFactory.decodeResource(getResources(),
R.drawable.slide_button_background);
switchBitMap = BitmapFactory.decodeResource(getResources(),
R.drawable.switch_background);
slideBitMapWidth = slideBitMap.getWidth();
switchBitMapWidth = switchBitMap.getWidth();
switchBitMapHeight = switchBitMap.getHeight();
Log.i("switchBitMapWidth", switchBitMapWidth + "");
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(switchBitMapWidth, switchBitMapHeight);// 设置控件的宽高
} @Override
protected void onDraw(Canvas canvas) {
// 绘制button背景图片
canvas.drawBitmap(switchBitMap, 0, 0, null);
// 绘制滑动开关
if (isSliding) {// 如果当前状态是滑动中 则动态绘制开关
int dis = currentX - slideBitMapWidth / 2;
if (dis < 0) {
dis = 0;
} else if (dis > switchBitMapWidth - slideBitMapWidth) {
dis = switchBitMapWidth - slideBitMapWidth;
}
canvas.drawBitmap(slideBitMap, dis, 0, null);
} else {
if (currentState) { // 绘制开关为开的状态
canvas.drawBitmap(slideBitMap, switchBitMapWidth
- slideBitMapWidth, 0, null);
} else { // 绘制开关为关的状态
canvas.drawBitmap(slideBitMap, 0, 0, null);
}
}
super.onDraw(canvas);
} @Override
public boolean onTouchEvent(MotionEvent event) {
// 手势识别 判断滑动方向
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
isSliding = true;
currentX = (int) event.getX();
break; case MotionEvent.ACTION_MOVE:
currentX = (int) event.getX();
Log.i("currentX", currentX + ""); break;
case MotionEvent.ACTION_UP:
isSliding = false;
int bgCenter = switchBitMapWidth / 2;
boolean state = currentX > bgCenter; // 改变后的状态
if (state != currentState && mChangedListener != null) {// 添加回调
mChangedListener.onToggleStateChanged(state);
}
currentState = state;
break;
default:
break;
}
invalidate();
return true;
} public OnToggleStateChangedListener getmChangedListener() {
return mChangedListener;
} public void setmChangedListener(
OnToggleStateChangedListener mChangedListener) {
this.mChangedListener = mChangedListener;
} public boolean isToggleState() {
return currentState;
} public void setToggleState(boolean currentState) {
this.currentState = currentState;
} }
回调接口,
- package com.kince.slidebutton;
- **
- * @author kince
- *
- */
- ublic interface OnToggleStateChangedListener {
- /**
- * @category
- * @param state
- */
- public void onToggleStateChanged(boolean state);
package com.kince.slidebutton; /**
* @author kince
*
*/
public interface OnToggleStateChangedListener { /**
* @category
* @param state
*/
public void onToggleStateChanged(boolean state); }
Activity代码,
- package com.kince.slidebutton;
- import android.support.v7.app.ActionBarActivity;
- import android.support.v7.app.ActionBar;
- import android.support.v4.app.Fragment;
- import android.support.v4.app.FragmentActivity;
- import android.os.Bundle;
- import android.view.LayoutInflater;
- import android.view.Menu;
- import android.view.MenuItem;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.Toast;
- import android.os.Build;
- public class MainActivity extends ActionBarActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- if (savedInstanceState == null) {
- getSupportFragmentManager().beginTransaction()
- .add(R.id.container, new PlaceholderFragment()).commit();
- }
- }
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.main, menu);
- return true;
- }
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- // Handle action bar item clicks here. The action bar will
- // automatically handle clicks on the Home/Up button, so long
- // as you specify a parent activity in AndroidManifest.xml.
- int id = item.getItemId();
- if (id == R.id.action_settings) {
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
- /**
- * A placeholder fragment containing a simple view.
- */
- public static class PlaceholderFragment extends Fragment implements
- OnToggleStateChangedListener {
- private SlideButton slidebutton;
- public PlaceholderFragment() {
- }
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View rootView = inflater.inflate(R.layout.fragment_main, container,
- false);
- slidebutton = (SlideButton) rootView.findViewById(R.id.slidebutton1);
- // 设置一下开关的状态
- slidebutton.setToggleState(true); // 设置开关的状态为打开
- slidebutton.setmChangedListener(this);
- return rootView;
- }
- @Override
- public void onToggleStateChanged(boolean state) {
- // TODO Auto-generated method stub
- FragmentActivity activity = getActivity();
- if (state) {
- Toast.makeText(activity, "开关打开", 0).show();
- } else {
- Toast.makeText(activity, "开关关闭", 0).show();
- }
- }
- }
- }
package com.kince.slidebutton; import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import android.os.Build; public class MainActivity extends ActionBarActivity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
} @Override
public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
} /**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment implements
OnToggleStateChangedListener { private SlideButton slidebutton; public PlaceholderFragment() {
} @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
slidebutton = (SlideButton) rootView.findViewById(R.id.slidebutton1);
// 设置一下开关的状态
slidebutton.setToggleState(true); // 设置开关的状态为打开
slidebutton.setmChangedListener(this);
return rootView;
} @Override
public void onToggleStateChanged(boolean state) {
// TODO Auto-generated method stub
FragmentActivity activity = getActivity();
if (state) {
Toast.makeText(activity, "开关打开", 0).show();
} else {
Toast.makeText(activity, "开关关闭", 0).show();
}
}
} }
未完待续。
滑动的Button的更多相关文章
- jQuery 效果 —— 滑动
jQuery 效果 -- 滑动 1.向下滑动元素 (1)使用slideDown()方法可以用于向下滑动元素 $("button").click(function(){ $(&quo ...
- Android开发--仿微信语音对讲录音
原文地址:http://www.2cto.com/kf/201502/378704.html 自微信出现以来取得了很好的成绩,语音对讲的实现更加方便了人与人之间的交流.今天来实践一下微信的语音对讲的录 ...
- [JS] JavaScript框架(1) jQuery
jQuery使用户能更方便地处理HTML(标准通用标记语言下的一个应用).events.实现动画效果,并且方便地为网站提供AJAX交互.jQuery还有一个比较大的优势是,它的文档说明很全,而且各种应 ...
- 160914、ionic指令简单布局
1) 添加引用类库(ionic样式和ionic js文件) 2) 标题栏,页脚栏,内容区 3) Js引入ionic类库,添加页面操作方法和对象 4) 数据初始化 5) Html页面绑定方法和对象 &l ...
- Android 实现用户列表信息的功能,然后选择删除幻灯片删除功能
在项目开发过程中.经常须要对用户列表的信息进行删除的操作.Android中经常使用的删除操作方式有两种 .一种就是类似微信的滑动出现删除button方式,另一种是通过CheckBox进行选择.然后通过 ...
- Callback方法和JQuery链的解释
这里讲到了一条语句运行多个JQuery方法(同一个元素)和动画100%完成后执行的callback方法. <!DOCTYPE html> <html> <head> ...
- 第三章 JQuery: HelloWorld--常见方法--css--选择器--筛选器--属性--效果--事件--数组操作--字符串操作--对象转换
1.jQuery简介 为了简化JavaScript 的开发, 一些JavsScript 库诞生了. JavaScript库封装了很多预定义的对象和实用函数.能帮助使用者建立有高难度交互的页面, 并且兼 ...
- Ionic学习笔记3_ionic指令简单布局
1) 添加引用类库(ionic样式和ionic js文件) 2) 标题栏,页脚栏,内容区 3) Js引入ionic类库,添加页面操作方法和对象 4) 数据初始化 5) Html页面 ...
- android 仿ios开关控件
ios一些控件还是挺美丽的,可是对android程序猿来说可能比較苦逼,由于ios一些看起来简单的效果对android来说可能就没那么简单了,可是没办法非常多产品都是拿ios的一些控件叫android ...
随机推荐
- jQuery hide()并不等于hide(0)
在实际使用中,经常用hide()函数来隐藏HTML元素,通常是没有什么问题的,但在一次做二级下拉菜单时遇到了问题,后来才发现有时候“speed”是不能省略的,即使“speed=0”,也就是说hide( ...
- Hive_初步见解,安装部署与测试
一.hive是什么东东 1. 个人理解 hive就是一个基于hdfs运行于MapReduce上的一个java项目, 这个项目封装了jdbc,根据hdfs编写了处理数据库的DDL/DML,自带的 二进制 ...
- Hibernate调用存储过程和函数
操作大批量数据或复杂逻辑,考虑到执行效率和代码量的时候,存储过程和函数在数据库中是预编译好的,调用执行效率高 // 调用过程 {call 过程名称(?,?,?)} public static void ...
- Scala命令设置JVM参数的规则
Scala下设置JVM参数简单分析 Scala 启动shell脚本,简化后的scala REPL 启动命令大致如下所示: java -Xmx256M -Xms32M \-Xbootclasspath/ ...
- poj 2325 Persistent Numbers
简单的贪心和高精度运算,主要还是要读懂题. #include"iostream" #include"stdio.h" #include"string& ...
- 【iCore3 双核心板】例程二十二:LAN_UDP实验——以太网数据传输
实验指导书及代码包下载: http://pan.baidu.com/s/1kTPlJMJ iCore3 购买链接: https://item.taobao.com/item.htm?id=524229 ...
- HTTP常见错误代码总结
1.HTTP 401 用户验证失败.不允许继续访问 2.HTTP 403 禁止访问,访问web应用,没有指定要访问页面的名称 3.HTTP 404 请求的文件找不到,一般情况是在浏览器输入地址时,输入 ...
- jdk动态代理学习
在jdk的好多底层代码中很多都使用jdk的动态代理,下面就写写简单的代码来look look. 老规矩先上代码: public interface SayDao { public String say ...
- mac 下面wireshark 找不到网卡
终端上面,执行如下命令: sudo chgrp admin /dev/bpf* sudo chmod g+rw /dev/bpf* http://www.9upk.com/article/25 ...
- ERROR 2006 (HY000) at line xx: MySQL server has gone away 解决方法