scrollview中隻能放一個控件,一般都放linearlayout,orientation屬性值為vertical。在linearlayout中放需要呈現的内容。listview也在其中,listview的高度設為适應自身内容(wrap_content)。但是為啥在scrollview中嵌套listview會出現隻顯示第一條listitem的高度呢,原因是:scrollview的ontach方法的滾動事件消費處理,listview控件的高度設定問題
從谷歌那裡找到的scrollview嵌套listview隻顯示一行的解決辦法相信很多人都遇到過,然後大部分都是用這位部落客的辦法解決的吧
剛開始我也是用這個辦法解決的,首先感謝這位哥的大私奉獻,貼上位址
<a target="_blank" href="http://blog.csdn.net/p106786860/article/details/10461015">http://blog.csdn.net/p106786860/article/details/10461015</a>
2、解決的核心代碼
public void setlistviewheightbasedonchildren(listview listview) {
// 擷取listview對應的adapter
listadapter listadapter = listview.getadapter();
if (listadapter == null) {
return;
}
int totalheight = 0;
for (int i = 0, len = listadapter.getcount(); i < len; i++) {
// listadapter.getcount()傳回資料項的數目
view listitem = listadapter.getview(i, null, listview);
// 計算子項view 的寬高
listitem.measure(0, 0);
// 統計所有子項的總高度
totalheight += listitem.getmeasuredheight();
viewgroup.layoutparams params = listview.getlayoutparams();
params.height = totalheight+ (listview.getdividerheight() * (listadapter.getcount() - 1));
// listview.getdividerheight()擷取子項間分隔符占用的高度
// params.height最後得到整個listview完整顯示需要的高度
listview.setlayoutparams(params);
}
這個代碼讓控件去計算listview自己的高度然後設定這個listview的高度
但是這個代碼裡面有一個問題,就是這個當你的listview裡面有多行的textview的話,listview的高度就會計算錯誤,它隻算到了一行textview的高度,
這個問題在so上的概述為以下:
<a target="_blank" href="http://stackoverflow.com/questions/14386584/getmeasuredheight-of-textview-with-wrapped-text">http://stackoverflow.com/questions/14386584/getmeasuredheight-of-textview-with-wrapped-text</a>
3、終極解決辦法
這個問題頭疼了一陣後,查找了一下,應該重寫一個textview的onmeasure方法比較好解決
代碼有
@override
protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
super.onmeasure(widthmeasurespec, heightmeasurespec);
layout layout = getlayout();
if (layout != null) {
int height = (int)floatmath.ceil(getmaxlineheight(this.gettext().tostring()))
+ getcompoundpaddingtop() + getcompoundpaddingbottom();
int width = getmeasuredwidth();
setmeasureddimension(width, height);
}
}
private float getmaxlineheight(string str) {
float height = 0.0f;
float screenw = ((activity)context).getwindowmanager().getdefaultdisplay().getwidth();
float paddingleft = ((linearlayout)this.getparent()).getpaddingleft();
float paddingreft = ((linearlayout)this.getparent()).getpaddingright();
//這裡具體this.getpaint()要注意使用,要看你的textview在什麼位置,這個是拿textview父控件的padding的,為了更準确的算出換行
int line = (int) math.ceil( (this.getpaint().measuretext(str)/(screenw-paddingleft-paddingreft))); height = (this.getpaint().getfontmetrics().descent-this.getpaint().getfontmetrics().ascent)*line; return height;}
上面的代碼完成更能為,在listview開始測量時,測量到textview時,就調用我們的onmeasure方法,我們就可以測量字型的總寬度除與去掉邊距的螢幕的大小,就可以算出文字要幾行來顯示,然後測量字型的高度*行數可以得到字型的總高度,然後在加上上下邊距就是textview真正的高度,然後setmeasureddimension進去就可以計算出正确的值出來。
完整大代碼我貼出來
public class mylistview2 extends linearlayout {
private baseadapter adapter;
private myonitemclicklistener onitemclicklistener;
boolean footerviewattached = false;
private view footerview;
@override
protected void onlayout(boolean changed, int l, int t, int r, int b) {
// todo auto-generated method stub
super.onlayout(changed, l, t, r, b);
}
protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
int expandspec = measurespec.makemeasurespec(integer.max_value >> 2,
measurespec.at_most);
super.onmeasure(widthmeasurespec, expandspec);
public void notifychange() {
int count = getchildcount();
if (footerviewattached) {
count--;
layoutparams params = new layoutparams(layoutparams.fill_parent,
layoutparams.wrap_content);
for (int i = count; i < adapter.getcount(); i++) {
final int index = i;
final linearlayout layout = new linearlayout(getcontext());
layout.setlayoutparams(params);
layout.setorientation(vertical);
view v = adapter.getview(i, null, null);
v.setonclicklistener(new onclicklistener() {
public void onclick(view v) {
if (onitemclicklistener != null) {
onitemclicklistener.onitemclick(mylistview2.this,
layout, index, adapter.getitem(index));
});
imageview imageview = new imageview(getcontext());
imageview.setlayoutparams(params);
layout.addview(v);
layout.addview(imageview);
addview(layout, index);
public mylistview2(context context) {
super(context);
initattr(null);
public mylistview2(context context, attributeset attrs) {
super(context, attrs);
initattr(attrs);
public void initattr(attributeset attrs) {
setorientation(vertical);
public void initfooterview(final view footerview) {
this.footerview = footerview;
public void setfooterviewlistener(onclicklistener onclicklistener) {
this.footerview.setonclicklistener(onclicklistener);
public baseadapter getadapter() {
return adapter;
public void setadapter(baseadapter adpater) {
this.adapter = adpater;
removeallviews();
if (footerviewattached)
addview(footerview);
notifychange();
public void setonitemclicklistener(myonitemclicklistener onclicklistener) {
this.onitemclicklistener = onclicklistener;
public void nomorepages() {
if (footerview != null && footerviewattached) {
removeview(footerview);
footerviewattached = false;
public void mayhavemorepages() {
if (!footerviewattached && footerview != null) {
footerviewattached = true;
public static interface myonitemclicklistener {
public void onitemclick(viewgroup parent, view view, int position,
object o);
這個adapter就是你擷取資料後設定的,也就是上面兩點的綜合