正 常來講,在ScrollView添加一個ListView後在真機上只會顯示ListView的一行多一點,我也不理解爲何會這樣,後來我把 ListView的layout_height改爲400dip,而不是用match_parent和wrap_content,我發現這樣的話 ListView就顯示的多了不少。因此就產生了把ListView全部的item的高度算出來給ListView設置的想法。下面是代碼:html
源碼:http://www.jinhusns.com/Products/Download/?type=xcjjava
public void setListViewHeightBasedOnChildren(ListView listView) { 編程
ListAdapter listAdapter = listView.getAdapter(); app
if (listAdapter == null) { ide
return; 函數
} 佈局
int totalHeight = 0; 測試
for (int i = 0; i < listAdapter.getCount(); i++) { this
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
params.height += 5;//if without this statement,the listview will be a little short
listView.setLayoutParams(params);
}
在代碼的倒數第二行二我又給加了5個像素,這是由於我在listview的屬性裏面添加了padding=5dip。
而後每次ListView的數據一有變化就用這個函數設置一下就行了,不過這樣總感受效率很低,但願有達人給指點一下。
簡單來講就是把layout_height寫死,這種辦法也很適用於GridView(若是能估計得出GridView的高度的話)。
listview與ScrollView老問題的另類解法
http://www.eoeandroid.com/thread-42893-1-1.html
這 幾天一直被listview怎麼合理的放進scorllview中的問題困擾,嘗試過把listview放入scorllview中的朋友都知 道,被放入的listview顯示是有問題的,不管怎麼設置layout都只顯示大概2行的高度,看起來很鬱悶,更別說美觀了,後來上網查詢了一下,解決 方法有的是用linearlayout替換listview,還有修改onmeasure的,我比較懶我的感受很麻煩不喜歡,終於想出了一個還算和諧的解 決方法:xml中的textlist設置以下:
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#44444444">
<ScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/ll1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:orientation="vertical"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingTop="30dp"
android:paddingBottom="30dp"
android:background="#ff888888">
<TextView
android:text="あ"
android:textColor="#ffeeeeee"
android:textSize="18sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"></TextView>
<ListView
android:scrollbars="none"
android:stackFromBottom="true"
android:id="@+id/lv0"
android:layout_width="fill_parent"
android:layout_height="20dp"></ListView>
</LinearLayout>
</ScrollView>
</LinearLayout>
其中的textview是我作的東西要用到的,和方法無關能夠不看,而後就是在java中從新設置listview的高度了,目的是把listview「撐」開:
LinearLayout.LayoutParams lp5 =new LinearLayout.LayoutParam(LayoutParams.FILL_PARENT, listItem.size()*51-1);
其 中第一個屬性沒必要說了,第二個是爲了計算listview要設置的總高度用的,51是我事先設置好的一行的高度(50)+每行之間的間隔(1) 而得來的,listItem.size()是我要顯示的行數,用.setLayoutParams(lp5);來從新設置高度,其餘別的設置跟之前同樣, 想要源碼我整理完以後貼出來
若是不想寫死 ,Android 解決ListView 和 ScrollView 共存衝突的問題
http://labs.chinamobile.com/mblog/532767_72693?wralxianxrnx
http://blog.liaoxiaoqi.com/?p=503
下面是個人一個實現 步驟:
一、繼承LinearLayout,既然會衝突那就不用ListView 改爲線性佈局作動態佈局效果
二、繼承BaseAdapter ,能夠參照一下Android app源碼中 Widget 目錄下的SimpleAdapter 爲前面擴展的LinearLayout作數據。
三、模擬數據填充擴展後的BaseAdapter 爲擴展後的LinearLayout 加載數據
第一步:新建LinearLayoutForListView 類使其擴展LinearLayout重寫如下兩個方法:
public LinearLayoutForListView(Context context) {
super(context);
}
public LinearLayoutForListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
這兩個方法可選,不過建議都寫上,第一個方法可讓咱們經過 編程的方式 實例化出來,第二個方法能夠容許咱們經過 XML的方式註冊 控件,能夠在第二個方法裏面爲擴展的複合組件加屬性。爲其添加get / set 方法
/**
* 獲取Adapter
*
* @return adapter
*/
public AdapterForLinearLayout getAdpater() {
return adapter;
}
/**
* 設置數據
*
* @param adpater
*/
public void setAdapter(AdapterForLinearLayout adpater) {
this.adapter = adpater;
bindLinearLayout();
}
/**
* 獲取點擊事件
*
* @return
*/
public OnClickListener getOnclickListner() {
return onClickListener;
}
/**
* 設置點擊事件
*
* @param onClickListener
*/
public void setOnclickLinstener(OnClickListener onClickListener) {
this.onClickListener = onClickListener;
}
sp;
第二步:新建AdapterForLinearLayout 類繼承自BaseAdapter,併爲其添加構造函數
private LayoutInflater mInflater;
private int resource;
private List<? extends Map<String, ?>> data;
private String[] from;
private int[] to;
public AdapterForLinearLayout(Context context,
List<? extends Map<String, ?>> data, int resouce, String[] from,
int[] to) {
this.data = data;
this.resource = resouce;
this.data = data;
this.from = from;
this.to = to;
this.mInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
此 構造函數模仿 simpleAdapter 經過傳進來的resouce 爲佈局設置數據。經過繼承BaseAdapter 重要的實現方法在下面getView ,此方法判斷經過傳進來的 String[] from 與 int[] to 爲分別查找出View 併爲View 設置相應的Text,代碼以下:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
convertView = mInflater.inflate(resource, null);
Map<String, ?> item = data.get(position);
int count = to.length;
for (int i = 0; i < count; i++) {
View v = convertView.findViewById(to[i]);
bindView(v, item, from[i]);
}
convertView.setTag(position);
return convertView;
}
/**
* 綁定視圖
* @param view
* @param item
* @param from
*/
private void bindView(View view, Map<String, ?> item, String from) {
Object data = item.get(from);
if (view instanceof TextView) {
((TextView) view).setText(data == null ? "" : data.toString());
}
}
Tip:
BindView 方法是一個自定義方法,在方法體內能夠爲經過判斷使本類更具靈活性,如上,你不只能夠判斷是TextView 而且能夠傳入任何你想要的View 只要在方法體內加入相應判斷便可,數據能夠經過data 作相應處理,具體如何操做讀者可另行測試。
convertView.setTag(position); 此句代碼爲View 設置tag 在之後咱們能夠經過 getTag 找出下標,後文有介紹如何經過下標操做數據。
下面是兩個類的所有代碼,讀者能夠無須更改直接使用:
LinearLayoutForListView
package com.terry.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
public class LinearLayoutForListView extends LinearLayout {
private AdapterForLinearLayout adapter;
private OnClickListener onClickListener = null ;
/**
* 綁定佈局
*/
public void bindLinearLayout() {
int count = adapter.getCount();
for ( int i = 0 ; i < count; i ++ ) {
View v = adapter.getView(i, null , null );
v.setOnClickListener( this .onClickListener);
if (i == count - 1 ) {
LinearLayout ly = (LinearLayout) v;
ly.removeViewAt( 2 );
}
addView(v, i);
}
Log.v( " countTAG " , "" + count);
}
public LinearLayoutForListView(Context context) {
super (context);
}
public LinearLayoutForListView(Context context, AttributeSet attrs) {
super (context, attrs);
}
/**
* 獲取Adapter
*
* @ return adapter
*/
public AdapterForLinearLayout getAdpater() {
return adapter;
}
/**
* 設置數據
*
* @ param adpater
*/
public void setAdapter(AdapterForLinearLayout adpater) {
this .adapter = adpater;
bindLinearLayout();
}
/**
* 獲取點擊事件
*
* @ return
*/
public OnClickListener getOnclickListner() {
return onClickListener;
}
/**
* 設置點擊事件
*
* @ param onClickListener
*/
public void setOnclickLinstener(OnClickListener onClickListener) {
this .onClickListener = onClickListener;
}
}
AdapterForLinearLayout
package com.terry.widget;
import java.util.List;
import java.util.Map;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class AdapterForLinearLayout extends BaseAdapter {
private LayoutInflater mInflater;
private int resource;
private List <? extends Map < String, ?>> data;
private String[] from;
private int [] to;
public AdapterForLinearLayout(Context context,
List <? extends Map < String, ?>> data, int resouce, String[] from,
int [] to) {
this .data = data;
this .resource = resouce;
this .data = data;
this .from = from;
this .to = to;
this .mInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@ Override
public int getCount() {
// TODO Auto-generated method stub
return data.size();
}
@ Override
public Object getItem( int position) {
// TODO Auto-generated method stub
return data.get(position);
}
@ SuppressWarnings( " unchecked " )
public String get( int position, Object key) {
Map < String, ?> map = (Map < String, ?> ) getItem(position);
return map.get(key).toString();
}
@ Override
public long getItemId( int position) {
// TODO Auto-generated method stub
return position;
}
@ Override
public View getView( int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
convertView = mInflater.inflate(resource, null );
Map < String, ?> item = data.get(position);
int count = to.length;
for ( int i = 0 ; i < count; i ++ ) {
View v = convertView.findViewById(to[i]);
bindView(v, item, from[i]);
}
convertView.setTag(position);
return convertView;
}
/**
* 綁定視圖
* @ param view
* @ param item
* @ param from
*/
private void bindView(View view, Map < String, ?> item, String from) {
Object data = item.get(from);
if (view instanceof TextView) {
((TextView) view).setText(data == null ? "" : data.toString());
}
}
}
對應的XML 以下:
<? xml version="1.0" encoding="UTF-8" ?>
< LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android"
android:orientation ="vertical" android:layout_width ="fill_parent"
android:layout_height ="fill_parent" >
< TextView android:id ="@ +id/TextView01"
android:layout_marginLeft ="10px" android:textAppearance ="?android:attr/textAppearanceLarge"
android:layout_width ="wrap_content" android:layout_height ="wrap_content" >
</ TextView >
< TextView android:id ="@ +id/TextView02" android:layout_width ="wrap_content"
android:textAppearance ="?android:attr/textAppearanceSmall"
android:layout_marginLeft ="10px" android:layout_height ="wrap_content" >
</ TextView >
< View android:layout_height ="1px" android:background ="#FFFFFF"
android:layout_width ="fill_parent" ></ View >
</ LinearLayout >
第三步:主頁面使用控件併爲其設置數據
XML以下:
< com.terry.widget.LinearLayoutForListView
android:orientation ="vertical" android:layout_width ="450px"
android:layout_height ="fill_parent" android:id ="@ +id/ListView01" >
</ com.terry.widget.LinearLayoutForListView >
加載數據以下:
lv = (LinearLayoutForListView) findViewById(R.id.ListView01);
for ( int i = 0 ; i < 10 ; i ++ ) {
HashMap < String, Object > map = new HashMap < String, Object > ();
map.put( " key_name " , " name " + i);
map.put( " value_name " , " value " + i);
list.add(map);
}
final AdapterForLinearLayout Layoutadpater = new AdapterForLinearLayout(
this , list, R.layout.test, new String[] { " key_name " ,
" value_name " }, new int [] { R.id.TextView01,
R.id.TextView02 });
事件操做,並經過下標獲得數據源:
Tip:get方法是在Layoutadpater 封裝的一個經過下標獲取相應數據的方法請參考上文。
lv.setOnclickLinstener( new OnClickListener() {
@ Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(
BlueToothActivity. this ,
Layoutadpater.get(Integer.parseInt(v.getTag()
.toString()), " key_name " ), 1000 ).show();
}
});
lv.setAdapter(Layoutadpater);
至此完成。有碰到這個問題的朋友能夠試試。
有人的總結以下:
只要在設置ListView的Adapter後調用此靜態方法便可讓ListView正確的顯示在其父ListView的ListItem中。可是要注意 的是,子ListView的每一個Item必須是LinearLayout,不能是其餘的,由於其餘的Layout(如RelativeLayout)沒有 重寫onMeasure(),因此會在onMeasure()時拋出異常。
在ScrollView中嵌套ListView(或者 ScrollView)的另一個問題就是,子ScrollView中沒法滑動的(若是它沒有顯 示徹底的話),由於滑動事件會被父ScrollView吃掉,若是想要讓子ScrollView也能夠滑動,只能強行截取滑動事件,有牛人在論壇 中發過代碼說能夠。雖然我沒有親自試過,但估計是可行的。
雖然在ScrollView中顯示ScrollView在技術上的難題能夠攻破,可是這樣的設計倒是很是差的用戶體驗由於用戶會不容易看到和操做子 ScrollView中的內容。好比好的設計是,父ListView的每一個Item只顯示歸納性的描述,而後點擊其Item會進入另一個頁面來詳細描述 和展現以及對這個Item的操做。
源碼:http://www.jinhusns.com/Products/Download/?type=xcj
因而找到另外兩種比較簡單的方法,並且又沒有影響的:
1.在ScrollView中添加一屬性 android:fillViewport="true" ,這樣就可讓ListView全屏顯示了2.指定ListView的高度 android:layout_height="420dp" ;