1.自定義屬性的聲明和獲取
2.測量onMeasure
3.繪製onDraw
4.狀態的存儲和恢復(考慮在activity重建之後要存儲和恢復的)
主要是通過onSaveInstanceState()(實現存儲)和onRestoreInstanceState()方法來實現
自定義一個TestView的類繼承View
public class TestView extends View { private static final String TAG = "TestView"; private Paint mPaint; public TestView(Context context) { super(context); } //如果想要view在佈局xml // 文件中使用,一定要重寫這個構造方法 public TestView(Context context, AttributeSet attrs) { super(context, attrs); initPaint(); TypedArray ta=context.obtainStyledAttributes(attrs, R.styleable.TestView); ta.getBoolean(R.styleable.TestView_test_boolean,false); boolean booleanTest=ta.getBoolean(R.styleable.TestView_test_boolean,false); int IntegerTest= ta.getInteger(R.styleable.TestView_test_integer,-1); float dimensionTest=ta.getDimension(R.styleable.TestView_test_dimension,0); String stringTest=ta.getString(R.styleable.TestView_test_string);//getString方法不需要默認值 int enumTest=ta.getInteger(R.styleable.TestView_test_emun,1); ta.recycle();//進行回收 Log.e(TAG,booleanTest+","+IntegerTest+","+dimensionTest+","+stringTest+","+enumTest); } }
重寫自定義view的構造方法:
自定義控件模式:
MeasureSpec.EXACTLY | 精確模式,尺寸的值是多少,那麼控件的長和寬就是多少 |
MeasureSpec.ATMOST | 最大模,同時父控件給出一個最大空間,不能超過這個值 |
MeasureSpec.UNSPECIFIED | 未指定模式,當前組件,可得到的空間不受限制 |
用於測量的代碼:
package com.example.animation.frame; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.util.Log; import android.view.View; import com.example.animation.R; public class TestView extends View { private static final String TAG = "TestView"; public TestView(Context context) { super(context); } //如果想要view在佈局xml // 文件中使用,一定要重寫這個構造方法 public TestView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray ta=context.obtainStyledAttributes(attrs, R.styleable.TestView); ta.getBoolean(R.styleable.TestView_test_boolean,false); boolean booleanTest=ta.getBoolean(R.styleable.TestView_test_boolean,false); int IntegerTest= ta.getInteger(R.styleable.TestView_test_integer,-1); float dimensionTest=ta.getDimension(R.styleable.TestView_test_dimension,0); String stringTest=ta.getString(R.styleable.TestView_test_string);//getString方法不需要默認值 int enumTest=ta.getInteger(R.styleable.TestView_test_emun,1); ta.recycle();//進行回收 Log.e(TAG,booleanTest+","+IntegerTest+","+dimensionTest+","+stringTest+","+enumTest); } public TestView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //獲得父控件傳入的值 int widthMode=MeasureSpec.getMode(widthMeasureSpec); int widthSize=MeasureSpec.getSize(widthMeasureSpec); int width=0; if(widthMode==MeasureSpec.EXACTLY) { width=widthSize; }else{ int needWidth=measureWidth()+getPaddingLeft()+getPaddingRight(); if(widthMode==MeasureSpec.AT_MOST)//needWidth不能超過父控件傳入的值 { width=Math.min(needWidth,widthSize); }else{ width=needWidth;//測量有多大就有多大 } } int heightMode=MeasureSpec.getMode(heightMeasureSpec); int heightSize=MeasureSpec.getSize(heightMeasureSpec); int height=0; if(heightMode==MeasureSpec.EXACTLY) { height=heightSize; }else{//自己測量 int needHeight=measureHeight()+getPaddingTop()+getPaddingBottom(); if(heightMode==MeasureSpec.AT_MOST) { height=Math.min(needHeight,heightSize); }else{ height=needHeight; } } super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(width,height); } private int measureHeight() { return 0; } private int measureWidth() { return 0; } }
canvas來繪製形狀,Paint來控制畫筆
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setStrokeWidth(1); canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/2,mPaint);//⚪ canvas.drawLine(0,getHeight()/2,getWidth(),getHeight()/2,mPaint);//橫向的線 canvas.drawLine(getWidth()/2,0,getWidth(),getHeight()/2,mPaint);// } private void initPaint()//初始化畫筆 { mPaint=new Paint(); mPaint.setStyle(Paint.Style.STROKE);//畫一個空心⚪、 mPaint.setStrokeWidth(6); mPaint.setColor(0xFFFF0000); mPaint.setAntiAlias(true); }
注意一定要給要恢復的控件加上id啊!(不然無法恢復)
保存和恢復的時候,需要注意父控件也要保存和恢復:
private static final String INSTANCE="instance"; private static final String KEY_TEXT="key_text"; @Override protected Parcelable onSaveInstanceState() { Bundle bundle=new Bundle(); bundle.putString(KEY_TEXT,mText); bundle.putParcelable(INSTANCE,super.onSaveInstanceState()); return super.onSaveInstanceState(); } @Override protected void onRestoreInstanceState(Parcelable state) { if(state instanceof Bundle) { //先恢復父控件的 Bundle bundle=(Bundle)state; Parcelable parcelable=bundle.getParcelable(INSTANCE); super.onRestoreInstanceState(parcelable); //再恢復自己的 mText=bundle.getString(KEY_TEXT); return; } super.onRestoreInstanceState(state); }