2018-11-29
在學(xué)習(xí)android自定義ViewGroup控件的過程中豺旬,隨著學(xué)習(xí)的深入會很容易意識到一些問題
比如:ViewGroup可以讓我通過重寫onLayout方法來操作子view在ViewGroup中的布局 做出很多比如線性布局這樣的自定義布局效果 但是有時候你會遇到
“不同的子view在布局中有不一樣的布局需求”的情況
最常見的就是:FrameLayout和LinearLayout 在xml文件中添加子view時你會發(fā)現(xiàn) FrameLayout的子view是不能添加Margin屬性的 而LinearLayout卻可以
這時你會發(fā)現(xiàn) 你的自定義ViewGroup里的子view也沒有這個屬性 這是什么原因钠惩?要知道 在android中要給一個view添加不同的屬性是需要重寫這個view帶AttributeSet的構(gòu)造方法的:
public TagGroup(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.TagGroup);
int targetColorInt = typedArray.getInt(R.styleable.TagGroup_targetColor,0);
if (targetColorInt != 0){
targetColor = context.getResources().getColor(targetColorInt);
}else targetColor = Color.WHITE;
typedArray.recycle();
}
要使用上面的方式獲取 int targetColorInt 需要先在android的values文件夾下新建一個名為attrs的xml文件 :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="TagGroup">
<attr name="targetColor" format="integer"/>
</declare-styleable>
</resources>
但是很明顯 LinearLayout并沒有使用這種方法 因為不管你添加什么view(包括你自定義的什么屬性都沒有的view)進去他們都會擁有Margin屬性
要怎么才能讓 “我的ViewGroup下的所有子view都擁有我希望它們擁有的屬性呢?” 這就需要我們的generateLayoutParams方法了
首先 我們修改下之前在attrs文件中的代碼:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="TagGroup_Layout">
<attr name="layoutMargin" format="dimension"/>
</declare-styleable>
</resources>
然后 我們先在我們的自定義ViewGroup中定義一個靜態(tài)的內(nèi)部類:
public static class TagGroupLayoutParams extends MarginLayoutParams {
public float margin;
public TagGroupLayoutParams(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.TagGroup_Layout);
margin = typedArray.getDimension(R.styleable.TagGroup_Layout_layoutMargin,0f);
typedArray.recycle();
}
public TagGroupLayoutParams(int width, int height) {
super(width, height);
}
public TagGroupLayoutParams(MarginLayoutParams source) {
super(source);
}
public TagGroupLayoutParams(LayoutParams source) {
super(source);
}
}
現(xiàn)在 在你的自定義ViewGroup中重寫關(guān)鍵的generateLayoutParams方法:
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new TagGroupLayoutParams(getContext(), attrs);
}
現(xiàn)在你會發(fā)現(xiàn) 在你的xml中 你的自定義ViewGroup不但擁有了margin屬性 還有了一個layoutMargin屬性:
<com.example.godru.demo.TagGroup
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/tag_group"
android:padding="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:myMargin="10dp"
android:layout_margin="10dp"
android:textSize="18sp"
android:text="@string/app_name"
/>
</com.example.godru.demo.TagGroup>
現(xiàn)在 你可以在任何地方通過獲取到你的ViewGroup中的子view 然后調(diào)用他們的getLayoutParams()方法來獲取TagGroupLayoutParams了 之后就可以使用你的自定義屬性來布局你的控件了
終上 其實generateLayoutParams方法的作用其實就是定義你的控件下所有子控件所使用的layoutParams類 通過這種形式使你的控件可以按自己想要的方式和屬性來操作它的子view 你甚至不需要關(guān)心子view本身 只要你重寫過generateLayoutParams方法 他們就一定會使用你給的LayoutParams來修飾自己 你也必然可以通過getLayoutParams方法獲取到 是一個高度解耦合的設(shè)計
注:自定義屬性可能在androidStudio中會報紅 說找不到目標(biāo)屬性 這是編譯問題 不會影響運行 通常把as關(guān)掉再進就會好