命名空間(namespace)
XML 命名空間提供避免元素命名沖突的方法。
舉個例子,A學校有名學生叫做林小明,B學校也有名學生叫林小明,那我們如何識別這兩名擁有相同名字的同學呢?這時候命名空間就派上用場了。A和B此時就可以被當成是命名空間了。也就是說,命名空間里面存放的是特定屬性的集合。
Android中常見的命名空間
下面分別介紹android、tools、app(自定義命名空間)這幾個常見的命名空間
1、android
xmlns:android=”http://schemas.android.com/apk/res/android”
在Android布局文件中我們都必須在根元素上定義這樣一個命名空間,接下來對這行代碼進行逐一講解:
xmlns:即xml namespace,聲明我們要開始定義一個命名空間了
android:稱作namespace-prefix,它是命名空間的名字
http://schemas.android.com/apk/res/android:這看起來是一個URL,但是這個地址是不可訪問的。實際上這是一個URI(統一資源標識符),所以它的值是固定不變的,相當於一個常量)。
有了他,就會提示你輸入什么,也可以理解為語法文件。
使用這行代碼,我們就可以引用命名空間中的屬性,如:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="New Text"
android:id="@+id/textView" />
</LinearLayout>
在這個布局中,只要以android:開頭的屬性便是引用了命名空間中的屬性。
android是賦予命名空間一個名字,就跟我們平時在定義變量一樣,比如我把它取成myns,那么上面的代碼我們也可以寫成:
<LinearLayout xmlns:myns="http://schemas.android.com/apk/res/android"
myns:layout_width="match_parent"
myns:layout_height="match_parent" >
<TextView
myns:layout_width="wrap_content"
myns:layout_height="wrap_content"
myns:layout_gravity="center"
myns:text="New Text"
myns:id="@+id/textView" />
</LinearLayout>
2、tools
xmlns:tools=”http://schemas.android.com/tools”
接下來會介紹,關於tools的三種使用方法吧,也算是他的特性。
2.1、tools只作用於開發階段
我們可以把他理解為一個工具(tools)的命名空間,它的只作用於開發階段,當app被打包時,所有關於tools屬性將都會被摒棄掉。
例如,基本上在android命名空間內的屬性,我們想在編寫代碼階段測試某個組件在屏幕上的效果,而當app安裝到手機上時,摒棄掉這條代碼,那么我們就可以用tools命名空間來代替掉android:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
tools:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello,World"/>
</LinearLayout>
以上是在layout中的布局,當我們切換到視圖窗口(Design)中查看時,看到的是標簽頂部居中顯示(左圖),然后,當我們運行到手機上時,確是這樣的:
如上所示,tools:layoutgravity= “center”確實在運行后背拋棄掉了!
2.2、tools:context開發中查看Activity布局效果
context的用法,在后面跟一個Activtiy的完整包名,它有什么作用呢?
當我們設置一個Activity主題時,是在AndroidManifest.xml中設置中,而主題的效果又只能在運行后在Activtiy中顯示
使用context屬性, 可以在開發階段中看到設置在Activity中的主題效果
tools:context=”com.littlehan.myapplication.MainActivity”
在布局中加入這行代碼,就可以在design視圖中看到與MainActivity綁定主題的效果。
2.3、tools:layout開發中查看fragment布局效果
當我們在Activity上加載一個fragment時,是需要在運行后才可以看到加載后的效果,有沒有方法在測試階段就在布局預覽窗口上顯示呢?
答案是有的,借助layout屬性,例如,在布局中加入這樣一行代碼:
tools:layout=@layout/yourfragmentlayoutname
這樣你的編寫的fragment布局就會預覽在指定主布局上了
3、自定義命名空間
如果使用DataBinding 會在xml用到 app屬性,其實這是個自定義命名空間。
xmlns:app=”http://schemas.android.com/apk/res-auto”
讀者可能會問了,這里哪里體現出是自定義的??
實際上也可以這么寫:
xmlns:app=”http://schemas.android.com/apk/res/完整的包名”
在res/后面填寫包名即可。但是,在Android Studio2.0上,是不推薦這么寫的,所以建議大家還是用第一種的命名方法。
通常自定義命名空間往往是和自定義View分不開的,當Android自帶的控件不能滿足需求時,可以自己去繪制一些View,而要為自定義View加上自定義的屬性時,就需要創建自定義命名空間。
命名空間里面存放的是特定屬性的集合,這樣一來,思路就很清晰,也就是說自定義命名空間的實際過程就是自定義屬性。
我們通過一個簡單的自定義TextView來學習下自定義命名空間是怎么一回事,自定義View的過程可以分成以下幾個步驟:
3.1、繼承View類
創建一個類名為CustomTextView繼承View(View是所有視圖的父類)並實現它三個構造方法
public class CustomTextView extends View {
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//畫筆
public CustomTextView(Context context) {
super(context);
}
public CustomTextView(Context context, AttributeSet attrs){
this(context, attrs, 0);//注意不是super(context,attrs,0);
}
public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr){
super(context,attrs,defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawText("I am a CustomTextView",100, 100, mPaint);
}
}
3.2、 使用自定義布局
將自定義的控件引入布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
>
<com.littlehan.customtextview.CustomTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
到了這里,一個自定義的控件就被引入布局使用了,我們可以切換到視圖窗口看看效果:
但是這個自定義控件,並不能在xml中去改變字體顏色,字體大小、自定義文本等。這個功能的實現,需要XML創建自定義屬性和在自定義View中解析屬性
3.3、自定義屬性
在values根目錄下新建一個名為attrs的xml文件來自定義屬性(自定義的屬性便是自定義命名空間里面的屬性)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomTextView">
<attr name="customColor" format="color"/>
<attr name="customText" format="string"/>
</declare-styleable>
</resources>
name定義的是屬性的名字
format定義的是屬性的類型
自定義屬性也可以不使用declare-styleable,參考這里
3.4、解析屬性
在CustomeTextView中解析這些屬性
public class CustomTextView extends View {
private int mColor = Color.RED;//默認為紅色
private String mText="I am a Custom TextView";//默認顯示該文本
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//畫筆
public CustomTextView(Context context) {
super(context);
// init();
}
public CustomTextView(Context context, AttributeSet attrs){
this(context, attrs, 0);//注意不是super(context,attrs,0);
init();
}
public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr){//解析自定義屬性
super(context,attrs,defStyleAttr);
TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.CustomTextView);
mColor = typedArray.getColor(R.styleable.CustomTextView_customColor, Color.RED);
// 如果沒有判斷,當沒有指定該屬性而去加載該屬性app便會崩潰掉
if(typedArray.getText(R.styleable.CustomTextView_customText) != null ){
mText = typedArray.getText(R.styleable.CustomTextView_customText).toString();
}
typedArray.recycle();//釋放資源
init();
}
private void init(){
mPaint.setColor(mColor);// 為畫筆添加顏色
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawText(mText, 100, 100, mPaint);
}
}
3.5、使用自定義屬性
要使用自定義屬性,就需要自定義屬性命名空間,在布局文件的根元素下插入這樣一行代碼:
xmlns:app=”http://schemas.android.com/apk/res-auto”
於是就可以使用自定義屬性了:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
>
<com.littlehan.customtextview.CustomTextView
app:customColor="@color/colorAccent"
app:customText="Test Message"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
切換到視圖預覽窗口,可以看到自定義的屬性已經生效了:
總結
在Android中,命名空間可分為3種:
- xmlns:android=”http://schemas.android.com/apk/res/android”
- xmlns:tools=”http://schemas.android.com/tools”
- xmlns:app=”http://schemas.android.com/apk/res-auto”
其中,1和2命名空間里的屬性是系統封裝好的,第3種命名空間里的屬性是用戶自定義的。