自定义初学4——自定义属性

不念不忘少年蓝@ 2021-09-22 04:56 660阅读 0赞

前面只是简单说了自定义View,接下来我们再来个增强版——自定义View的属性

1、自定义View的属性,首先在res/values/ 下建立一个attrs.xml , 在里面定义我们的属性。



















这里简单介绍一下控件的常用属性

format的取值及使用

  1. Reference:引用类型,参考某一资源ID

(1)属性定义:

  1. <declare-styleable name = "名称">
  2. <attr name = "background" format = "reference"/>
  3. <attr name = "src" format = "reference" />
  4. </declare-styleable>

(2)属性使用:

  1. <ImageView android:layout_width = "42dip"
  2. android:layout_height = "42dip"
  3. android:background = "@drawable/图片ID"/>
  1. color:颜色值。

(1)属性定义:

  1. <declare-styleable name = "名称">
  2. <attr name = "textColor" format = "color"/>
  3. </declare-styleable>

(2)属性使用:

  1. <TextView android:layout_width = "42dip"
  2. android:layout_height = "42dip"
  3. android:textColor = "#00FF00"/>
  1. boolean:布尔值。

(1)属性定义:

  1. <declare-styleable name = "名称">
  2. <attr name = "focusable" format = "boolean"/>
  3. </declare-styleable>

(2)属性使用:

  1. <Button android:layout_width = "42dip"
  2. android:layout_height = "42dip"
  3. android:focusable = "true"/>
  1. dimension:尺寸值。

(1)属性定义:

  1. <declare-styleable name = "名称">
  2. <attr name = "layout_width" format = "dimension"/>
  3. <attr name = "layout_height" format = "dimension"/>
  4. </declare-styleable>

(2)属性使用:

  1. <Button android:layout_width = "42dip"
  2. android:layout_height = "42dip"/>
  1. float:浮点值。

(1)属性定义:

  1. <declare-styleable name = "名称">
  2. <attr name = "fromAlpha" format = "float"/>
  3. <attr name = "toAlpha" format = "float"/>
  4. </declare-styleable>

(2)属性使用:

  1. <alpha android:fromAlpha = "1.0" android:toAlpha = "0.7"/>
  1. integer:整型值。

(1)属性定义:

  1. <declare-styleable name = "名称">
  2. <attr name = "visible"/>
  3. <attr name = "frameDuration" format="integer"/>
  4. <attr name = "framesCount" format="integer"/>
  5. <attr name = "pivotX"/><attr name = "pivotY"/>
  6. <attr name = "drawable"/>
  7. </declare-styleable>

(2)属性使用:

  1. <animated-rotate xmlns:android ="http://schemas.android.com/apk/res/android"
  2. android:drawable = "@drawable/图片ID"
  3. android:pivotX = "50%"
  4. android:pivotY = "50%"
  5. android:framesCount = "12"
  6. android:frameDuration = "100"/>
  1. string:字符串。

(1)属性定义:

  1. <declare-styleable name = "名称">
  2. <attr name = "text" format = "string" />
  3. </declare-styleable>

(2)属性使用:

  1. <TextView
  2. android:layout_width = "fill_parent"
  3. android:layout_height = "fill_parent"
  4. android:text ="0jOkQ80oD1JL9C6HAja99uGXCRiS2CGjKO_bc_g"/>
  1. fraction:百分数类型。

(1)属性定义:

  1. <declare-styleable name="名称">
  2. <attr name = "visible"/>
  3. <attr name = "fromDegrees" format = "float"/>
  4. <attr name = "toDegrees" format = "float"/>
  5. <attr name = "pivotX" format = "fraction"/>
  6. <attr name = "pivotY" format = "fraction"/>
  7. <attr name = "drawable"/>
  8. </declare-styleable>

(2)属性使用:

  1. <rotate xmlns:android ="http://schemas.android.com/apk/res/android"
  2. android:interpolator = "@anim/动画ID"
  3. android:fromDegrees = "0"
  4. android:toDegrees = "360"
  5. android:pivotX = "200%"
  6. android:pivotY = "300%"
  7. android:duration = "5000"
  8. android:repeatMode = "restart"
  9. android:repeatCount = "infinite"/>
  1. enum:枚举值。

(1)属性定义:

  1. <declare-styleable name="名称">
  2. <attr name="orientation">
  3. <enum name="horizontal" value="0"/>
  4. <enum name="vertical" value="1"/>
  5. </attr>
  6. </declare-styleable>

(2)属性使用:

  1. <LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
  2. android:orientation = "vertical"
  3. android:layout_width = "fill_parent"
  4. android:layout_height = "fill_parent">
  5. </LinearLayout>
  1. flag:位或运算。

(1)属性定义:

  1. <declare-styleable name="名称">
  2. <attr name="windowSoftInputMode">
  3. <flag name = "stateUnspecified" value = "0"/>
  4. <flag name = "stateUnchanged" value = "1"/>
  5. <flag name = "stateHidden" value = "2"/>
  6. <flag name = "stateAlwaysHidden" value = "3"/>
  7. <flag name = "stateVisible" value = "4"/>
  8. <flag name = "stateAlwaysVisible" value = "5"/>
  9. <flag name = "adjustUnspecified" value = "0x00"/>
  10. <flag name = "adjustResize" value = "0x10"/>
  11. <flag name = "adjustPan" value = "0x20"/>
  12. <flag name = "adjustNothing" value = "0x30"/>
  13. </attr></declare-styleable>

(2)属性使用:

  1. <activity android:name = ".StyleAndThemeActivity"
  2. android:label = "@string/app_name"
  3. android:windowSoftInputMode = "stateUnspecified | stateUnchanged | stateHidden">
  4. <intent-filter><action android:name = "android.intent.action.MAIN"/>
  5. <category android:name = "android.intent.category.LAUNCHER"/>
  6. </intent-filter></activity>

注意:

属性定义时可以指定多种类型值。

(1)属性定义:

  1. <declare-styleable name = "名称">
  2. <attr name = "background" format = "reference|color"/>
  3. </declare-styleable>

(2)属性使用:

  1. <ImageView android:layout_width = "42dip"
  2. android:layout_height = "42dip"
  3. android:background = "@drawable/图片ID|#00FF00"/>
  1. 多类型

2、在布局文件中声明我们的View

  1. <com.example.activity.view.CustomAttrView
  2. android:layout\_width="wrap\_content"
  3. android:layout\_height="wrap\_content"
  4. android:layout\_centerInParent="true"
  5. android:padding="10dp"
  6. custom:text="9958"
  7. custom:textColor="\#ff0000"
  8. custom:textSize="30sp" />

这里要强调的一点就是,一定要引入我们自己的名称空间(我绿色标注的部分),后面的包路径指的是项目的包名。

3、在View的构造方法中,获得我们的自定义的属性

public class CustomAttrView extends View {

  1. private String mStrText;
  2. private int mTextColor;
  3. private int mTextSize;
  4. /\*\*
  5. \* 绘制时控制文本绘制的范围
  6. \*/
  7. private Rect mBound;
  8. private Paint mPaint;
  9. public CustomAttrView(Context context) \{
  10. this(context, null);
  11. \}
  12. public CustomAttrView(Context context, AttributeSet attrs) \{
  13. this(context, attrs, 0);
  14. \}
  15. // 获得自定义的样式属性
  16. public CustomAttrView(Context context, AttributeSet attrs, int defStyle) \{
  17. super(context, attrs, defStyle);
  18. /\*\*
  19. \* 获得自定义样式属性
  20. \*/
  21. TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs,
  22. R.styleable.CustomAttrView, defStyle, 0);

// int n = typedArray.getIndexCount();

// for (int i = 0; i < n; i++) {

// int attr = typedArray.getIndex(i);

// switch (attr) {

// case R.styleable.CustomAttrView_text:

// mStrText = typedArray.getString(attr);

// break;

// case R.styleable.CustomAttrView_textColor:

// // 默认颜色设置为黑色

// mTextColor = typedArray.getColor(attr, Color.BLACK);

// break;

// case R.styleable.CustomAttrView_textSize:

// // 默认设置为16sp,TypeValue也可以把sp转化为px

// mTextSize = typedArray.getDimensionPixelSize(attr,

// (int) TypedValue.applyDimension(

// TypedValue.COMPLEX_UNIT_SP, 16, getResources()

// .getDisplayMetrics()));

// break;

//

// }

//

// }

  1. /\*\*
  2. \* 下面三句和上面注释掉的句子的作用一样
  3. \*/
  4. mStrText = typedArray.getString(R.styleable.CustomAttrView\_text);
  5. mTextColor = typedArray.getColor(R.styleable.CustomAttrView\_textColor, Color.BLACK);
  6. mTextSize = typedArray.getDimensionPixelSize(R.styleable.CustomAttrView\_textSize,16);
  7. typedArray.recycle();
  8. mPaint = new Paint();
  9. mPaint.setTextSize(mTextSize);
  10. mPaint.setColor(mTextColor);

/**

  1. \* 获得绘制文本的宽和高
  2. \*/
  3. mBound = new Rect();
  4. mPaint.getTextBounds(mStrText, 0, mStrText.length(), mBound);
  5. \}

}

4、重写onDraw,调用系统提供的onMesure方法

@Override

  1. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) \{
  2. super.onMeasure(widthMeasureSpec, heightMeasureSpec);

}

@Override

  1. protected void onDraw(Canvas canvas) \{
  2. mPaint.setColor(Color.BLUE);
  3. canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);
  4. mPaint.setColor(mTextColor);
  5. canvas.drawText(mStrText, getWidth() / 2 - mBound.width() / 2,
  6. getHeight() / 2 + mBound.height() / 2, mPaint);
  7. \}

此时效果如下:

Center

但是此时如果我们把布局文件的宽和高写成wrap_content,会发现效果和我们想的并不一样:

Center 1

这是因为系统帮我们测量的高度和宽度都是MATCH_PARNET,当我们设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结果,当我们设置为WRAP_CONTENT或者MATCH_PARENT系统帮我们测量的结果就是MATCH_PARENT的长度。

所以,当设置了WRAP_CONTENT时,我们需要自己进行测量,即重写onMesure方法,重写之前先了解下MeasureSpec的specMode的类型:

EXACTLY:一般是设置了明确的值或者是MATCH_PARENT

AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT

UNSPECIFIED:表示子布局想要多大就多大,很少使用

下面是我们重写onMeasure代码:

@Override

  1. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) \{
  2. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  3. int width = 0;
  4. int height = 0;
  5. /\*\*
  6. \* 设置宽度
  7. \*/
  8. int specMode = MeasureSpec.getMode(widthMeasureSpec);
  9. int specSize = MeasureSpec.getSize(widthMeasureSpec);
  10. switch (specMode) \{
  11. case MeasureSpec.EXACTLY:// 明确指定了
  12. width = getPaddingLeft() + getPaddingRight() + specSize;
  13. break;
  14. case MeasureSpec.AT\_MOST:// 一般为WARP\_CONTENT
  15. width = getPaddingLeft() + getPaddingRight() + mBound.width();
  16. break;
  17. \}
  18. /\*\*
  19. \* 设置高度
  20. \*/
  21. specMode = MeasureSpec.getMode(heightMeasureSpec);
  22. specSize = MeasureSpec.getSize(heightMeasureSpec);
  23. switch (specMode) \{
  24. case MeasureSpec.EXACTLY:// 明确指定了
  25. height = getPaddingTop() + getPaddingBottom() + specSize;
  26. break;
  27. case MeasureSpec.AT\_MOST:// 一般为WARP\_CONTENT
  28. height = getPaddingTop() + getPaddingBottom() + mBound.height();
  29. break;
  30. \}
  31. setMeasuredDimension(width, height);
  32. \}

现在我们可以对高度、宽度进行随便的设置了,基本可以满足我们的需求。

当然了我们这个自定义View与TextView相比还没什么区别,但是前面的例子已经提到,我们可以给View添加一些监听事件,代码就不写了,想看的话可以下载源码。

Center 2

源代码

参考:

http://blog.csdn.net/lmj623565791/article/details/24252901

http://www.jb51.net/article/32172.htm

http://blog.csdn.net/u013045971/article/details/42299533

http://blog.csdn.net/aigestudio/article/details/41212583

发表评论

表情:
评论列表 (有 0 条评论,660人围观)

还没有评论,来说两句吧...

相关阅读

    相关 data-* 定义属性

    之前没有关于自定义属性的规范,所以管理起来比较混乱。 HTML5增加data-*用于设置自定义属性,可以用来存储数据,也可以称之为数据属性。 同时,JavaScript提...