初次自定義view,繪製了一個表,點擊錶針會轉動。自定義的控件的儘量將可以從外部設置的屬性暴露出來,這樣增加控件適用場合和靈活性。
思路
- extends view並實現其中的onDraw方法來實現繪製圖形
- 重寫其中的ClockView(Context context, AttributeSet attrs)來實現在xml中的引用
- implements View.OnClickListener來實現監聽點擊
- 重寫onSizeChanged方法實現部分參數的初始化和對界面尺寸變化的適應
參數說明
private int count_clicked=0;//點擊次數
private float mborderwidth;//畫筆寬度
private int mbordercolor;//線條顏色
private Paint mPaint;//畫筆
private RectF mBounds;//矩形
private float mWidth;//矩形區寬度
private float mHeight;//矩形區高度
private float mRadius;//指針半徑
private float smalllength;//小刻度長
private float largerlength;//大刻度長
1.創建一個ClockView繼承自view並實現View.OnClickListener方法,一定要記得重載其中的第二個構造器,這樣才能在xml中引用
public class ClockView extends View implements View.OnClickListener
public ClockView(Context context)
public ClockView(Context context, AttributeSet attrs)
public ClockView(Context context, AttributeSet attrs, int defStyleAttr)
2.爲了在xml中設置屬性,爲控件設置屬性,在values下創建attrs.xml文件
<resources>
<declare-styleable name="ClockView">
<attr name="border_color" format="color"/>
<attr name="border_width" format="dimension"/>
</declare-styleable>
</resources>
3.重寫構造方法,從xml中解析屬性,初始化一些數據
public ClockView(Context context, AttributeSet attrs) {
super(context, attrs);
//獲取xml中的自定義屬性
TypedArray typedArray=context.getTheme().obtainStyledAttributes(
attrs,R.styleable.ClockView,0,0);
mbordercolor=typedArray.getColor(R.styleable.ClockView_border_color,0xff000000);
mborderwidth=typedArray.getDimension(R.styleable.ClockView_border_width, 2);
InitPara();
setOnClickListener(this);
}
4.初始化畫筆並處理點擊事件,每次點擊旋轉6度,一共可以旋轉60次,count_clicked記錄需要旋轉的次數(在每個構造器中添加InitPara(); setOnClickListener(this);)
private void InitPara(){
mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mborderwidth);
mPaint.setColor(mbordercolor);
}
@Override
public void onClick(View v) {
count_clicked++;//控制錶針的轉動位置
if(count_clicked%60==0){
count_clicked=0;
}
invalidate();//重新繪製,調用onDraw
}
5.重寫onSizeChanged,並進行一些數據初始化
/**
* 當界面的尺寸發生改變時調用
* @param w
* @param h
* @param oldw
* @param oldh
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBounds=new RectF(getLeft(),getTop(),getRight(),getBottom());
mWidth=mBounds.right-mBounds.left;
mHeight=mBounds.bottom-mBounds.top;
if(mHeight<mWidth){
mRadius=mHeight/4;
}else{
mRadius=mWidth/4;
}
smalllength=30;
largerlength=60;
}
6.自定義ClockDraw(canvas, count_clicked)用來繪製自定義的圖形
private void ClockDraw(Canvas canvas,int count){
//繪製底色和矩形框
canvas.drawColor(0xff000000);
canvas.drawRoundRect(new RectF(mBounds.centerX()-(float)0.9*mWidth/2,
mBounds.centerY() - (float)0.9*mHeight/2,
mBounds.centerX() + (float)0.9*mWidth/2,
mBounds.centerY() + (float)0.9*mHeight/2), 30, 30, mPaint);
mPaint.setColor(mbordercolor);
//繪製錶盤的刻度
float start_x,start_y;
float end_x,end_y;
for(int i=0;i<60;i++)
{
start_x=mRadius*(float)Math.cos(Math.PI / 180 * i * 6);
start_y=mRadius*(float)Math.sin(Math.PI/180*i*6);
if(i%5==0){
end_x=(mRadius+largerlength)*(float)Math.cos(Math.PI / 180 * i * 6);
end_y=(mRadius+largerlength)*(float)Math.sin(Math.PI/180*i*6);
}else {
end_x=(mRadius+smalllength)*(float)Math.cos(Math.PI / 180 * i * 6);
end_y=(mRadius+smalllength)*(float)Math.sin(Math.PI/180*i*6);
}
start_x+=mBounds.centerX();
start_y+=mBounds.centerY();
end_x+=mBounds.centerX();
end_y+=mBounds.centerY();
canvas.drawLine(start_x,start_y,end_x,end_y,mPaint);
}
canvas.drawCircle(mBounds.centerX(), mBounds.centerY(), mRadius, mPaint);//錶盤的圓
canvas.drawCircle(mBounds.centerX(), mBounds.centerY(), 20, mPaint);//表芯的圓
canvas.rotate(6 * count, mBounds.centerX(), mBounds.centerY());//旋轉畫布,座標系跟隨畫布旋轉
canvas.drawLine(mBounds.centerX(), mBounds.centerY(), mBounds.centerX(), mBounds.centerY() - mRadius, mPaint);
}
7.重寫onDraw方法,調用自己的Draw方法
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
ClockDraw(canvas, count_clicked);
}
在xml中調用自定義的view,設置顏色和線條粗細
<com.demo.eric.defineview.ClockView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:border_color="#eaf1e90b"
app:border_width="4dp"/>
完成!!!
總結:
重點是onDraw中的重寫,在onDraw中進行一系列的圖形繪製;canvas作爲畫布,利用paint在canvas上調用canvas.drawXXX(X,X,X,……,paint)繪製自己想要的圖形。
ClockView整體源碼
/**
* Created by Administrator on 2016/1/7 0007.
*/
public class ClockView extends View implements View.OnClickListener {
private int count_clicked=0;//點擊次數
private float mborderwidth;//畫筆寬度
private int mbordercolor;//線條顏色
private Paint mPaint;//畫筆
private RectF mBounds;//矩形
private float mWidth;//矩形區寬度
private float mHeight;//矩形區高度
private float mRadius;//指針半徑
private float smalllength;//小刻度長
private float largerlength;//大刻度長
public ClockView(Context context) {
super(context);
setOnClickListener(this);
InitPara();
}
public ClockView(Context context, AttributeSet attrs) {
super(context, attrs);
//獲取xml中的自定義屬性
TypedArray typedArray=context.getTheme().obtainStyledAttributes(
attrs,R.styleable.ClockView,0,0);
mbordercolor=typedArray.getColor(R.styleable.ClockView_border_color,0xff000000);
mborderwidth=typedArray.getDimension(R.styleable.ClockView_border_width, 2);
InitPara();
setOnClickListener(this);
}
public ClockView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
InitPara();
setOnClickListener(this);
}
private void InitPara(){
mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mborderwidth);
mPaint.setColor(mbordercolor);
}
/**
* 當界面的尺寸發生改變時調用
* @param w
* @param h
* @param oldw
* @param oldh
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBounds=new RectF(getLeft(),getTop(),getRight(),getBottom());
mWidth=mBounds.right-mBounds.left;
mHeight=mBounds.bottom-mBounds.top;
if(mHeight<mWidth){
mRadius=mHeight/4;
}else{
mRadius=mWidth/4;
}
smalllength=30;
largerlength=60;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
ClockDraw(canvas, count_clicked);
}
private void ClockDraw(Canvas canvas,int count){
//繪製底色和矩形框
canvas.drawColor(0xff000000);
canvas.drawRoundRect(new RectF(mBounds.centerX()-(float)0.9*mWidth/2,
mBounds.centerY() - (float)0.9*mHeight/2,
mBounds.centerX() + (float)0.9*mWidth/2,
mBounds.centerY() + (float)0.9*mHeight/2), 30, 30, mPaint);
mPaint.setColor(mbordercolor);
//繪製錶盤的刻度
float start_x,start_y;
float end_x,end_y;
for(int i=0;i<60;i++)
{
start_x=mRadius*(float)Math.cos(Math.PI / 180 * i * 6);
start_y=mRadius*(float)Math.sin(Math.PI/180*i*6);
if(i%5==0){
end_x=(mRadius+largerlength)*(float)Math.cos(Math.PI / 180 * i * 6);
end_y=(mRadius+largerlength)*(float)Math.sin(Math.PI/180*i*6);
}else {
end_x=(mRadius+smalllength)*(float)Math.cos(Math.PI / 180 * i * 6);
end_y=(mRadius+smalllength)*(float)Math.sin(Math.PI/180*i*6);
}
start_x+=mBounds.centerX();
start_y+=mBounds.centerY();
end_x+=mBounds.centerX();
end_y+=mBounds.centerY();
canvas.drawLine(start_x,start_y,end_x,end_y,mPaint);
}
canvas.drawCircle(mBounds.centerX(), mBounds.centerY(), mRadius, mPaint);//錶盤的圓
canvas.drawCircle(mBounds.centerX(), mBounds.centerY(), 20, mPaint);//表芯的圓
canvas.rotate(6 * count, mBounds.centerX(), mBounds.centerY());//旋轉畫布,座標系跟隨畫布旋轉
canvas.drawLine(mBounds.centerX(), mBounds.centerY(), mBounds.centerX(), mBounds.centerY() - mRadius, mPaint);
}
@Override
public void onClick(View v) {
count_clicked++;
if(count_clicked%60==0){
count_clicked=0;
}
invalidate();
}
}