您的位置:首页 > 移动开发 > Android开发

Android自定义View

2015-11-14 17:10 387 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/songlin0859/article/details/49836727

Android自定义View的步骤:

1、编写一个类(class)继承自View(貌似还可以继承自Drawable);

2、编写自定义属性文件(不是必须)

3、在类的构造方法中获取自定义的属性值(不是必须)

4、复写onMeasure方法测量自定义view的宽高、如果复写了就必须调用setMeasuredDimension方法设置自定义view的宽高(不是必须)

5、复习onDraw方法,绘制想要的界面/结果


1、编写一个类(class)继承自View

public class MyView extends View

2、编写自定义属性文件

在android工程res->values文件夹下建立attrs.xml文件

属性有下面这些类型:

<attr name="colorValue" format="color" />
<attr name="floatValue" format="float" />
<attr name="integerValue" format="integer" />
<attr name="booleanValue" format="boolean" />
<attr name="dimensionValue" format="dimension" />
<attr name="stringValue" format="string" />
<attr name="referenceValue" format="color|reference" />
<attr name="imageValue" format="reference"/>

<attr name="Visibility">
<enum name="invisible" value="0" />
<enum name="visible" value="1" />
<enum name="gone" value="2" />
</attr>
有颜色、浮点型、整型、布尔、尺寸(dp、sp)、字符串、引用、enum

定义的属性文件如下

<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--  <attr name="TextColor" format="color"/>
<attr name="float" format="color"/>
<attr name="int" format="integer"/>
<attr name="bool" format="boolean"/>
<attr name="dimens" format="dimension"/>
<attr name="text" format="string"/>
<attr name="background" format="color"/>
<attr name="image" format="reference"/>
<attr name="Visibility">
<enum name="VISIBLE" value="0" />
<enum name="INVISIBLE" value="1" />
<enum name="GONE" value="2" />
</attr> -->

<declare-styleable name="MyView">
<attr name="TextColor" format="color"/>
<attr name="f" format="float"/>
<attr name="i" format="integer"/>
<attr name="bool" format="boolean"/>
<attr name="dimens" format="dimension"/>
<attr name="text" format="string"/>
<attr name="background" format="color|reference"/>
<attr name="image" format="reference"/>
<attr name="Visibility">
<enum name="VISIBLE" value="0" />
<enum name="INVISIBLE" value="1" />
<enum name="GONE" value="2" />
</attr>
</declare-styleable>
</resources>

上面的定义和下面的定义的效果貌似是一样的

<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="TextColor" format="color"/>
<attr name="f" format="color"/>
<attr name="i" format="integer"/>
<attr name="bool" format="boolean"/>
<attr name="dimens" format="dimension"/>
<attr name="text" format="string"/>
<attr name="background" format="color"/>
<attr name="image" format="reference"/>
<attr name="Visibility">
<enum name="VISIBLE" value="0" />
<enum name="INVISIBLE" value="1" />
<enum name="GONE" value="2" />
</attr>

<declare-styleable name="MyView">
<attr name="TextColor"/>
<attr name="f"/>
<attr name="i"/>
<attr name="bool"/>
<attr name="dimens"/>
<attr name="text"/>
<attr name="background"/>
<attr name="image"/>
<attr name="Visibility"/>
</declare-styleable>
</resources>


3、在类的构造方法中获取自定义的属性值


自定义view中的field如下:

private Paint mPaint;
private float mTitleTextSize = 150.0f;
private Rect mBounds;
private int textcolor;
private float f;
private int integer;
private boolean b;
private int dimens;
private int background;
private Drawable backgroundDrawable;
private int visiblity;
private Drawable image;
private Bitmap bitmap;
private int drawablwID;
private String mTitle;

获取属性值


由一个特殊的

String attributeValue = attrs.getAttributeValue(null, "textsize");
if (attributeValue!=null) {
try {
mTitleTextSize=Integer.parseInt(attributeValue);
} catch (Exception e) {
}
}

TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyView, defStyleAttr, 0);
int n = a.getIndexCount();
for (int i = 0; i < n; i++)
{
int index = a.getIndex(i);
switch (index)
{
case R.styleable.MyView_TextColor:
textcolor = a.getColor(index,Color.BLACK);
break;
case R.styleable.MyView_f:
f = a.getFloat(index, 0.0f);
break;
case R.styleable.MyView_i:
integer = a.getInt(index, 0);
break;
case R.styleable.MyView_bool:
b = a.getBoolean(index, false);
break;
case R.styleable.MyView_dimens:
dimens = a.getDimensionPixelSize(index, 0);
break;
case R.styleable.MyView_text:
mTitle=a.getString(index);
break;
case R.styleable.MyView_background:
//            	try {
//					background = a.getColor(index,Color.BLACK);
//				} catch (Exception e) {
//					System.out.println("------getColor Exception-----");
//					backgroundDrawable=a.getDrawable(index);
//				}
backgroundDrawable=a.getDrawable(index);
break;
case R.styleable.MyView_image:
image = a.getDrawable(index);
break;
case R.styleable.MyView_Visibility:
visiblity = a.getInt(index, 0);
break;
}

}

最后打印输出一下各个数据

StringBuilder sb=new StringBuilder()
.append("textcolor="+textcolor)
.append("\nf="+f)
.append("\ninteger="+integer)
.append("\nb="+b)
.append("\ndimens="+dimens)
.append("\nmTitle="+mTitle)
.append("\nbackground="+background)
.append("\nbackgroundDrawable="+backgroundDrawable)
.append("\nimage="+image)
.append("\nvisiblity="+visiblity)
;
System.out.println(sb.toString());

注意:获取完属性后调用TypedArray 的recycle方法!!!!!!!!

a.recycle();

4、复写onMeasure方法测量自 3ff7 定义view的宽高

虽然这个方法不是必须复写的、但是不复写可能或显示不正常,比如wrap_content时是全屏等

代码如下,是会在一段文字,注释掉的部分是绘制图片时测试宽高的方法

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;
//width=bitmap.getWidth()+getPaddingLeft()+getPaddingRight();
}

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;
//height=bitmap.getHeight()+getPaddingTop()+getPaddingBottom();
}
<strong></strong><pre name="code" class="html">                setMeasuredDimension(width, height);


千万记住最后调用setMeasuredDimension(width, height);方式设置尺寸

5、复习onDraw方法,绘制想要的界面

注释掉部分为画图片的代码

FontMetrics fontMetrics = mPaint.getFontMetrics();
canvas.drawText(mTitle,
getWidth() / 2 - mBounds.width() / 2,
//getHeight() / 2 + mBounds.height() / 2,
//-fontMetrics.top,
getHeight()/2-(fontMetrics.ascent+fontMetrics.descent)/2,
mPaint);
System.out.println("----------------------------------");
System.out.println("getw="+getWidth()+",getH="+getHeight());
System.out.println("canvas.getw="+canvas.getWidth()+",canvas.geth="+canvas.getHeight());
System.out.println("mBounds.w="+mBounds.width()+",mBounds.h="+mBounds.height());
System.out.println("getpaddingl="+getPaddingLeft()+",getpaddingr="+getPaddingRight());

mPaint.setColor(Color.RED);
canvas.drawLine(0, getHeight()/2, getWidth(), getHeight()/2, mPaint);//画中心线看文字是否画得垂直居中
//		canvas.drawBitmap(bitmap,
//				getWidth()/2-bitmap.getWidth()/2,
//				getHeight()/2-bitmap.getHeight()/2,
//				mPaint);

6、定义好View后View的使用方法

6.1 在代码中使用的话、(应该在自定义view中实现相关属性field的get、set方法)直接new出实例后addView到ViewGroup中

6.2在布局文件中使用

<com.example.myview.MyView
android:id="@+id/myview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:padding="15dip"
csl:TextColor="#00f"
csl:f="123.0"
csl:i="36"
csl:bool="true"
csl:dimens="20dp"
csl:text="songlin_2015"
csl:background="#0f0"
csl:image="@drawable/ic_launcher"
csl:Visibility="GONE"
textsize="150"
/>


有问题请多多指教 代码下载


最后来一张效果图压压惊:

------end----- 关于测量文字和绘制文字单独记录一篇


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: