@linux1s1s
2016-09-22T03:04:35.000000Z
字数 3817
阅读 2510
AndroidView
阅读此篇博客前请先行阅读 Android View 自定义属性 然后我们来回顾一下自定义View需要做哪些事情:
onMeasure方法,如果需要的话onDraw方法上面四个步骤一般在自定义View的时候都需要,如果父类的onMeasure测量有误,这里一般会发生在wrap_content的时候,父类的测量有可能会当成match_parent来处理,所以需要我们主动修改这个测量过程。
<?xml version="1.0" encoding="utf-8"?><resources><attr name="titleText" format="string" /><attr name="titleColor" format="color" /><attr name="titleSize" format="dimension" /><declare-styleable name="TitleView"><attr name="titleText" /><attr name="titleColor" /><attr name="titleSize" /></declare-styleable></resources>
这里提示一下,format的类型一共有以下几个:string,color,demension,integer,enum,reference,float,boolean,fraction,flag;
然后我们在Layout文件中使用这个自定义属性
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:linroid="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"><android.neulion.com.viewattrs.TitleViewandroid:layout_width="match_parent"android:layout_height="@dimen/custom_view_height"android:id="@+id/my_id"linroid:titleText="@string/hello_world"linroid:titleSize="@dimen/title_text_size"linroid:titleColor="@android:color/background_dark" /></RelativeLayout>
注意这里的命名空间,Studio下可能会报错,但是并不影响使用。
public class TitleView extends View{private String mTitleText;private int mTitleColor;private int mTitleSize;private final Paint mPaint;private final Rect mRect;public TitleView(Context context, AttributeSet attrs){this(context, attrs, 0);}public TitleView(Context context, AttributeSet attrs, int defStyleAttr){super(context, attrs, defStyleAttr);final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TitleView);//one way// mTitleText = a.getString(R.styleable.TitleView_titleText);// mTitleColor = a.getInt(R.styleable.TitleView_titleColor, -1);// mTitleSize = a.getInt(R.styleable.TitleView_titleSize, -1);//or other wayfinal int size = a.getIndexCount();for (int i = 0; i < size; i++){int attr = a.getIndex(i);switch (attr){case R.styleable.TitleView_titleText:mTitleText = a.getString(attr);break;case R.styleable.TitleView_titleColor:mTitleColor = a.getDimensionPixelSize(attr, -1);break;case R.styleable.TitleView_titleSize:mTitleSize = a.getColor(attr, -1);break;}}a.recycle();mPaint = new Paint();mPaint.setTextSize(mTitleSize);mRect = new Rect();mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mRect);}...}
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){super.onMeasure(widthMeasureSpec, heightMeasureSpec);}
@Overrideprotected void onDraw(Canvas canvas){super.onDraw(canvas);mPaint.setColor(Color.YELLOW);canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);mPaint.setColor(mTitleColor);canvas.drawText(mTitleText,getWidth() / 2 - mRect.width() / 2, getHeight() / 2 - mRect.height() / 2, mPaint);}
Run一下,看看效果如下:

看到这里是不是感觉良好,不过,加入我们把layout文件修改成wrap_content这个时候是啥样子?

完全不是我们想象的样子了,说明父View的measure出问题了,它并没有测量准确我们希望的样子,所以必须自己重写onMeasure方法
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){int widthMode = MeasureSpec.getMode(widthMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);int width;int height ;if (widthMode == MeasureSpec.EXACTLY){width = widthSize;} else{mPaint.setTextSize(mTitleTextSize);mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds);float textWidth = mBounds.width();int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());width = desired;}if (heightMode == MeasureSpec.EXACTLY){height = heightSize;} else{mPaint.setTextSize(mTitleTextSize);mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds);float textHeight = mBounds.height();int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom());height = desired;}setMeasuredDimension(width, height);}
接下来在Run一下看看

到这里已经自定义View完成了,是不是没有想象中的那么难(^o^)/~。
