Android 自定义View

距离上次写博客很久了,今天终于有机会闲下来写写了,没办法一直忙项目了, 从项目中跟定大神学了点东西  感觉自定义View我掌握的不是很好正好研究了几天  然后写一个小Demo 希望对自定义view不熟悉的同学可以借鉴一下。

自定义View我是按照三步进行的

1.自定义属性(在values文件下面新建attrs)

   <!-- 自定义控件的属性 -->
    <declare-styleable name="MyViewCircle">
        <attr name="circleColor" format="color" />
        <attr name="max" format="integer"></attr>
        <attr name="circleProgress" format="color" />
        <attr name="circleBoderWidth" format="dimension" />
        <attr name="cicleBoderWidthColor" format="color" />
        <attr name="textColor" format="color" />
        <attr name="textSize" format="dimension" />
        <attr name="otherSize" format="dimension" />
        <attr name="bottomNumSize" format="dimension" />
        <attr name="style">
            <enum name="STROKE" value="0"></enum>
            <enum name="FILL" value="1"></enum>
        </attr>
    </declare-styleable>

这里面具体的我就不说了  大家百度一下肯定是可以弄明白的 

2.在自定义View的构造方法里面获取自定义的属性

public MyCircleView(Context context) {
this(context, null);
this.mContext = context;
}
public MyCircleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
this.mContext = context;
}
public MyCircleView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.mContext = context;
mPaint = new Paint();
TypedArray array = context.obtainStyledAttributes(attrs,
R.styleable.MyViewCircle);
/**
* 获取自定义属性
*/
circleColor = array.getColor(R.styleable.MyViewCircle_circleColor,
Color.YELLOW);
cicleBoderWidthColor = array.getColor(
R.styleable.MyViewCircle_cicleBoderWidthColor, Color.BLUE);
circleProgressColor = array.getColor(
R.styleable.MyViewCircle_circleProgress, Color.RED);
circleBoderWidth = UiSizeHelper.scalePx(context, 20);
max = array.getInteger(R.styleable.MyViewCircle_max, 100);
styleCircle = array.getInt(R.styleable.MyViewCircle_style, 0);
textColor = array.getColor(R.styleable.MyViewCircle_textColor,
Color.RED);
textSize = UiSizeHelper.scalePx(context, 40);
percentSize = UiSizeHelper.scalePx(context, 22);
otherSize = UiSizeHelper.scalePx(context, 30);
bottomNumSize = UiSizeHelper.scalePx(context, 25);
array.recycle();
}

UiSizeHelper这个是我自定义的一个辅助类 待会直接给大家上传 主要是一些手机屏幕的计算 这个也没什么好说的  如果对自定义View有一点的了解肯定理解这段代码

3.用OnDraw方法开始画(这里没有用onMearsor方法计算  根据具体情况调用)

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 得到最外面圆的半径
int centerWidth = getWidth() / 2;
// 内部圆的半径
int circleTwo = (int) (centerWidth - circleBoderWidth);
mPaint.setColor(cicleBoderWidthColor); // 设置圆环的颜色
mPaint.setStyle(Paint.Style.STROKE); // 设置空心
mPaint.setStrokeWidth(circleBoderWidth); // 设置圆环的宽度
mPaint.setAntiAlias(true); // 消除锯齿
canvas.drawCircle(centerWidth, centerWidth, circleTwo, mPaint);
// 点击效果画一个半透明的C
if (is_shade == 1) {
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setColor(color.myciecleBT);
mPaint.setStrokeWidth(0); // 设置圆环的宽度
mPaint.setAntiAlias(true);
canvas.drawCircle((float) centerWidth, (float) centerWidth,
(float) circleTwo-circleBoderWidth/2, mPaint);

// 画Text
mPaint.setStrokeWidth(0);
mPaint.setColor(textColor);
mPaint.setTextSize(textSize);
// 设置默认的字体
mPaint.setTypeface(Typeface.DEFAULT);
// 得到画上去的字体的宽度
float textWidth = mPaint.measureText(textContent + "");
// 得到画上去的字体的高度
float textHeight = (float) Math.ceil(mPaint.getFontMetrics().descent
- mPaint.getFontMetrics().ascent) / 2;
if (!TextUtils.isEmpty(textContent + "")) {
canvas.drawText(textContent + "", centerWidth - textWidth / 2 - 5,
centerWidth + textHeight / 2 + 4, mPaint);
mPaint.setTextSize(percentSize);
canvas.drawText("%", centerWidth + textWidth / 2 + 3, centerWidth
+ textHeight / 2 + 2, mPaint);
// 写上面和下面的字
// 上面的字
mPaint.setColor(Color.BLACK);
mPaint.setTextSize(otherSize);
float textWidth1 = mPaint.measureText("年化");
float textHeight1 = (float) Math
.ceil(mPaint.getFontMetrics().descent
- mPaint.getFontMetrics().ascent) / 2;
canvas.drawText("年化", centerWidth - textWidth1 / 2 - 1, centerWidth
- textHeight / 2 - UiSizeHelper.scalePx(mContext, 25),
mPaint);
// 下面的字
mPaint.setTextSize(bottomNumSize);
mPaint.setColor(Color.RED);
float textWidth3 = mPaint.measureText(borrow_duration + "");
if (duration_type == 1) {
// 前面的数字
canvas.drawText(
borrow_duration + "",
centerWidth - textWidth1 / 2 - 15,
centerWidth + textHeight / 2
+ UiSizeHelper.scalePx(mContext, 45), mPaint);
// 后面加上几个月
mPaint.setColor(Color.BLACK);
mPaint.setTextSize(otherSize);
canvas.drawText("个月", centerWidth - textWidth1 / 2 - 15
+ textWidth3, centerWidth + textHeight / 2
+ UiSizeHelper.scalePx(mContext, 45), mPaint);
// 天数
} else {
// 前面的数字
canvas.drawText(
borrow_duration + "",
centerWidth - textWidth1 / 2 + 2,
centerWidth + textHeight / 2
+ UiSizeHelper.scalePx(mContext, 45), mPaint);
// 后面加上几个月
mPaint.setColor(Color.BLACK);
mPaint.setTextSize(otherSize);
canvas.drawText(
"天",
centerWidth - textWidth1 / 2 + 2 + textWidth3,
centerWidth + textHeight / 2
+ UiSizeHelper.scalePx(mContext, 45), mPaint);
}

}


// 画圆弧
// 圆环上面的颜色(进度的颜色)
mPaint.setColor(circleProgressColor);
// 圆环的宽度
mPaint.setStrokeWidth(circleBoderWidth);
RectF oval = new RectF(centerWidth - circleTwo,
centerWidth - circleTwo, centerWidth + circleTwo, centerWidth
+ circleTwo); // 用于定义的圆弧的形状和大小的界限
mPaint.setStrokeCap(Paint.Cap.ROUND);
switch (styleCircle) {
// 空心
case STROKE:
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawArc(oval, -90, progress * 360 / max, false, mPaint);
Log.i("22", String.valueOf(progress / max * 360));
break;
// 实心
case FILL:
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawArc(oval, -90, progress * 360 / max, true, mPaint); // 根据进度画圆弧
break;


default:
break;
}
}

这个上面有详细的注释, 我想说的就几点 

a.画笔Paint画图的时候   我这里画的是一个圆  设置了画笔的stroke 其实是这样的


例如 我想画的圆的半径是50 我的mPaint.setStrokeWidth(20); 画笔宽度为20 那么这个画笔会怎么画,对就是图中红色线之间的距离 意思就是paint会居中去画 左边的红线离圆边10 右边的红线离圆边10 说了这么多 都是为了说明paint会居中去画  前提是设置了setStrokeWidth 默认的是0

RectF oval = new RectF(centerWidth - circleTwo,
centerWidth - circleTwo, centerWidth + circleTwo, centerWidth
+ circleTwo); // 用于定义的圆弧的形状和大小的界限

这句话大家最好动手画画  数学好的理解的肯定快点
其实我这个Demo的思路大概就是

先画一个圆  设置一个stroke为20 然后在画一个圆跟上一个圆是重合的 唯一不同的是stroke的颜色  这样两个颜色就区分开了 然后再根据进度做了一个线程的sleep 让大家看起来像动画一样得效果 其实不是动画 然后我自己开始弄不明白画笔怎么画的 我自己又加了一个点击效果

大家看Demo的时候可以看一下我具体怎么写的


这个是我的Mainactivty里面的

private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
if (msg.what == 1) {
myCircleView.setProgress((int) (Float.valueOf(String
.valueOf(index)) / Float.valueOf("220") * 100));
}
};
};

这里就是更新UI 看起来有一个动画 其实不是动画

下面的是动态计算一下这个控件占屏幕的宽度和高度

RelativeLayout.LayoutParams sp_params = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
sp_params.width = UiSizeHelper.getScreenWidth() / 3;
sp_params.height = UiSizeHelper.getScreenHeight() / 5;
sp_params.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
sp_params
.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
myCircleView.setLayoutParams(sp_params);
Log.i("MA", UiSizeHelper.getScreenHeight() / 5 + "");
myCircleView.setProgress((int) (Float.valueOf(String.valueOf(2))
/ Float.valueOf("220") * 100));
myCircleView.setBorrow_duration(20);
myCircleView.setDuration_type(1);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
initThread();
mThread.start();
}
}, 700);
}
public void initThread() {
mThread = new Thread() {
@SuppressWarnings("static-access")
public void run() {
for (int i = 2; i <= 150; i++) {
index = i;
Message message = Message.obtain();
message.what = 1;
mHandler.sendMessage(message);
try {
mThread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
};
}


这段代码里面UiSizeHelper是一个适配手机的类 我是根据720*1080去适配的  根据屏幕的比例去设置相应的大小

好 待会我传上Demo大家看一下

总结:

其实自定义View不难   开始会感觉特别难 最难的应该是 测量OnMesear里面的  我这个Demo里面没有涉及 等到时候遇到的时候还是会继续更新博客 如果想做一个中级开发或者高级开发 自定义View是必须掌握的 如果只是想一直静静的当个小程序员 。。。 提供一个我Demo的网址 http://download.youkuaiyun.com/detail/qq_20607305/9293291











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值