Androidカスタムコンポーネントには、一般に3つの実装方法があります:
1.組み合わせコントロール:名前が示すように、組み合わせコントロールはいくつかの小さなコントロールを組み合わせて新しいコントロールを形成します。これらの小さなコントロールのほとんどは組み込みのコントロールです。
2つ目は、自己描画コントロール:自己描画コントロールとは、ペイントとキャンバスで完全に描画されます。これは、onDraw()メソッドで描画し、onMeasure()メソッドで測定します。コンテナーがonLayout()メソッドに配置されている場合各サブコンポーネント。
3.継承されたコントロール:既存のコントロールを継承し、新しいコントロールを作成し、継承された親コントロールの特性を保持し、新しい特性を導入することを意味します。
自己描画コントロールには、カスタムコンポーネントとカスタムコンテナの 2つのタイプもあります。カスタムコンポーネントはViewクラスを継承し、カスタムコンテナがViewGrounpを継承する場合、今日、カスタムコンポーネントの主な分析は、より実用的な例を示すことです。最も単純なTextViewを描画するために最初に頭に浮かぶのは、canvas.drawText()メソッドです。さらに、ステップバイステップである必要があります:
(1))MyTextViewクラスを作成すると、Viewを継承し、3つの構築メソッドを書き換えます。もちろん、onDraw()メソッドとonMeasure()メソッドがあり、次のコードがあります。
public class MyTextView extends View{
/**
* 文本颜色
*/
private int textColor;
/**
* 字体大小
*/
private float textSize;
/**
* 文本
*/
private String text;
/**
* 绘制时控制
*/
private Paint mPaint;
private Rect mBoud;
public MyTextView(Context context) {
this(context, null);
}
public MyTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
(2)次に、これはTextViewであるため、text、color、textSizeなどの属性が必要であると考える必要があります。これらの属性を値ディレクトリのattrs.xmlで定義します。これにより、MyTextViewをxmlに導入してこれらの値を直接操作し、次のようにこれらの属性を3つのパラメーターを持つコンストラクションメソッドのコントロールに関連付けることができます。
attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyTextView">
<attr name="textColor" format="color|reference"/>
<attr name="textSize" format="dimension|reference"/>
<attr name="text" format="string|reference"/>
</declare-styleable>
</resources>
public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs,R.styleable.MyTextView, 0, 0);
textColor = typedArray.getColor(R.styleable.MyTextView_textColor, 0);
textSize = typedArray.getDimensionPixelSize(R.styleable.MyTextView_textSize, 0);
text = typedArray.getString(R.styleable.MyTextView_text);
typedArray.recycle();
}
(3)プロパティが定義されているので、ペイントブラシを使用してこれらのプロパティをConstructionメソッドで設定し、次にonDrawメソッドでキャンバスを使用してテキストビューを描画します。
public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyTextView, 0, 0);
textColor = typedArray.getColor(R.styleable.MyTextView_textColor, 0);
textSize = typedArray.getDimensionPixelSize(R.styleable.MyTextView_textSize, 0);
text = typedArray.getString(R.styleable.MyTextView_text);
typedArray.recycle();
mPaint = new Paint();
// 设置画笔为抗锯齿
mPaint.setAntiAlias(true);
mPaint.setColor(textColor);
mPaint.setTextSize(textSize);
//获取绘制文本的宽和高
mBoud = new Rect();
mPaint.getTextBounds(text, 0, text.length(), mBoud);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = measureWidth(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec);
setMeasuredDimension(width, height);
}
private int measureWidth(int widthMeasureSpec){
int mode = MeasureSpec.getMode(widthMeasureSpec);
int size = MeasureSpec.getSize(widthMeasureSpec);
int width = 0;
if(mode == MeasureSpec.EXACTLY){
//如果是math_parent或确定尺寸
width = size;
}else if(mode == MeasureSpec.AT_MOST){
//如果是wrap_parent
width = getPaddingLeft() + mBound.width() + getPaddingRight();
}
return width;
}
private int measureHeight(int heightMeasureSpec){
int mode = MeasureSpec.getMode(heightMeasureSpec);
int size = MeasureSpec.getSize(heightMeasureSpec);
int height = 0;
if(mode == MeasureSpec.EXACTLY){
//如果是math_parent或确定尺寸
height = size;
}else if(mode == MeasureSpec.AT_MOST){
//如果是wrap_parent
height = getPaddingTop() + mBound.height() + getPaddingBottom();
}
return height;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//canvas.drawText(text, x, y, paint); //第一个参数是文本,第四个参数是画笔,第二个参数x默认是字符串的左边在屏幕的位置, 第三个参数y是这个字符文本baseline基线在屏幕上的位置,不是这个字符的中心在屏幕的位置
Log.v("MyTextView", "getWidth:"+getWidth()/2);
Log.v("MyTextView", "mBoud.width:"+mBoud.width()/2);
Log.v("MyTextView", "getHeight"+getHeight()/2);
Log.v("MyTextView", "mBoud.height:"+mBoud.height()/2);
Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();
int baseline = (getMeasuredHeight() / 2) - ((fontMetrics.bottom + fontMetrics.top) / 2);
Log.v("MyTextView", "baseline:"+baseline);
Log.v("MyTextView", "getMeasuredHeight:"+getMeasuredHeight());
Log.v("MyTextView", "fontMetrics.top:"+fontMetrics.top);
Log.v("MyTextView", "fontMetrics.bottom:"+fontMetrics.bottom);
Log.v("MyTextView", "fontMetrics.ascent:"+fontMetrics.ascent);
Log.v("MyTextView", "fontMetrics.descent:"+fontMetrics.descent);
canvas.drawText(text, getWidth()/2 - mBoud.width()/2, baseline, mPaint);
}
onMeasureメソッドについて説明する
1.まず、コンポーネントの幅と高さを測定するとき、コンポーネントの親コンテナーによって呼び出されます。最初に、コンテナーはコンテナー内のすべての子コンポーネントをトラバースし、幅と高さを1つずつ測定します。ここで、カスタムtextViewの親コンテナーは最も外側のRelativeLayout
2.次に、MeasureSpecクラスを理解する必要があります。このクラスは、幅と高さの寸法とモードを取得するために、getMode(int measureSpec)とgetSize(int measureSpec)の2つのメソッドを提供します。このクラスは、 3つの定数は:MeasureSpec.EXACTLY、MeasureSpec.AT_MOSTは、MeasureSpec.UNSPECIFIED;
MeasureSpec.EXACTLY:一定サイズはTextViewに指定されているとき、またはmath_parent
MeasureSpec.AT_MOST:TextViewにはwrap_contentである場合
のTextViewに定義された幅と高さを有していない。MeasureSpec.UNSPECIFIED