最近正在做動态添加Button的效果。結果動态添加的按鈕的樣式設定過了但是margin屬性卻總是被忽略,不起作用。這個還是得從LayoutInflater的使用開始說起。
LayoutInflater有三種加載方式,之前看過網上的很多關于LayoutInflater的擷取方式,但是想要使動态加載的view的屬性生效,實際上取決于我們使用的LayoutInflater的方法。(不要感覺下面的LayoutInflater 的獲得方式沒用,重點是第二部分動态加載view的方式)
獲得 LayoutInflater 的三種方式
這裡簡單介紹一下LayoutInflater 獲得的三種方式,如果你已經很清楚了就不需要看了
方式一:
//調用Activity的getLayoutInflater()
LayoutInflater inflater = getLayoutInflater();
方式二:
LayoutInflater inflater = LayoutInflater.from(context);
方式三:
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
動态加載方式
這部分才是重點
既然要動态加載那就需要獲得我們的view,view的獲得方式,根據方法的重載,傳遞的參數不同,調用的方法也不同。下面是LayoutInflater的源碼,結合源碼來看一下。
LayoutInflater獲得View有三種方法,主要使用的下面兩中方式:
代碼執行個體:
這種調用方式會忽略View的屬性
.inflate(R.layout.activity_travel_starttravel,null);
這種方式才是我們所想要的,不會使屬性失效的方式
.inflate(R.layout.activity_travel_starttravel,mLinearLayoutEndTravel,false)
下面看下源碼中他們的差別
方式一:
from the specified xml resource. Throws
* {@link InflateException} if there is an error.
*
* @param resource ID for an XML layout resource to load (e.g.,
* <code>R.layout.main_page</code>)
* @param root Optional view to be the parent of the generated hierarchy.
* @return The root View of the inflated hierarchy. If root was supplied,
* this is the root View; otherwise it is the root of the inflated
* XML file.
*/
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return
注意:可以看出來方式一調用的是方式二的三個參數的傳遞方法,這就是關鍵了,是以我們直接來看方式二
方式二:
from the specified xml resource. Throws
* {@link InflateException} if there is an error.
*
* @param resource ID for an XML layout resource to load (e.g.,
* <code>R.layout.main_page</code>)
* @param root Optional view to be the parent of the generated hierarchy (if
* <em>attachToRoot</em> is true), or else simply an object that
* provides a set of LayoutParams values for root of the returned
* hierarchy (if <em>attachToRoot</em> is false.)
* @param attachToRoot Whether the inflated hierarchy should be attached to
* the root parameter? If false, root is only used to create the
* correct subclass of LayoutParams for the root view in the XML.
* @return The root View of the inflated hierarchy. If root was supplied and
* attachToRoot is true, this is root; otherwise it is the root of
* the inflated XML file.
*/
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
if (DEBUG) {
Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
+ Integer.toHexString(resource) + ")");
}
final XmlResourceParser parser = res.getLayout(resource);
try {
return
方式二中再次進行了調用了方法inflate,也就是下面的方法
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
final Context inflaterContext = mContext;
final AttributeSet attrs = Xml.asAttributeSet(parser);
Context lastContext = (Context) mConstructorArgs[0];
mConstructorArgs[0] = inflaterContext;
View result = root;
try {
// Look for the root node.
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty
}
//有關XmlPullParser的部分先不管
if (type != XmlPullParser.START_TAG) {
throw new InflateException(parser.getPositionDescription()
+ ": No start tag found!");
}
final String name = parser.getName();
if (DEBUG) {
System.out.println("**************************");
System.out.println("Creating root view: "
+ name);
System.out.println("**************************");
}
if (TAG_MERGE.equals(name)) {
if (root == null || !attachToRoot) {
throw new InflateException("<merge /> can be used only with a valid "
+ "ViewGroup root and attachToRoot=true");
}
rInflate(parser, root, inflaterContext, attrs, false);
} else {
// Temp is the root view that was found in the xml
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
//直接看這一部分,如果傳入了view所要添加到的布局則會産生布局屬性
if (root != null) {
if (DEBUG) {
System.out.println("Creating params from root: " +
root);
}
// Create layout params that match root, if supplied
//産生與布局相關的參數
params = root.generateLayoutParams(attrs);
//如果将attachToRoot設定為false則進行設定屬性,否則不設定
//前面方式一與方式二預設傳入的是root!=null,也就是傳入了attachToRoot=true,是以不會設定屬性了
if (!attachToRoot) {
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
temp.setLayoutParams(params);
}
}
if (DEBUG) {
System.out.println("-----> start inflating children");
}
// Inflate all children under temp against its context.
rInflateChildren(parser, temp, attrs, true);
if (DEBUG) {
System.out.println("-----> done inflating children");
}
// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
root.addView(temp, params);
}
// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;
}
}
} catch (XmlPullParserException e) {
InflateException ex = new InflateException(e.getMessage());
ex.initCause(e);
throw ex;
} catch (Exception e) {
InflateException ex = new InflateException(
parser.getPositionDescription()
+ ": " + e.getMessage());
ex.initCause(e);
throw ex;
} finally {
// Don't retain static reference on context.
mConstructorArgs[0] = lastContext;
mConstructorArgs[1] = null;
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
return
重點了解部分:
是以,如果想要使你動态添加的按鈕有效則必須使用方式二來添加按鈕。下面附一個使用執行個體,實作的效果是部落格開篇圖檔展示的效果。
使用執行個體
界面布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/activity_chart_subscribe_header"></include>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/light_grey"></View>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="已添加"
android:textSize="18sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="(點選删除)"
android:textSize="14sp"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/light_grey"></View>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
<Button
android:id="@+id/button_nullsubscribe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="20dp"
android:drawableTop="@mipmap/formdate_null_icon"
android:textColor="@color/grey"
android:visibility="gone"
android:background="@null"/>
<GridLayout
android:id="@+id/gridlayoyt_blank_chartsubscribe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:columnCount="3"
android:rowCount="3"
android:minHeight="10dp"
android:minWidth="10dp"
android:layout_marginLeft="10dp"
<Button
android:id="@+id/button_gridlayout_blank_locate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="随時定位"
style="@style/SubscribeBlankButtonStyle"
<Button
android:id="@+id/button_gridlayout_blank_cusvisit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="客戶拜訪"
style="@style/SubscribeBlankButtonStyle"
<Button
android:id="@+id/button_gridlayout_blank_addnewcus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="新增客戶"
style="@style/SubscribeBlankButtonStyle"
<Button
android:id="@+id/button_gridlayout_blank_cusall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/SubscribeBlankButtonStyle"
android:text="客戶總量"/>
</GridLayout>
</FrameLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/light_grey"></View>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="可添加"
android:layout_marginLeft="15dp"
android:layout_marginTop="10dp"
android:paddingBottom="10dp"
android:paddingTop="10dp"
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/light_grey"></View>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
<GridLayout
android:id="@+id/gridlayoyt_canadd_chartsubscribe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:rowCount="2"
android:columnCount="3"
android:minHeight="10dp"
android:minWidth="10dp"
android:layout_marginLeft="10dp"
</GridLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/light_grey"></View>
</LinearLayout>
按鈕的兩種樣式設定
name="SubscribeBlankButtonStyle">
<item name="android:textColor">@color/red</item>
<item name="android:background">@drawable/subscribe_button_red</item>
<item name="android:textSize">14sp</item>
<item name="android:layout_weight">1</item>
<item name="android:layout_columnWeight">1</item>
<item name="android:layout_marginTop">10dp</item>
<item name="android:layout_marginLeft">10dp</item>
<item name="android:layout_gravity">fill_horizontal</item>
</style>
<style name="SubscribeAddButtonStyle">
<item name="android:textColor">@color/deep_grey</item>
<item name="android:textSize">14sp</item>
<item name="android:maxWidth">80dp</item>
<item name="android:layout_weight">1</item>
<item name="android:layout_marginTop">10dp</item>
<item name="android:layout_columnWeight">1</item>
<item name="android:layout_marginLeft">10dp</item>
<item name="android:background">@drawable/subscribe_button_grey</item>
<item name="android:layout_gravity">fill_horizontal</item>
</style>
Button按鈕的兩個子View,編寫在了xml檔案中
紅色按鈕樣式
<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/SubscribeAddButtonStyle"
<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/SubscribeBlankButtonStyle"
public class ActivityChartSubscribe extends BaseActivity implements View.OnClickListener{
//傳回報表界面的按鈕注釋
private Button mButtonBackToChart;
//已添加下面沒有任何東西時的button
private Button mButtonBlank;
//已添加下面的GridLayout
private GridLayout mGridLayoutBlank;
//可添加下面的GridLayout
private GridLayout mGridLayoutAdd;
//已添加下面的按鈕
private Button mButtonGridBlankLocate;
private Button mButtonGridBlankCusVisit;
private Button mButtonGridBlankAddNewCus;
private Button mButtonGridBlankCusAll;
private int TYPE_LOCATE=0x11;
private int TYPE_CUSVISIT=0x22;
private int TYPE_CusALL=0x33;
private int TYPE_AddNewCus=0x44;
private int mButtonCount=4;
private List<String> mButtonType;
private List<String> mButtonTypeAdd;
private SharedPreferences mSharedPreferences;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chart_subscribe);
chartsubscribefindview();
}
@Override
public void onClick(View view) {
switch ( view.getId()){
case R.id.button_backtochart_chartsubscribe:
//傳回報表界面
SharedPreferences.Editor mEdit1= mSharedPreferences.edit();
mEdit1.putInt("Button_type", mButtonType.size()); /*sKey is an array*/
for(int i=0;i<mButtonType.size();i++) {
mEdit1.remove("Button_" + i);
mEdit1.putString("Button_" + i, mButtonType.get(i));
}
mEdit1.commit();
finish();
break;
case R.id.button_gridlayout_blank_locate:
deletebuttonfromgridblank(view, TYPE_LOCATE);
break;
case R.id.button_gridlayout_blank_cusvisit:
deletebuttonfromgridblank(view ,TYPE_CUSVISIT);
break;
case R.id.button_gridlayout_blank_cusall:
deletebuttonfromgridblank(view, TYPE_CusALL);
break;
case R.id.button_gridlayout_blank_addnewcus:
//從BlankGridlayout部分删除,新增客戶
deletebuttonfromgridblank(view, TYPE_AddNewCus);
break;
}
}
/**
*該方法用于删除紅色的按鈕同時添加灰色的按鈕
* @param
private void deletebuttonfromgridblank(View v,final int type) {
mGridLayoutBlank.removeView(v);
Button button=(Button)v;
mButtonCount--;
isnull();
LayoutInflater inflater=LayoutInflater.from(this);
//使用三個參數的方式加載Button
Button buttongridaddlocate=(Button)inflater.inflate(R.layout.button_subscribe_grey, mGridLayoutAdd,false);
for (int i=mButtonType.size()-1;i>=0;i--){
if (mButtonType.get(i).equals(button.getText().toString()))
{
mButtonType.remove(i);
}
}
for (int i=mButtonTypeAdd.size()-1;i>=0;i--){
if (mButtonTypeAdd.get(i).equals(button.getText().toString()))
{
mButtonTypeAdd.add(button.getText().toString());
}
}
if(type==TYPE_LOCATE){
buttongridaddlocate.setText("随時定位");
}
if (type==TYPE_CUSVISIT){
buttongridaddlocate.setText("客戶拜訪");
}
if (type==TYPE_CusALL){
buttongridaddlocate.setText("客戶總量");
}
if (type==TYPE_AddNewCus){
buttongridaddlocate.setText("新增客戶");
}
mGridLayoutAdd.addView(buttongridaddlocate);
buttongridaddlocate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
addbuttontogridblank(view, type);
}
});
}
/**
* 該方法用于删除灰色的按鈕同時添加紅色的按鈕
* @param
private void addbuttontogridblank(View v,final int type) {
mGridLayoutAdd.removeView(v);
Button button= (Button) v;
mButtonCount++;
isnull();
LayoutInflater inflater=LayoutInflater.from(this);
Button buttongridblanklocate=(Button)inflater.inflate(R.layout.button_subscribe_red,mGridLayoutBlank,false);
for (int i=mButtonType.size()-1;i>=0;i--){
if (mButtonType.get(i).equals(button.getText().toString()))
{
mButtonType.add(button.getText().toString());
}
}
for (int i=mButtonTypeAdd.size()-1;i>=0;i--){
if (mButtonTypeAdd.get(i).equals(button.getText().toString()))
{
mButtonTypeAdd.remove(button.getText().toString());
}
}
if(type==TYPE_LOCATE){
buttongridblanklocate.setText("随時定位");
}
if (type==TYPE_CUSVISIT){
buttongridblanklocate.setText("客戶拜訪");
}
if (type==TYPE_CusALL){
buttongridblanklocate.setText("客戶總量");
}
if (type==TYPE_AddNewCus){
buttongridblanklocate.setText("新增客戶");
}
mGridLayoutBlank.addView(buttongridblanklocate);
buttongridblanklocate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
deletebuttonfromgridblank(view, type);
}
});
}
private void chartsubscribefindview(){
//傳回按鈕
mButtonBackToChart= (Button) findViewById(R.id.button_backtochart_chartsubscribe);
//已添加部分沒有任何資訊時需要顯示的按鈕
mButtonBlank= (Button) findViewById(R.id.button_nullsubscribe);
mButtonBackToChart.setOnClickListener(this);
mButtonBlank.setOnClickListener(this);
//已添加的布局
mGridLayoutBlank= (GridLayout) findViewById(R.id.gridlayoyt_blank_chartsubscribe);
//可添加的布局
mGridLayoutAdd= (GridLayout) findViewById(R.id.gridlayoyt_canadd_chartsubscribe);
mButtonGridBlankLocate= (Button) findViewById(R.id.button_gridlayout_blank_locate);
mButtonGridBlankCusVisit= (Button) findViewById(R.id.button_gridlayout_blank_cusvisit);
mButtonGridBlankAddNewCus= (Button) findViewById(R.id.button_gridlayout_blank_addnewcus);
mButtonGridBlankCusAll= (Button) findViewById(R.id.button_gridlayout_blank_cusall);
mButtonGridBlankCusAll.setOnClickListener(this);
mButtonGridBlankLocate.setOnClickListener(this);
mButtonGridBlankCusVisit.setOnClickListener(this);
mButtonGridBlankAddNewCus.setOnClickListener(this);
mButtonType=new ArrayList<>();
mButtonTypeAdd=new ArrayList<>();
mSharedPreferences= getSharedPreferences("buttontype",MODE_PRIVATE);
}
private void isnull(){
if(mButtonCount==0){
mButtonBlank.setVisibility(View.VISIBLE);
}else{
mButtonBlank.setVisibility(View.GONE);
}
}
@Override
protected void onResume() {
int size = mSharedPreferences.getInt("Button_type", 0);
for(int i=0;i<size;i++) {
mButtonType.add(mSharedPreferences.getString("Button_" + i, null));
}
List<String> mButtonTypeAddCopy=mButtonTypeAdd;
for (int i=mButtonTypeAddCopy.size()-1;i>=0;i++){
switch (mButtonTypeAddCopy.get(i)){
case "随時定位":deletebuttonfromgridblank(mButtonGridBlankLocate, TYPE_LOCATE);
break;
case "客戶拜訪":deletebuttonfromgridblank(mButtonGridBlankCusVisit, TYPE_CUSVISIT);break;
case "新增客戶":deletebuttonfromgridblank(mButtonGridBlankAddNewCus, TYPE_AddNewCus);break;
case "客戶總量":deletebuttonfromgridblank(mButtonGridBlankCusAll, TYPE_CusALL);break;
}
}
super.onResume();
}
}