在研究了几个星期的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也不是很麻烦。总结下来就是
第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时所遇到的问题