
首先看UI给的图形,那个红点,最蠢的方法就是我们写一个TextView在设置一个android:drawablePadding="",但是这样写很不友好,要切图,但是*的话我们直接也可以输入法敲出来,所以还是自定义,以后不管这个点在哪里,我们直接可以用了
第一步:设置属性
在values的文件夹下的attrs.xml中设置属性

<declare-styleable name="RequiredTextView">
<attr name="android:text" />
<attr name="prefix" format="string|reference" />
<attr name="prefix_color" format="integer|reference" />
</declare-styleable>
顺便讲一下属性的意义:
- reference 参考某一资源ID
<declare-styleable name="名称">
<attr name = "background" format="reference" />
</declare-styleable>
<ImageView
android:layout_width = "42dp"
android:layout_height = "42dp"
android:background = "@drawable/图片ID" />
- color:颜色值
<declare-styleable name="名称">
<attr name = "textColor" format="color" />
</declare-styleable>
<TextView
android:layout_width = "42dp"
android:layout_height = "42dp"
android:textColor = "#ABABAB" />
- boolean:布尔值
<declare-styleable name="名称">
<attr name = "focusable" format="boolean" />
</declare-styleable>
<TextView
android:layout_width = "42dp"
android:layout_height = "42dp"
android:focusable = "true" />
- string:字符串
<declare-styleable name = "MapView">
<attr name = "apiKey" format = "string" />
</declare-styleable>
<com.google.android.maps.MapView
android:layout_width = "fill_parent"
android:layout_height = "fill_parent"
android:apiKey = "0jOkQ80oD1JL9C6HAja99uGXCRiS2CGjKO_bc_g" />
属性定义时可以指定多种类型值。
<declare-styleable name = "名称">
<attr name = "background" format = "reference|color" />
</declare-styleable>
<ImageView
android:layout_width = "42dip"
android:layout_height = "42dip"
android:background = "@drawable/图片ID|#00FF00" />
基本上我们就先介绍常用的这几个
第二步:自定义TextView
public class RequiredTextView extends android.support.v7.widget.AppCompatTextView {
private String prefix = "*";
private int prefixColor = Color.RED;
public RequiredTextView(Context context) {
super(context);
}
public RequiredTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public RequiredTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
/**
* @param context
* @param attrs 获取属性的集合
* SPAN_EXCLUSIVE_INCLUSIVE 不包前包后
*/
private void init(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RequiredTextView);
prefixColor = typedArray.getInteger(R.styleable.RequiredTextView_prefix_color, Color.RED);
String text = typedArray.getString(R.styleable.RequiredTextView_android_text);
prefix = typedArray.getString(R.styleable.RequiredTextView_prefix);
if (TextUtils.isEmpty(prefix)) prefix = "*";
if (TextUtils.isEmpty(text)) text = "";
typedArray.recycle();
setText(text+prefix);
}
public void setText(String texts) {
SpannableString spannableString = new SpannableString(texts);
spannableString.setSpan(new ForegroundColorSpan(prefixColor), texts.length()-1,texts.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
setText(spannableString);
}
}
android开发者网站上有相关的说明文档:
public View (Context context)是在java代码创建视图的时候被调用,如果是从xml填充的视图,就不会调用这个
public View (Context context, AttributeSet attrs)这个是在xml创建但是没有指定style的时候被调用
public View (Context context, AttributeSet attrs, int defStyle)给View提供一个基本的style,如果我们没有对View设置某些属性,就使用这个style中的属性。

- set
set:表示从layout文件中直接为这个View添加的属性的集合,如:android:layout_width="match_parent"。注意,这里面的属性必然是通过xml配置添加的,也就是由LayoutInflater加载进来的布局或者View`才有这个属性集。
现在你知道为啥我们在自己定义View的时候至少要重写(Context context, AttributeSet set)构造器了吧?因为不重写时,我们将无法获取到layout中配置的属性!!当然,也因为这样,LayoutInflater在inflater布局时会通过反射去调用View的(Context context, AttributeSet attrs)构造器。
set 中实际上又有两种数据来源,当然最后都会包含在set中。一种是直接使用android:layout_width="wrap_content"这种直接指定的,还有一种是通过style="@style/somestyle"这样指定的。
- attrs
attrs:int[],每个方法中都有的参数,就是告诉系统需要获取那些属性的值。 - defStyleAttr
也是自定义一个可以在Theme中配置的样式的关键,先看个栗子吧:
如果我想通过在系统主题里面设置一个样式,修改所有textview的样式,你一般会这么做:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
//在主题中设置textview的style
<item name="android:textViewStyle">@style/textviewstyle</item>
</style>
<style name="textviewstyle" parent="android:style/Widget.TextView">
<!--指定一些属性-->
</style>
public TextView(Context context, AttributeSet attrs) {
//指定属性textViewStyle为defStyleAttr,然后系统会去搜索Theme中你为这个
//属性配置的style
this(context, attrs, com.android.internal.R.attr.textViewStyle);
}
- TypedArray
我们看到在获取到属性值之后,都会返回一个TypedArray对象,它又是什么鬼?TypedArray主要有两个作用,第一是内部去转换attrid和属性值数组的关系;第二是提供了一些类型的自动转化,比如我们getString时,如果你是通过@string/hello这种方式设置的,TypedArray会自动去将ResId对应的string从资源文件中读出来。说到底,都是为了方便我们获取属性参数。
网友评论