在研究了幾個星期的view以后,打算自定義個view鞏固檢驗1下最近學的知識,view知知趣關博文
首先,定義1個繼承自view的子類Customview
public class CustomView extends View { private String mCustomTitle;//標題文本 private int mTitleTxtSize;//標題字體大小 private int mTitleTxtColor;//標題文本色彩 private String mCustomCont;//正文文本 private int mContTxtSize;//正文字體大小 private int mContTxtColor;//正文文本色彩 private Rect mBounds; private TextPaint mPaint; public CustomView(Context context) { super(context); } public CustomView(Context context, AttributeSet attrs) { this(context, attrs,0); } public CustomView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mPaint = new TextPaint(); mBounds = new Rect(); TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CustomViewStyle); //從添加view的xml文件中獲得到view的相干屬性信息 //標題相干屬性 mCustomTitle = array.getString(R.styleable.CustomViewStyle_customTitle); mTitleTxtSize = array.getDimensionPixelSize(R.styleable.CustomViewStyle_titleTxtSize, (int) getResources().getDimension(R.dimen.title_default_size)); mTitleTxtColor= array.getColor(R.styleable.CustomViewStyle_titleTxtColor, Color.BLACK); //正文文本相干屬性 mCustomCont = array.getString(R.styleable.CustomViewStyle_customCont); mContTxtSize = array.getDimensionPixelSize(R.styleable.CustomViewStyle_contTxtSize, (int) getResources().getDimension(R.dimen.cont_default_size)); mContTxtColor = array.getColor(R.styleable.CustomViewStyle_contTxtColor,Color.GRAY); array.recycle(); }
對1個view在xml中相干的 屬性有限,我們需要添加自己想要的屬性,添加方式也很簡單,
第1步那就是在values目錄下創建1個resource為節點的資源文件,把想要的屬性添加進去
<?xml version="1.0" encoding="utf⑻"?> <resources> <declare-styleable name="CustomViewStyle"> <attr name="customTitle" format="string"/> <attr name="customCont" format="string"/> <attr name="titleTxtSize" format="dimension"/> <attr name="contTxtSize" format="dimension"/> <attr name="titleTxtColor" format="color"/> <attr name="contTxtColor" format="color"/> </declare-styleable> </resources>
第3步,現在,可以在xml文件中使用了
<com.fang.zrf.customview.widges.CustomView android:layout_width="wrap_content" android:layout_height="wrap_content" custom:customTitle="@string/custom_view_title" custom:customCont="@string/custom_view_cont" android:paddingLeft="50dp"/>
xmlns:custom="http://schemas.android.com/apk/res-auto"
屬性添加成功后可以進行丈量,布局和繪制了。
即需要重寫onMeasure和onDraw方法。
這樣整體來看,其實自定義view也不是很麻煩??偨Y下來就是
第1,先定義自己的view類
第2,創建資源文件添加view的屬性
第3,在onMeasure方法中丈量view所需要顯示的大小
第4,在onDraw中借助畫筆和畫布把view繪制出來。
恩~看著確切挺簡單,實現起來真是問題層見疊出
轉載請注明出處
問題1 ,Paint畫筆對象為null的異常
FATAL EXCEPTION: main Process: com.fang.zrf.mycustomview, PID: 12882 java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference at android.graphics.Canvas.drawText(Canvas.java:1656) at com.fang.zrf.mycustomview.widgets.CustomViewSec.onDraw(CustomViewSec.java:76) at android.view.View.draw(View.java:16207)
public CustomView(Context context) { super(context); } public CustomView(Context context, AttributeSet attrs) { super(context, attrs); } public CustomView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mPaint = new Paint(); TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CustomViewStyle); //從添加view的xml文件中獲得到view的相干屬性信息 //標題相干屬性 mCustomTitle = array.getString(R.styleable.CustomViewStyle_customTitle); mTitleTxtSize = array.getDimensionPixelSize(R.styleable.CustomViewStyle_titleTxtSize, (int) getResources().getDimension(R.dimen.title_default_size)); mTitleTxtColor= array.getColor(R.styleable.CustomViewStyle_titleTxtColor, Color.BLACK); //正文文本相干屬性 mCustomCont = array.getString(R.styleable.CustomViewStyle_customCont); mContTxtSize = array.getDimensionPixelSize(R.styleable.CustomViewStyle_contTxtSize, (int) getResources().getDimension(R.dimen.cont_default_size)); mContTxtColor = array.getColor(R.styleable.CustomViewStyle_contTxtColor,Color.GRAY); array.recycle(); }
我自定義view時實現了3個構造方法,使用的是as中的快捷鍵創建的,以致于第3個構造方法根本就沒調用,所以做甚么都是錯的,解決方案很簡單,那就是把第2個構造方法的方法體改1下便可
public CustomView(Context context, AttributeSet attrs) { this(context, attrs,0); }
通過前幾篇對view的分析可以得出,這個draw繪制出來的大小跟onMeasure方法是分不開的,所以呢,重點是對所丈量的寬和高進行重新計算
利用paint畫筆對象可以直接對文本的寬高進行計算:
private Rect mBounds; mBounds = new Rect(); @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int measuredWidth; int measuredHeight; int widthMode = MeasureSpec.getMode(widthMeasureSpec);//獲得丈量規范,對這些不曉得可參考博文 int width = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); mPaint.getTextBounds(mCustomTitle,0,mCustomTitle.length(),mBounds); if (widthMode != MeasureSpec.EXACTLY){ measuredWidth = mBounds.width(); }else{//在xml文件中規定了準確的值 measuredWidth = width; } if (heightMode != MeasureSpec.EXACTLY){ Log.i("fang","---"); measuredHeight = mBounds.height(); }else{ measuredHeight = height; } setMeasuredDimension(measuredWidth + getPaddingLeft() + getPaddingRight(), measuredHeight + getPaddingTop() + getPaddingBottom()); }
然落后行繪制:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setTextSize(mTitleTxtSize); mPaint.setColor(mTitleTxtColor); canvas.drawText(mCustomTitle,getPaddingLeft(), getHeight()/2 + mBounds.height()/2,mPaint); }
第1張圖是每次重新oncreate界面時的效果,(在此聲明1下設置的view是paddingleft為50dp)
第2張圖是每次onPause然后onResume以后的效果。
由以上這兩張圖可以發現兩個問題
第1,每次oncreate時view所繪制出的大小其實不正確
第2,view沒有自動換行,view的繪制已超越了父view的邊界
是否是發現問題層見疊出??漸漸來吧
問題3,在oncreate時view所繪制的大小不正確
問題4,view需要換行
問題3和問題4待解決中,估計需要點兒時間,有解決方案的請留言,謝謝,也歡迎各位分享你自定義view時所遇到的問題