自定义View的步骤
今天来介绍下如何自定义类似iOS的按钮。
switch.gif要想自定义View,需要了解自定义View的相关步骤,一般来说自定义View需要实现以下操作:
自定义view步骤自定义切换按钮
1.自定义属性
根据自定义View中需要用户设置的属性,来构造自定义属性,直接在xml资源文件中的resources
标签下声明:
<declare-styleable name="Switch">
<attr name="checked" format="reference|boolean"/>
<attr name="switchOnColor" format="reference|color"/>
<attr name="switchOffColor" format="reference|color"/>
<attr name="spotOnColor" format="reference|color"/>
<attr name="spotOffColor" format="reference|color"/>
<attr name="spotPadding" format="reference|dimension"/>
<attr name="duration" format="reference|integer" />
</declare-styleable>
并在继承View类的Switch
类中声明全局变量:
private int switchOnColor;
private int switchOffColor;
private int spotOnColor;
private int spotOffColor;
private int spotPadding;
private boolean mChecked;
private int duration;
2.初始化构造函数
一般来说,如果自定义View用于在布局文件声明,则必须初始化覆盖基类的两个参数的构造函数;其他带参构造函数,根据需求进行初始化。
在构造函数中通过obtainStyledAttributes()
方法获取用户设置的属性值:
public Switch(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Switch);
switchOnColor = a.getColor(R.styleable.Switch_switchOnColor, DEFAULT_SWITCH_ON_COLOR);
switchOffColor = a.getColor(R.styleable.Switch_switchOffColor, DEFAULT_SWITCH_OFF_COLOR);
spotOnColor = a.getColor(R.styleable.Switch_spotOnColor, DEFAULT_SPOT_ON_COLOR);
spotOffColor = a.getColor(R.styleable.Switch_spotOffColor, DEFAULT_SPOT_OFF_COLOR);
spotPadding = a.getDimensionPixelSize(R.styleable.Switch_spotPadding, dp2px(DEFAULT_SPOT_PADDING));
duration = a.getInteger(R.styleable.Switch_duration, ANIMATION_DURATION);
mChecked = a.getBoolean(R.styleable.Switch_checked, false);
a.recycle();
state = mChecked ? State.SWITCH_ON : State.SWITCH_OFF;
setClickable(true);
}
3.测量View——onMeasure
onMeasure
方法是决定自定义View布局大小的关键,可通过MeasureSpec
获取父布局分配给子布局的大小及布局模式。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int width = dp2px(DEFAULT_WIDTH) + getPaddingLeft() + getPaddingRight();
int height = dp2px(DEFAULT_HEIGHT) + getPaddingTop() + getPaddingBottom();
if (widthSpecMode != MeasureSpec.AT_MOST) {
width = Math.max(width, widthSpecSize);
}
if (heightSpecMode != MeasureSpec.AT_MOST) {
height = Math.max(height, heightSpecSize);
}
setMeasuredDimension(width, height);
}
4.给定View高宽——setMeasuredDimension
通过setMeasuredDimension
方法设置自定义布局想要的View大小。代码如上所示。
5.绘制View——onDraw
最核心的方法莫过于onDraw
了,onDraw
是绘制View的关键,结合ValueAnimator
、ObjectAnimator
等可实现View的动画效果。
private void animateToCheckedState() {
valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.setDuration(duration);
valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPos = (float) animation.getAnimatedValue();
invalidate();
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
isMoving = true;
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
isMoving = false;
}
});
if (!valueAnimator.isRunning()) {
valueAnimator.start();
currentPos = 0;
}
}
6.回调监听
切换按钮的回调,主要体现在开关状态的变化:
public interface OnCheckedChangeListener {
/**
* Called when the checked state of a switch has changed.
*
* @param s The switch whose state has changed.
* @param isChecked The new checked state of switch.
*/
void onCheckedChanged(Switch s, boolean isChecked);
}
7.手势处理
本项目中并未使用onTouchEvent方法处理手势监听,而是覆盖了父类的performClick
方法,同时保证了OnClickListener
的生效。
@Override
public boolean performClick() {
toggle();
final boolean handled = super.performClick();
if (!handled) {
// View only makes a sound effect if the onClickListener was
// called, so we'll need to make one here instead.
playSoundEffect(SoundEffectConstants.CLICK);
}
return handled;
}
网友评论
at com.fynn.switcher.Switch.setChecked(Switch.java:330)
at com.fynn.switcher.Switch.toggle(Switch.java:393)
at com.fynn.switcher.Switch.performClick(Switch.java:276)
这些伟大的方法不存在