@linux1s1s
2016-09-22T11:04:35.000000Z
字数 3817
阅读 2187
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.TitleView
android: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 way
final 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);
}
...
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected 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
方法
@Override
protected 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^)/~。