日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

android view使用方法,Android View构造方法第三参数使用方法详解

發布時間:2025/3/20 Android 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android view使用方法,Android View构造方法第三参数使用方法详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

我們都知道,在Android中要使用一個View,一般會有兩種方式:

在XML文件中配置;

直接在代碼中new一個View的對象。

我們今天討論的內容就是圍繞著View的構造方法的。

1、實例

首先我們先來看一個例子。

新建一個工程,layout文件如下:

android:id="@+id/layout"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical" >

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="(Context, AttributeSet)" />

Activity:

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.three_button_layout);

Button btn1 = new Button(this);

btn1.setText("(Context)");

Button btn2 = new Button(this, null, 0);

btn2.setText("(Context, AttributeSet, int)");

LinearLayout layout = (LinearLayout) findViewById(R.id.layout);

layout.addView(btn1);

layout.addView(btn2);

}

在layout文件中有一個Button,然后在代碼中new了兩個Button,并且添加到layout文件中,顯示結果如下:

Demo截圖顯示

很顯然,前面兩個Button樣式是一樣的,并且默認可以點擊,第3個Button就有點奇怪了,而且還無法點擊。為什么會出現這種現象呢?這就是這篇文章要說明的問題了。

View的構造函數

要想理解上面的問題,我們必須先得了解View的構造函數。默認情況下,View有3個構造函數,函數原型如下:

/**

* 在Code中實例化一個View就會調用這個構造函數

* Simple constructor to use when creating a view from code.

*

* @param context The Context the view is running in, through which it can

* access the current theme, resources, etc.

*/

public View(Context context);

/**

* 在xml中定義會調用這個構造函數

* Constructor that is called when inflating a view from XML. This is called

* when a view is being constructed from an XML file

*/

public View(Context context, AttributeSet attrs);

public View(Context context, AttributeSet attrs, int defStyle);

如果要在代碼中new一個View對象,我們一般會使用第一個構造函數。

如果是在XML文件中聲明的View,系統會默認調用第二個構造函數。

而對于第三個構造函數,我們在自己的代碼中一般都沒有去調用它。

在上面的例子中,btn2這個Button正是采用的第三種構造方法創建出來的,結果導致了很奇怪的結果。既然是用Button做的例子,我們來看下Button的源碼(Button的源碼可以說是所有Android自帶控件中最簡單的了吧):

public class Button extends TextView {

public Button(Context context) {

this(context, null);

}

public Button(Context context, AttributeSet attrs) {

this(context, attrs, com.android.internal.R.attr.buttonStyle);

}

public Button(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

}

}

我們可以看到,整個類中僅僅只有3個構造方法,但是它繼承自TextView,所以它的各種方法都是在TextView中實現的。然而,我們平時看到的TextView和Button還是有很多地方不同的,那是什么地方導致的這些差異呢?

顯然,除了第二個構造方法中的com.android.internal.R.attr.buttonStyle,不可能有其他地方來區分TextView和Button了。而這里第二個構造方法調用了第三個構造方法,第三個構造比第二個構造方法多了一個int類型的參數。這就是關鍵所在了。

View構造方法中的第三個參數。

我們來看一下第三個構造方法的官方文檔注釋:

Perform inflation from XML and apply a class-specific base style. This constructor of View allows subclasses to use their own base style when they are inflating. For example, a Button class's constructor would call this version of the super class constructor and supply R.attr.buttonStyle for defStyle; this allows the theme's button style to modify all of the base view attributes (in particular its background) as well as the Button class's attributes.

對第三個參數的解釋是:

An attribute in the current theme that contains a reference to a style resource to apply to this view. If 0, no default style will be applied.

它的大概意思就是,給View提供一個基本的style,如果我們沒有對View設置某些屬性,就使用這個style中的屬性。

繼續用Button來分析。

通過Button第3個構造方法的調用,我們來到TextView的構造方法中,當中有一句關鍵代碼:

TypedArray a = context.obtainStyledAttributes(

attrs, com.android.internal.R.styleable.TextView, defStyle, 0);

接下來,我們分析一下obtainStyledAttributes方法。

obtainStyledAttributes

跟蹤該方法,發現最終調用的是Resources.Theme類中的obtainStyledAttributes()方法,該方法里面主要是通過調用一個native方法來拿到控件的屬性,放到TypedArray中。

public TypedArray obtainStyledAttributes(AttributeSet set,

@StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {

return mThemeImpl.obtainStyledAttributes(this, set, attrs, defStyleAttr, defStyleRes);

}

我們來仔細閱讀一下obtainStyledAttributes()方法的官方文檔

obtainStyledAttributes()方法的官方文檔

set:在XML中明確寫出了的屬性集合。(比如android:layout_width、android:text="@string/hello_world"這些)

attrs:需要在上面的set集合中查詢哪些內容。如果是自定義View,一般會把自定義的屬性寫在declare-styleable中,代表我們想查詢這些自定義的屬性值。

defStyleAttr:這是一個定義在attrs.xml文件中的attribute。這個值起作用需要兩個條件:1. 值不為0;2. 在Theme中使用了(出現即可)。

defStyleRes:這是在styles.xml文件中定義的一個style。只有當defStyleAttr沒有起作用,才會使用到這個值。

這還是一個比較模糊的概念,我們來看看系統里面是怎么使用這些值的。

首先找到frameworks\base\core\res\res\values目錄下的attrs.xml、styles.xml、themes.xml三個文件,打開。

既然Button的構造方法中使用到了com.android.internal.R.attr.buttonStyle,我們就來看看這個attr。該attr位于attrs.xml中:

只是簡單的定義了一個attr。

然后在哪里用到了它呢?看到themes.xml文件下,有這樣一個style:

...

@android:style/Widget.Button

...

在這里用到了buttonStyle屬性,它指向另外一個style,這個style在styles.xml文件下:

@android:drawable/btn_default

true

true

?android:attr/textAppearanceSmallInverse

@android:color/primary_text_light

center_vertical|center_horizontal

我們可以看到,這里面的屬性都是用來配置Button的。如果在XML文件中沒有給Button配置背景、內容的位置等屬性,就會默認使用這里的屬性。當然這是在使用了defStyleAttr的情況才會出現的,這也解釋了文章開頭的例子中的奇怪現象了。

千萬不要以為這樣就萬事大吉了,現在我們只是定義好了這些屬性,并沒有使用到它。那在哪里使用到的呢?注意上面的themes.xml中的那個style的名稱為Theme,而在我們自己的工程中,在配置menifest文件的時候,給application或者activity設置的主題android:theme一般都是這個style的子類,所以也就這樣使用到了defStyleAttr定義的屬性了。至于是如何拿到這些屬性的,我想是在obtainStyledAttributes()方法中處理的,這里不需要過多追究。

還有一個defStyleRes參數,我們可以發現在TextView、ImageView等控件中,這個值傳的都是0,也就是不使用它。它的作用就像是一個替補,當defStyleAttr不起作用的時候它就上場,因為它也是一個style,這個參數是怎么起作用的在下面的實例中有提到。

實例

上面的都是理論,我們接下來用一個例子來實踐一下。

首先創建一個attrs.xml文件:(如果還不會自定義View屬性的,請參考

注意,這里即使將customViewStyle屬性寫在declare-styleable里,最終效果也一樣。

定義style。

首先定義我們的defStyleAttr屬性(在本項目中是customViewStyle屬性)需要用到的style(位于styles.xml文件中):

attr3 from custom_view_style

attr4 from custom_view_style

然后定義一個在xml布局文件中需要用到的style(位于styles.xml文件中):

attr2 from xml_style

attr3 from xml_style

自定義一個簡單的View:

public class CustomView extends View {

static final String LOG_TAG = "CustomView";

public CustomView(Context context) {

this(context, null);

}

public CustomView(Context context, AttributeSet attrs) {

this(context, attrs, R.attr.customViewStyle);

}

public CustomView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CustomView, defStyle, 0);

Log.d(LOG_TAG, "attr1 => " + array.getString(R.styleable.CustomView_attr1));

Log.d(LOG_TAG, "attr2 => " + array.getString(R.styleable.CustomView_attr2));

Log.d(LOG_TAG, "attr3 => " + array.getString(R.styleable.CustomView_attr3));

Log.d(LOG_TAG, "attr4 => " + array.getString(R.styleable.CustomView_attr4));

Log.d(LOG_TAG, "attr5 => " + array.getString(R.styleable.CustomView_attr5));

Log.d(LOG_TAG, "attr6 => " + array.getString(R.styleable.CustomView_attr6));

}

}

注意這里用到了R.attr.customViewStyle。為了使它生效,需要在當初工程的theme中設置它的值(位于styles.xml文件中):

@style/custom_view_style

這里就用到了我們上面定義的custom_view_style這個style。

運行結果:

運行結果

分析:

attr1只在xml布局文件中設置,所以值為attr1 from xml。

attr2在xml布局文件和xml style中都設置了,取值為布局文件中設置的值,所以為attr2 from xml。

attr3沒有在xml布局文件中設置,但是在xml style和defStyleAttr定義的style中設置了,取xml style中的值,所以值為attr3 from xml_style。

attr4只在defStyleAttr定義的style中設置了,所以值為attr4 from custom_view_style。

attr5和attr6沒有在任何地方設置值,所以為null。

這也證實了前面所得出的順序是正確的。

我們再來測試一下defStyleRes這個參數,它是一個style,所以添加一個style(位于styles.xml文件中):

attr4 from default_view_style

attr5 from default_view_style

然后還需要修改CustomView中的第16行,為下面一行:

TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CustomView, defStyle, R.style.default_view_style);

運行結果:

運行結果

咦,為什么結果和上面一樣呢?

我們看到官方文檔中對obtainStyledAttributes()方法的defStyleRes參數解釋是這樣的:

A resource identifier of a style resource that supplies default values for the TypedArray, used only if defStyleAttr is 0 or can not be found in the theme. Can be 0 to not look for defaults.

也就是說,當defStyleAttr這個參數定義為0(即不使用這個參數),或者是在theme中找不到defStyleAttr這個屬性時(即使在theme中的配置是這樣的:@null,也代表找到了defStyleAttr屬性,defStyleRes參數也不會生效),defStyleRes參數才會生效。

所以我們修改CustomView為下面內容(或者是去掉theme中對customViewStyle的使用):

TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CustomView, 0, R.style.default_view_style);

運行結果:

運行結果

由于defStyleAttr已經失效,所以attr4和attr5都是從default_view_style中獲取到的值。

我們知道,在theme所在的style中也可以設置屬性,如下:

@style/custom_view_style

attr5 from AppTheme

attr6 from AppTheme

運行結果:

運行結果

attr1~attr4不用說了。

attr5在default style和theme下都定義了,取default style下的值,所以為attr5 from default_view-style。

attr6只在theme下定義了,所以取值為attr6 from AppTheme。

注意,如果將CustomView中重新改成下面的內容(即使customViewStyle生效):

TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CustomView, defStyle, 0);

這時,default style是失效了的,那么在theme中設置的值會不會生效呢?

看運行結果:

運行結果

attr5在default style和theme下都定義了,但default style失效了,這里并沒有因為customViewStyle是有效的而忽略theme中設置的值,所以為attr5 from AppTheme。

attr6只在theme下定義了,同樣沒有因為customViewStyle是有效的而忽略theme中設置的值,所以取值為attr6 from AppTheme。

這里和default style的取值形式有一點點不同。

總結

View中的屬性有多處地方可以設置值,這個優先級是:

1、直接在XML布局文件中設置的值優先級最高,如果這里設置了值,就不會去取其他地方的值了。

2、XML布局文件中有一個叫“style”的屬性,它指向一個style,在這個style中設置的屬性值優先級次之。

3、如果上面兩個地方都沒有設置值,那么就會根據View帶三個參數的構造方法中的第三個參數attribute指向的style設置值,前提是這個attribute的值不為0。

4、如果上面的attribute設置為0了,我們就根據obtainStyledAttributes()方法中的最后一個參數指向的style來設置值。

5、如果仍然沒有設置到值,就會用theme中直接設置的屬性值,而不會去管第3步和第4步中是否設置了值。

必須要注意:要想讓View構造方法的第三個參數生效,必須讓它出現在我們自己的Application或者Activity的android:theme所指向的style中。設置Activity的theme一樣可以。

參考文章:

總結

以上是生活随笔為你收集整理的android view使用方法,Android View构造方法第三参数使用方法详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。