再来回顾一下自定义View的步骤:
1、自定义View的属性
2、在View的构造方法中获得我们自定义的属性
[ 3、重写onMesure ]
4、重写onDraw
相信看过前两篇博客的同学,对这个步骤已经差不多熟悉了。现在我对第一篇博客中的TextViw有些疑问:
1 如果在填写控件大小的时候,填大了,超过了屏幕的宽度
如下:
<com.pepe.widgetdemo.OneTextView
android:layout_width="480dp"
android:layout_height="100dp"
android:layout_marginTop="10dp"
custom:text="第三个:宽度超过屏幕"
custom:textColor="#0000ff"
custom:textSize="20sp" />
会是什么效果
2 如果控件中的文字过多,超过了屏幕的宽度
如下:
<com.pepe.widgetdemo.OneTextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="10dp"
custom:text="第四个:文字长度超过屏幕文字长度超过屏幕文字长度超过屏幕文字长度超过屏幕"
custom:textColor="#0000ff"
custom:textSize="20sp" />
又会是什么效果
3 如果文字的宽度为wrap_content
<com.pepe.widgetdemo.OneTextView
android:layout_width="wrap_content"
android:layout_height="100dp"
android:layout_marginTop="10dp"
custom:text="第五个:wrap_content"
custom:textColor="#0000ff"
custom:textSize="20sp" />
我希望背景的宽度能刚好包裹文字
我们先来看问题1和问题2的效果:
很显然,效果是不尽如人意的,那么如何去改善呢,这就需要重写onMeasure()方法了。
针对问题一
首先要对比屏幕宽度和控件的设置宽度,然后才做判断
我们在构造方法中,获取屏幕宽度
//获取窗口管理器
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
//得到屏幕宽度
windowWidth = wm.getDefaultDisplay().getWidth();
做了如下修改:
/**
* onMeasure传入的两个参数是由上一层控件传入的大小,有多种情况,重写该方法时需要对计算控件的实际大小,
* 然后调用setMeasuredDimension(int, int)设置实际大小。
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取控件的宽度模式
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
//获取控件的宽度大小
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
//获取控件的高度模式
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
//获取控件的高度大小
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if(widthSize>windowWidth){//如果控件宽度大于屏幕宽度,则设置为屏幕宽度
widthSize=windowWidth;
}
setMeasuredDimension(widthSize, heightSize); //这里直接调用了父类的方法
}
修改之后的效果
针对问题二
文字过长,那么只能改变文字的大小以适应屏幕了
如何判断文字过长?如果过长,该缩小到多大合适呢?
修改如下:
//在绘制文字之前做判断
if(mBound.width()>windowWidth){
//计算文字大小并重新设置
mTextSize=mTextSize*windowWidth/mBound.width();
mPaint.setTextSize(mTextSize);
//设置左上角坐标为0
canvas.drawText(mText, 0, getHeight()
/ 2 + mBound.height() / 2, mPaint);
}else{
// 绘制文字,第2,3个参数是文字左上角的坐标,设置文字在控件中心,
canvas.drawText(mText, getWidth() / 2 - mBound.width() / 2, getHeight()
/ 2 + mBound.height() / 2, mPaint);
}
修改之后的效果
针对问题三
如果宽和高都是wrap_content,那么“第五个”是不会显示的,这里涉及到ScrollView的特殊情况
那么如何达到刚好包裹文字的效果呢,还是得重写onMeasure()方法
修改如下:
if(widthMode==MeasureSpec.EXACTLY){//Match_parent或者具体的数值100dp
if(widthSize>windowWidth){//如果控件宽度大于屏幕宽度,则设置为屏幕宽度
widthSize=windowWidth;
}
}else if(widthMode==MeasureSpec.AT_MOST){//wrap_content
widthSize=mBound.width();//设置为包裹文字的矩形的宽度
}
setMeasuredDimension(widthSize, heightSize);
修改之后的效果:
相信看到这里,各位同学对onMeasure()这个方法应该有些初步的了解了。