前言:前几天看到了迅雷app上有个一元夺宝,那时无聊就参加了几次,到后来中奖结果出来了,哎,根本就没我的份啊(意料之中),还好投的钱不多,就一块两块,不过,我看到了那里有个数值输入的效果,我当时想了想这个实现挺简单了,应该有很多种方式,于是做了个决定,如果没中奖,我就把那个数值输入器做出来以惩罚自己(开玩笑~),现在,该是兑现自己承诺的时候了。
先看看我们即将要实现的效果图:
大家看到这个效果,要实现这么一个控件,我们可以怎么做?
一开始,我心想,这还不简单,自定义一个view,然后分别画出左边的减号按钮,中间的输入控件,和右边的加法按钮,包括最外边的边框,最后重新view的事件监听方法,在里面判断点击的坐标,如果是点击了左边按钮的坐标范围,那么让中间的输入控件数值递减,如果是点击了右边按钮的坐标范围,那么让中间的输入按钮数值递增。
嗯,这听起来不错,好吧,我动手试着按照这种思路开始做了,当我在画中间的输入按钮的时候,我懵了,怎么才能画出一个可以让用户输入的控件?于是,我放弃了这种思路,开始了另一种思路。
接着,我想,这用类似组合控件的形式不是很简单吗,干嘛搞得那么复杂啊,这样一来,不是不仅不用自己画一个输入控件了,而且还不用计算点击坐标了。所以,下面将用组合控件的形式实现这个控件。
1. 自定义属性
为了提供控件的可定制性,我们需要自定义属性,观察上面的效果图,我们可以定义下面9个属性供用户使用(当然,你也可以定义其他的属性供用户定制)
- border_color:边框的颜色
- border_width:边框的宽度
- minus_color:减号的颜色
- minus_width:…
- plus_color:加号的颜色
- plus_width:…
- min_value:允许的最小值
- initial_value:初始值
- max_value:允许的最大值
2. 自定义加减按钮
为了解决耦合问题,那个减号,加号按钮使用自定义view绘图来实现,不引用任何资源,这里以加号按钮为例,做个说明(在文章结尾将会贴上全部代码)。
class PlusView extends View{
private Paint mPlusPaint;
public PlusView(Context context) {
this(context, null);
}
public PlusView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public PlusView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPlusPaint = new Paint();
mPlusPaint.setAntiAlias(true);
mPlusPaint.setStrokeWidth(mPlusWidth);
mPlusPaint.setStyle(Paint.Style.STROKE);
mPlusPaint.setStrokeCap(Paint.Cap.ROUND);
mPlusPaint.setColor(mPlusColor);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if(widthMode == MeasureSpec.AT_MOST){
widthSize = Math.min(widthSize,100);
}
if(heightMode == MeasureSpec.AT_MOST){
heightSize = Math.min(heightSize,100);
}
setMeasuredDimension(widthSize,heightSize);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();
canvas.drawLine(mWidth - mWidth / 5, mHeight / 2, mWidth / 5, mHeight / 2, mPlusPaint);
canvas.save();
canvas.rotate(90, mWidth / 2, mHeight / 2);
canvas.drawLine(mWidth / 5, mHeight / 2, mWidth - mWidth / 5, mHeight / 2, mPlusPaint);
canvas.restore();
}
}
这里自定义view,就是在测量的时候判断一些测量模式,如果是AT_MOST模式,那么给个最小值。测量完了以后,在onDraw()方法中画个加号就行了,对于自定义view不熟悉的可以参考这篇文章:android自定义view(一),打造绚丽的验证码
3. 继承LinearLayout实现控件组合
观察上面的效果图,可以看出这个控件的三部分是等宽的,所以,使用LinearLayout实现非常简单(weight属性),下面,定义类继承LinearLayout:
public class NumberInput extends LinearLayout {
public NumberInput(Context context) {
this(context, null);
}
public NumberInput(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public NumberInput(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// viewGroup必须设置背景,这样才会调用onDraw()方法
setBackgroundColor(Color.TRANSPARENT);
init(context,attrs);
initView(context);
}
}
这里,三个构造方法的调用情况就不多说了,不懂的可以问度娘~。我们在构造方法中做了一些初始化的工作,包括获取布局属性值,添加子view等等。这里,要注意的事,viewGroup默认是不会调用onDraw()方法的,我们可以给它设置背景强制viewGroup调用onDraw()方法。
获取属性值:
/**
* 获取自定义属性值
*/
private void init(Context context,AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.NumberInput);
mBorderColor = typedArray.getColor(R.styleable.NumberInput_border_color, Color.GRAY);
mBorderWidth = typedArray.getDimension(R.styleable.NumberInput_border_width, 6);
mMinusColor = typedArray.getColor(R.styleable.NumberInput_minus_color, Color.GRAY);
mMinusWidth = typedArray.getDimension(R.styleable.NumberInput_minus_width, 5);
mPlusColor = typedArray.getColor(R.styleable.NumberInput_plus_color, Color.GRAY);
mPlusWidth = typedArray.getDimension(R.styleable.NumberInput_plus_width, 5);
mInitialValue = typedArray.getInteger(R.styleable.NumberInput_initial_value, 0);
mMinValue = typedArray.getInteger(R.styleable.NumberInput_min_value, Integer.MIN_VALUE);
mMaxValue = typedArray.getInteger(R.styleable.NumberInput_max_value, Integer.MAX_VALUE);
<

最低0.47元/天 解锁文章
3798





