/*这个demo演示了如何使用自定义的View。在本例中自定义了一个LableView,并且自定义了
* text、textColor、textSize三个自定义的属性*/
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
在resource/values目录下新建attrs.xml创建自定义属性:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="LabelView">
<attr name="text" format="string"/>
<attr name="textColor" format="color"/>
<attr name="textSize" format="dimension"/>
</declare-styleable>
</resources>
创建自定义视图LabelView
public class LabelView extends View {
private Paint mTextPaint;
// 需要绘制的文本
private String mText;
// 文本的基准线至最高点的距离
private int mAscent;
public LabelView(Context context) {
super(context);
initLabelView();
}
// 重写该方法是为了在layout中使用自定义的属性
public LabelView(Context context, AttributeSet attrs) {
super(context, attrs);
initLabelView();
// 获取到自定义的属性集合
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.LabelView);
// 获取text属性的值
CharSequence s = a.getString(R.styleable.LabelView_text);
if (s != null) {
setText(s.toString());
}
setTextColor(a.getColor(R.styleable.LabelView_textColor, 0xff000000));
int textSize = a.getDimensionPixelOffset(
R.styleable.LabelView_textSize, 0);
if (textSize > 0) {
setTextSize(textSize);
}
// 注意用完之后一定要回收属性集合
a.recycle();
}
private void setTextSize(int textSize) {
mTextPaint.setTextSize(textSize);
requestLayout();
invalidate();
}
private void setTextColor(int color) {
mTextPaint.setColor(color);
invalidate();
}
private void setText(String text) {
mText = text;
// view显示的文本发生变化,需要重新绘制,并改变layout的布局
requestLayout();
invalidate();
}
private void initLabelView() {
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
// 将大小转化为适合当前屏幕的尺寸
mTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
mTextPaint.setColor(Color.BLACK);
setPadding(3, 3, 3, 3);
}
/*
* widthMeasureSpec是由父窗体传入的根据父窗体的布局、边距等属性计算出的子View的大小。
* 该值由高32位和低16位组成,高32位用来表示specMode:共有三个值:MeasureSpec.EXACTLY、
* MeasureSpec.AT_MOST、MeasureSpec.UNSPECIFIED
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec),
measureHeight(heightMeasureSpec));
}
private int measureHeight(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
mAscent=(int) mTextPaint.ascent();
System.out.println("ascent:"+mAscent);
//父视图希望子视图的大小应该是specSize中指定的。
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
result = (int) (-mAscent+mTextPaint.descent() + getPaddingBottom() + getPaddingTop());
if(specMode==MeasureSpec.AT_MOST){
result=Math.min(result, specSize);
}
}
return result;
}
private int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
result = (int) (mTextPaint.measureText(mText) + getPaddingLeft() + getPaddingRight());
if(specMode==MeasureSpec.AT_MOST){
result=Math.min(result, specSize);
}
}
return result;
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawText(mText, getPaddingLeft(), getPaddingTop()-mAscent, mTextPaint);
}
}
在布局文件中应用自定义视图
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:lab="http://schemas.android.com/apk/res/com.fishtosky.customview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.fishtosky.customview.LabelView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffff0000"
lab:text="Red" />
<com.fishtosky.customview.LabelView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ff0000ff"
lab:text="Blue"
lab:textSize="20sp"/>
<com.fishtosky.customview.LabelView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ff00ff00"
lab:text="Green"
lab:textColor="#ffffffff" />
</LinearLayout>