前言:在开发过程中我们会经常遇到修改控件属性以及窗口属性的问题,现在就来分析下这些属性;
1.先从一个xml布局开始:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
这是一个很简单的布局,我们来逐步分析:
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns的全名是xml namespace,有点像C++中的namespace,它的作用是引入"android"这个概念,以便于后面的android:layout_width可以正常使用,如果没有声明"android"这个概念,android:layout_width是个错误的写法;
"http://schemas.android.com/apk/res/android"中最后面的一个字段"android",指的是包名,这个"android"是在manifest.xml中被声明的;
所以上面xml布局中代码的含义就是:
声明android引用,并给android引用赋予一个地址,接下来就可以使用android中的内容了;
再来举个项目中的例子:
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.gome"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.gome.internal.menu.FloatActionMenuView
android:id="@+id/floatMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="10dp"
app:maxItems="3"
app:menu="@menu/panel_edit_menu" />
</FrameLayout>
可以看到: xmlns:app="http://schemas.android.com/apk/res/com.gome";
这就表示了,app指向了com.gome这个包名,看看这个com.gome是在哪定义的?
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gome"
coreApp="true"
android:sharedUserId="android.uid.system"
android:sharedUserLabel="@null">
</manifest>
com.gome是应用程序包名;
既然已经声明了app,接下来就可以使用它的内容了:
app:maxItems="3"
app:menu="@menu/panel_edit_menu"
注意:Manifest.xml中的"com.gome"与布局xml不在同一个进程里面,即"com.gome"是另一个应用,如果"com.gome"在布局xml的进程里面,还可以这样定义app:
xmlns:app="http://schemas.android.com/apk/res/res-auto";
表示在该程序包名的目录下自动查找路径;
2.上面介绍了怎么样使用app,但是没有解释app:maxItems="3"是怎么来的?接下来就详解下自定义属性:
我们以一个TextView为例:
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/msg_scroll_sreenshot_stop_hint"
android:textColor="#ffffffff"
android:textSize="13sp" />
可以看到TextView中有text,textColor,textSize这三个属性,而且,这三个属性的所对应的值的类型也是不同的,textColor对应的是"#ffffffff",textSize对应的是"13sp",这是怎么回事?
TextView其实就是一个标签,既然是标签,那就肯定有定义标签的地方,TextView标签的定义在frameworks\base\core\res\res\values\attrs.xml中的;
<declare-styleable name="TextView">
<attr name="bufferType">
<enum name="normal" value="0" />
<enum name="editable" value="2" />
</attr>
<attr name="hint" format="string" />
<attr name="textSize" />
<attr name="textScaleX" format="float" />
<attr name="cursorVisible" format="boolean" />
<attr name="lines" format="integer" />
<attr name="height" format="dimension" />
<flag name="integer" value="0x01" />
<flag name="signed" value="0x03" />
<flag name="decimal" value="0x05" />
</attr>
<attr name="drawableTop" format="reference|color" />
<attr name="drawableTint" format="color" />
............
</declare-styleable>
TextView中的attr代表着TextView标签中的属性,属性后面的format指的是该属性可以被赋予哪些类型的值,不同的属性可以被赋予的值的类型也就不同,接下来详细分析下这些属性:
①<attr name="hint" format="string" />
表示值的类型是字符串类型;
如:<TextView android:text = "我是文本"/>
②<attr name="textScaleX" format="float" />
表示值的类型是float类型;
如:<TextView android:textScaleX = "1.0"/>
③<attr name="cursorVisible" format="boolean" />
表示值的类型是boolean类型;
如:<TextView android:cursorVisible= "false"/>
④<attr name="drawableTop" format="reference|color" />
表示值的类型既可以是引用类型也可以是color类型;
如:<TextView android:drawableTop= "@drawable/图片ID"/>
<TextView android:drawableTop= "#ffff0000"/>
⑤<attr name="height" format="dimension" />
表示值的类型是尺寸类型;
如:<TextView android:layout_height= "42dp"/>
⑥<attr name="bufferType">
<enum name="normal" value="0" />
<enum name="editable" value="2" />
</attr>
表示值的类型是枚举类型;
如:<TextView android:bufferType= "normal"/>
⑦<attr name="height" format="dimension" />
<flag name="integer" value="0x01" />
<flag name="signed" value="0x03" />
<flag name="decimal" value="0x05" />
</attr>
表示值的类型是位或运算类型;
如:<TextView android:height= "integer|signed"/>
看完了这些,大家知道textview属性的赋值含义了吧;
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/msg_scroll_sreenshot_stop_hint"
android:textColor="#ffffffff"
android:textSize="13sp" />
注意:
①我们看到在Textview的标签声明中,并没有layout_width属性,为啥在TextView中可以使用这些属性?
因为TxetView是继承自View这个类的,View类的所拥有的属性TextView全部拥有,layout_width属性被定义在View中,可以Textview可以直接使用;
②在TextView标签中,我们看到textSize属性并没有被指明要赋哪种类型的值:
<attr name="textSize" />;
format是限定当前定义的属性能接受什么值,如果不带format的就是在使用已有的属性;
3.根据上面的介绍,接下来我们自定义一个属性:
①首先在attrs文件中添加我们的自定义属性:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyTextView2">
<attr name="myText" format="string"/>
<attr name="myTextColor" format="color"/>
<attr name="myTextSize" format="dimension"/>
</declare-styleable>
</resources>
②在布局文件中使用该属性:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:myview="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.qianmo.activitydetail.MyTextView2
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00ff00"
myview:myText=" I Love You ......I Love You ......"
myview:myTextColor="#ff3399"
myview:myTextSize="25sp"/>
</LinearLayout>
③在构造方法中获取我们的自定义属性
public MyTextView2(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
/**
* 初始化数据
*/
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
//获取自定义属性的值
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyTextView2, defStyleAttr, 0);
mText = a.getString(R.styleable.MyTextView2_myText);
mTextColor = a.getColor(R.styleable.MyTextView2_myTextColor, Color.BLACK);
mTextSize = a.getDimension(R.styleable.MyTextView2_myTextSize, 30f);
a.recycle();
//初始化Paint数据
mPaint = new Paint();
mPaint.setColor(mTextColor);
mPaint.setTextSize(mTextSize);
//获取绘制的宽高
mBound = new Rect();
mPaint.getTextBounds(mText, 0, mText.length(), mBound);
Log.i(TAG, "mText :" + mText + ",mTextColor:" + mTextColor+ ",mTextSize:" + mTextSize);
}
4.属性使用时的常见问题解析
①<style name="MusicTheme" parent="@com.gome:style/Theme.GOME.Light">
这个@com.gome:style/Theme.GOME.Light是啥意思?
这句代码和下面这句代码有点雷同:android:id="@android:id/tabhost";
"@"表示引用;
"android:id"表示是android包下面的id属性;
"tabhost"表示id的名字叫做tabhost;
所以,"@com.gome:style/Theme.GOME.Light"的意思就是:引用"com.gome"包下的名为"Theme.GOME.Light"的"style"属性;
②android:textAppearance="?android:attr/textAppearanceSmall"
这个怎么解释?开始分析:
"textAppearanceSmall",是"Theme"标签的属性:
<declare-styleable name="Theme">
<attr name="textAppearanceSmall" format="reference" />
</declare-styleable>
所以"android:attr/textAppearanceSmall"可以简单理解为:android包下的Theme标签的textAppearanceSmall属性;
那"?"是意思呢?--> "?"表示系统是否给Theme标签的textAppearanceSmall属性设置了值,如果系统给它设置了值,那我们就引用这个textAppearanceSmall,如果没有,那就使用默认的值;
我们知道,不同的风格,就有不同的Theme,不同的Theme就有不同的textAppearanceSmall,比如:
<style name="Theme.Material">
<item name="textAppearanceSmall">@style/TextAppearance.Material.Small</item>
</style>
<style name="Theme.Material.Light" parent="Theme.Light">
<item name="textAppearanceSmall">@style/TextAppearance.Material.Small</item>
</style>
<style name="Theme.Holo">
<item name="textAppearanceSmall">@style/TextAppearance.Holo.Small</item>
</style>
所以:"?android:attr/textAppearanceSmall"就是引用相应Theme风格下的textAppearanceSmall属性;
③"?"和"@"有什么区别?
这个问题是接着上面那两个问题的,何时用"@........",何时用"?.........";
@是引用的意思,@......表示引用一个确定的值,如引用一个drawable,引用一个style,drawable和style都是有明确的唯一的值,如:
<style name="Theme.Material">
<item name="textAppearanceSmall">@style/TextAppearance.Material.Small</item>
</style>
Theme.Material有确定的唯一的值;
?也可以理解为引用,但它引用的是一个属性,这个属性被定义在Theme标签中,在theme.xml中会给不同Theme的该属性指定不同的值,这个从案例②中就可以看到;所以?......就是指定该Theme中的这个属性所对应的值;