1、自定义View
android中可能遇到很多需求要求自定义view,一般github上都有各种各样的酷炫效果自定义view,特别是仪表盘,柱状图,饼状图都有,但还是不免遇到一些特别的需求,自定义样式难以修改开源库,因此还是需要自己来实现。接下来记录自己一点一点学习自定义view的过程。接下来主要实现这样的效果(简单的实现画圆,和简单的动画效果)
项目目录结构
2、自定义view中构造方法
构造方法用来初始化view,一般的定义的view比如圆的宽,高,圆的颜色等,都是在我们xml文件中配置的,因此,我们必须重写带有AttributeSet的构造方法
/**
* 当需要在xml中声明此控件,则需要实现此构造函数
* 并且在构造函数中把自定义的属性与控件的数据成员连接起来
*
* @param context
* @param attrs
*/
public View1(Context context, AttributeSet attrs) {
super(context, attrs);
//如果xml文件中没有文件,则使用后面默认值;
paintOut = new Paint();
paintIn=new Paint();
//从attrs读取属性
TypedArray typedArray = context.obtainStyledAttributes(attrs,
R.styleable.MyView1);
this.cicle_in_color = typedArray.getColor(R.styleable.MyView1_cicle_in_color, Color.BLACK);
this.cicle_in_radius = typedArray.getDimension(R.styleable.MyView1_cicle_in_radius, 100);
this.cicle_in_StrokeWidth = typedArray.getDimension(R.styleable.MyView1_cicle_in_StrokeWidth, 5);
this.cicle_out_color = typedArray.getColor(R.styleable.MyView1_cicle_out_color, Color.BLACK);
this.cicle_out_radius = typedArray.getDimension(R.styleable.MyView1_cicle_out_radius, 30);
this.cicle_out_StrokeWidth = typedArray.getDimension(R.styleable.MyView1_cicle_out_StrokeWidth, 5);
//打开抗锯齿
paintOut.setAntiAlias(true);
//设置xml文件中的属性
paintOut.setColor(cicle_out_color);
paintOut.setStyle(Paint.Style.STROKE);
paintOut.setStrokeWidth(cicle_out_StrokeWidth);
paintIn.setColor(cicle_in_color);
paintIn.setStyle(Paint.Style.STROKE);
paintIn.setStrokeWidth(cicle_in_StrokeWidth);
//回收TypedArray,以便后面重用
typedArray.recycle();
}
3、在xml文件中配置自定义view的属性、
在values下新建attrs.xml文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
//自定义属性名,定义公共属性
<attr name="textSize" format="dimension"></attr>
<attr name="textTitle" format="string"></attr>
<attr name="textColor" format="color"></attr>
<attr name="cicle_color" format="color"></attr>
<attr name="cicle_radius" format="dimension"></attr>
<declare-styleable name="MyView1">
<attr name="cicle_color"></attr>
<attr name="cicle_out_color" format="color"></attr>
<attr name="cicle_out_radius" format="dimension"></attr>
<attr name="cicle_out_StrokeWidth" format="dimension"></attr>
<attr name="cicle_in_color" format="color"></attr>
<attr name="cicle_in_radius" format="dimension"></attr>
<attr name="cicle_in_StrokeWidth" format="dimension"></attr>
</declare-styleable>
<declare-styleable name="MyView2">
<attr name="textSize"></attr>
<attr name="textTitle"></attr>
<attr name="textColor"></attr>
<attr name="cicle_color"></attr>
<attr name="cicle_StrokeWidth" format="dimension"></attr>
<attr name="cicle_radius"></attr>
</declare-styleable>
</resources>
这样,就可以在界面的xml文件中配置这些属性,添加命名空间和声明的属性名称
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<view.viewActivity1.View1
android:layout_width="100dp"
android:layout_height="100dp"
custom:cicle_in_StrokeWidth="5dp"
custom:cicle_in_color="#00ff00"
custom:cicle_in_radius="20dp"
custom:cicle_out_StrokeWidth="5dp"
custom:cicle_out_color="#ff0000"
custom:cicle_out_radius="45dp"
/>
<view.viewActivity1.View2
android:id="@+id/view2"
android:layout_width="100dp"
android:layout_height="100dp"
custom:cicle_StrokeWidth="5dp"
custom:cicle_color="#0000ff" />
</LinearLayout>
4、自定义view的主要代码,在代码中做详解
1、画圆的主要代码
package view.viewActivity1;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import com.example.cusotmerview.R;
/**
* Created by yuxiaogang on 2017/2/23.
*/
public class View1 extends View {
private Paint paintOut;
private Paint paintIn;
private int cicle_in_color;
private float cicle_in_radius;
private float cicle_in_StrokeWidth;
private int cicle_out_color;
private float cicle_out_radius;
private float cicle_out_StrokeWidth;
public View1(Context context) {
super(context);
}
/**
* 当需要在xml中声明此控件,则需要实现此构造函数
* 并且在构造函数中把自定义的属性与控件的数据成员连接起来
*
* @param context
* @param attrs
*/
public View1(Context context, AttributeSet attrs) {
super(context, attrs);
//如果xml文件中没有文件,则使用后面默认值;
paintOut = new Paint();
paintIn=new Paint();
//从attrs读取属性
TypedArray typedArray = context.obtainStyledAttributes(attrs,
R.styleable.MyView1);
this.cicle_in_color = typedArray.getColor(R.styleable.MyView1_cicle_in_color, Color.BLACK);
this.cicle_in_radius = typedArray.getDimension(R.styleable.MyView1_cicle_in_radius, 100);
this.cicle_in_StrokeWidth = typedArray.getDimension(R.styleable.MyView1_cicle_in_StrokeWidth, 5);
this.cicle_out_color = typedArray.getColor(R.styleable.MyView1_cicle_out_color, Color.BLACK);
this.cicle_out_radius = typedArray.getDimension(R.styleable.MyView1_cicle_out_radius, 30);
this.cicle_out_StrokeWidth = typedArray.getDimension(R.styleable.MyView1_cicle_out_StrokeWidth, 5);
//打开抗锯齿
paintOut.setAntiAlias(true);
//设置xml文件中的属性
paintOut.setColor(cicle_out_color);
paintOut.setStyle(Paint.Style.STROKE);
paintOut.setStrokeWidth(cicle_out_StrokeWidth);
paintIn.setColor(cicle_in_color);
paintIn.setStyle(Paint.Style.STROKE);
paintIn.setStrokeWidth(cicle_in_StrokeWidth);
//回收TypedArray,以便后面重用
typedArray.recycle();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/**
* 第一个参数:圆心x坐标
* 第二个参数:圆心y坐标
* 第三个参数:半径
* 第四个参数:paint画笔
*/
canvas.drawCircle(100, 100, cicle_out_radius, paintOut);
canvas.drawCircle(100, 100, cicle_in_radius, paintIn);
}
}
2、画圆有动画效果的代码
package view.viewActivity1;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import com.example.cusotmerview.R;
/**
* Created by yuxiaogang on 2017/2/23.
*/
public class View2 extends View {
private Paint circlePaint;
private RectF circleRect;
private int cicle_out_color;
private float cicle_out_radius;
private float cicle_out_StrokeWidth;
private int mCurrentPercent;
public int getmTargetPercent() {
return mTargetPercent;
}
public void setmTargetPercent(int mTargetPercent) {
this.mTargetPercent = mTargetPercent;
}
private int mTargetPercent;
private float mCurrentAngle;
private float mStartSweepValue;
public View2(Context context) {
super(context);
}
/**
* 当需要在xml中声明此控件,则需要实现此构造函数
* 并且在构造函数中把自定义的属性与控件的数据成员连接起来
*
* @param context
* @param attrs
*/
public View2(Context context, AttributeSet attrs) {
super(context, attrs);
//如果xml文件中没有文件,则使用后面默认值;
circlePaint = new Paint();
//从attrs读取属性
TypedArray typedArray = context.obtainStyledAttributes(attrs,
R.styleable.MyView2);
this.cicle_out_color = typedArray.getColor(R.styleable.MyView2_cicle_color, Color.BLACK);
this.cicle_out_radius = typedArray.getDimension(R.styleable.MyView2_cicle_radius, 30);
this.cicle_out_StrokeWidth = typedArray.getDimension(R.styleable.MyView2_cicle_StrokeWidth, 5);
//回收TypedArray,以便后面重用
typedArray.recycle();
init();
}
private void init() {
mStartSweepValue = 180;
//当前角度
mCurrentAngle = 0;
//当前百分比
mCurrentPercent = 0;
circleRect = new RectF(20, 20, getWidth() - 20, getWidth() - 20);
}
public void setNumber(int size) {
mCurrentPercent = 0;
mTargetPercent = size;
mCurrentAngle = 0;
postInvalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//打开抗锯齿
circlePaint.setAntiAlias(true);
//设置xml文件中的属性
circlePaint.setColor(cicle_out_color);
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setStrokeWidth(cicle_out_StrokeWidth);
// 通过上下左右4个边的坐标来表示一个矩形,画圆就在这个矩形区域内;
circleRect = new RectF(10, 10, getWidth() - 10, getWidth() - 10);
/**
* drawArc()
* 第一个参数:圆弧外的轮廓区域
* 第二个参数,圆弧开始的角度
* 第三个参数,圆弧顺时针扫过的角度
* 第四个参数, 如果为True时,在绘制圆弧时将圆心包括在内,通常用来绘制扇形
* 第五个参数,画布
*/
canvas.drawArc(circleRect, mStartSweepValue, mCurrentAngle, false, circlePaint);
if (mCurrentPercent < mTargetPercent) {
//当前百分比+1
mCurrentPercent += 2;
//当前角度+360
mCurrentAngle += 7.2;
//每100ms重画一次
postInvalidateDelayed(100);
}
}
}