前言
經(jīng)歷就是財富
發(fā)現(xiàn)問題
有意無意之間,Android的開發(fā)不可避免涉及不到列表頁的,而列表頁大多也逃不開ListView宇立,當(dāng)然還有RecyclerView舀射。在開發(fā)的時候總是有莫名的問題出現(xiàn),而這些莫名的問題可能會浪費你一大半時間驹碍,索性現(xiàn)在網(wǎng)上的資源也很豐富壁涎,盡可能的縮短了這個時間,但與此同時還需要一雙發(fā)現(xiàn)問題本質(zhì)的眼睛志秃,閑話不再多說怔球,還是直奔主題的好。
情況是這樣的:也就是一般的給ListView的Item設(shè)置高度浮还,代碼表象如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="@dimen/dimen_120"
android:background="@color/white"
android:paddingEnd="@dimen/dimen_30"
android:paddingLeft="@dimen/dimen_30"
android:paddingRight="@dimen/dimen_30"
android:paddingStart="@dimen/dimen_30">
<View
android:id="@+id/view_divide"
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/color_dddddd"
tools:background="@color/color_ff5736"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/color_333333"
android:textSize="@dimen/text_size_28"
tools:text="每日簽到"/>
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimen_16"
android:textColor="@color/color_999999"
android:textSize="@dimen/text_size_24"
tools:text="2017-05-13 15:24"/>
</LinearLayout>
<TextView
android:id="@+id/tv_point_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:textSize="@dimen/text_size_34"
tools:text="+2"
tools:textColor="@color/color_ff5736"/>
</RelativeLayout>
在getView方法中:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 省略代碼......
convertView = LayoutInflater.from(getContext()).inflate(item.getItemLayout(), null, false);
// 省略代碼......
}
導(dǎo)致運行在手機(jī)上的表象就是無論把這個高度設(shè)置多大竟坛,其表現(xiàn)出來的都是剛好自適應(yīng)其高度,讓人無可奈何钧舌,各種打斷點瞎改都無濟(jì)于事担汤,時間緊迫,瞬間上頭了洼冻,哪根神經(jīng)搭錯了崭歧,想到去網(wǎng)上尋找答案,起初認(rèn)為這個高度不起作用撞牢,肯定是哪塊代碼有問題了率碾,屬于自己的疏忽操作,怎么可能是普遍存在呢屋彪?結(jié)果還真找到這樣的詞條了所宰,搜索到結(jié)果后很快的解決了問題,兩種解決方案畜挥,特附上鏈接:
解決ListView中Item布局設(shè)置的layout_height無效
Android中設(shè)置ListView的item高度無效--解決方案
然而問題就這樣解決了嗎歧匈? 這樣的話,怎么能滿足一顆程序員求知的心砰嘁?其歸根結(jié)底還是LayoutInflater
在從中作梗件炉,且聽我慢慢道來。
解決問題
熟悉LayoutInflater
的同學(xué)都知道矮湘,LayoutInflater
是用來動態(tài)加載布局的一大利器斟冕,獲取LayoutInflater
有三種方式:
1. LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT\_INFLATER\_SERVICE);
2. LayoutInflater inflater = LayoutInflater.from(context);
4. LayoutInflater inflater = getLayoutInflater(); //在Activity中調(diào)用
跟蹤源碼,上面的三種方式缅阳,最終都是通過第一種方式獲取的磕蛇,在日常編碼過程中景描,通常是使用第二種或第三種方式間接獲取LayoutInflater
,跟蹤源碼便不在此贅述秀撇,相信聰明的你肯定可以自行查看超棺。
說到這里不得不說到動態(tài)創(chuàng)建View的方式:
1. View.inflate(Context context, int resource, ViewGroup root);
2. LayoutInflater.from(context).inflate(int resource, ViewGroup root, boolean attachToRoot);
跟蹤源碼,通過View.inflate()
的方式其實還是調(diào)用了LayoutInflater.from(context).inflate()
, 我們一起來看一下:
//View.inflate方法調(diào)用LayoutInflater的inflate方法
public static View inflate(Context context, int resource, ViewGroup root) {
LayoutInflater factory = LayoutInflater.from(context);
return factory.inflate(resource, root);
}
//LayoutInflater的inflate重載方法
public View inflate(int resource, ViewGroup root) {
return inflate(resource, root, root != null);
}
//LayoutInflater的inflate重載方法
public View inflate(int resource, 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 {
//最終的調(diào)用重載方法
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
最終的最終調(diào)用該方法:
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
final AttributeSet attrs = Xml.asAttributeSet(parser);
mConstructorArgs[0] = mContext;
View result = root;
try {
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
}
if (type != XmlPullParser.START_TAG) {
throw new InflateException(parser.getPositionDescription()
+ ": No start tag found!");
}
final String name = parser.getName();
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, attrs);
} else {
View temp = createViewFromTag(name, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
temp.setLayoutParams(params);
}
}
rInflate(parser, temp, attrs);
if (root != null && attachToRoot) {
root.addView(temp, params);
}
if (root == null || !attachToRoot) {
result = temp;
}
}
} catch (XmlPullParserException e) {
InflateException ex = new InflateException(e.getMessage());
ex.initCause(e);
throw ex;
} catch (IOException e) {
InflateException ex = new InflateException(
parser.getPositionDescription()
+ ": " + e.getMessage());
ex.initCause(e);
throw ex;
}
return result;
}
}
上面的代碼就是使用Android提供的pull解析方式來解析布局文件的呵燕,核心方法是createViewFromTag()
,這個方法是用于根據(jù)節(jié)點來創(chuàng)建View對象棠绘。
重點代碼摘要:
View temp = createViewFromTag(name, attrs);
ViewGroup.LayoutParams params = null;
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
temp.setLayoutParams(params);
}
rInflate(parser, temp, attrs);
if (root != null && attachToRoot) {
root.addView(temp, params);
}
if (root == null || !attachToRoot) {
result = temp;
}
歸納總結(jié):對于inflate(int resource, ViewGroup root, boolean attachToRoot)
- 如果root為null,attachToRoot將失去作用再扭,設(shè)置任何值都沒有意義
- 如果root不為null氧苍,attachToRoot設(shè)為true,則會給加載的布局文件的指定一個父布局泛范,即root
- 如果root不為null让虐,attachToRoot設(shè)為false,則會將布局文件最外層的所有l(wèi)ayout屬性進(jìn)行設(shè)置罢荡,當(dāng)該view被添加到父view當(dāng)中時赡突,這些layout屬性會自動生效
- 在不設(shè)置attachToRoot參數(shù)的情況下,如果root不為null区赵,attachToRoot參數(shù)默認(rèn)為true
總結(jié)
綜上所述惭缰,給ListView的Item設(shè)置高度時所出現(xiàn)的問題,便迎刃而解惧笛。有時候我們不應(yīng)該僅僅停留在問題的表象上面从媚,而應(yīng)該發(fā)現(xiàn)問題的本質(zhì),當(dāng)你解決了這個問題患整,收獲的就不僅僅是這個問題了拜效。
參考:
Android LayoutInflater原理分析,帶你一步步深入了解View(一)
LayoutInflater源碼分析與應(yīng)用