ScrollView下,ListView重複呼叫getview解決方案
首先講一下我遇到的需求吧,頁面是這樣的,上邊有東西,中間是列表,下邊還有東西。首先我看到列表立刻就想到了用ListView,但是頁面有限,只能用ScrollView包一下。想到就做唄。我就在ScrollView裡面加了一個ListView, ListView設定的是wapcontent,這樣就出現了ListView資料只顯示出了一行。好的,解決問題的方案就來了。
一.設定scrollView中的ListView內容全部顯示,不能滑動,將滑動交給scrollView去做。
做法:在設定adapter之前,重新計算ListView的高度,我這裡寫了一個方法:
[html]
- /**
- * 動態設定listView的高度
- * count 總條目
- */
- private void setListViewHeight(ListView listView, BaseAdapter adapter,
- int count) {
- int totalHeight = 0;
- for (int i = 0; i < count; i++) {
- View listItem = adapter.getView(i, null, listView);
- listItem.measure(0, 0);
- totalHeight += listItem.getMeasuredHeight();
- }
- ViewGroup.LayoutParams params = listView.getLayoutParams();
- params.height = totalHeight + (listView.getDividerHeight() * count);
- listView.setLayoutParams(params);
- }
這樣做的前提條件是佈局檔案中ListView的高度要指定,這樣才能重新計算,不要設成wapcontent!
二.不全部展示資料,二者皆可滑動。
此方法不用重新計算ListView的高度,只需焦點在Listview上的時候,ScrollView能把滑動權主動交給Listview,這樣需要重寫ScrollView的一個方法,如下:
[html] view plain copy- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- return false;
- }
這樣Scrollview就會根據焦點而讓出滑動事件。
三. 不重新計算ListView的高度,展示所有資料,ListView不可滑動。
這個做法是重寫ListView的onMeasure方法,如下:
[html] view plain copy- /**
- * 設定不滾動
- */
- public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
- {
- int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
- MeasureSpec.AT_MOST);
- super.onMeasure(widthMeasureSpec, expandSpec);
- }
這種方法是同事告訴我的,我沒有用過。
做到這裡,ScrollView和ListView的問題是解決了,但是ListView的效率問題出現了。
你會發現在ListView的adapter裡的getview方法重複執行了很多次,技術使用了快取技術也是無用的。
有時候資料只有兩三個,但是getView方法卻被執行了40多次。這樣肯定是不行的。但是為什麼單獨使用ListView的時候卻不會出現這種問題呢?
這個原因肯定出在ScrollView和ListView共存上。Google了一下,外國人都不建議他們共存,但是需求是這樣的怎麼辦呢?
我的最終解決方案:自己寫一個類似ListView的東西
一. 最初:[html] view plain copy
- /**
- * 虛擬listview
- *
- * @author JustMe
- *
- */
- public class MyListView extends LinearLayout {
- private BaseAdapter adapter;
- private MyOnItemClickListener onItemClickListener;
- /**
- * 通知更新listview
- */
- public void notifyChange() {
- int count = getChildCount();
- 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() {
- @Override
- public void onClick(View v) {
- if (onItemClickListener != null) {
- onItemClickListener.onItemClick(MyListView.this,
- layout, index, adapter.getItem(index));
- }
- }
- });
- // 每個條目下面的線
- ImageView imageView = new ImageView(getContext());
- imageView.setBackgroundResource(R.drawable.divider_list);
- imageView.setLayoutParams(params);
- layout.addView(v);
- layout.addView(imageView);
- addView(layout, index);
- }
- }
- public MyListView(Context context) {
- super(context);
- initAttr(null);
- }
- public MyListView(Context context, AttributeSet attrs) {
- super(context, attrs);
- initAttr(attrs);
- }
- /**
- * 設定方向
- *
- * @param attrs
- */
- public void initAttr(AttributeSet attrs) {
- setOrientation(VERTICAL);
- }
- public BaseAdapter getAdapter() {
- return adapter;
- }
- /**
- * 設定adapter並模擬listview新增資料
- *
- * @param adpater
- */
- public void setAdapter(BaseAdapter adpater) {
- this.adapter = adpater;
- notifyChange();
- }
- /**
- * 設定條目監聽事件
- *
- * @param onClickListener
- */
- public void setOnItemClickListener(MyOnItemClickListener onClickListener) {
- this.onItemClickListener = onClickListener;
- }
- /**
- * 點選事件監聽
- *
- * @author JustMe
- *
- */
- public static interface MyOnItemClickListener {
- public void onItemClick(ViewGroup parent, View view, int position,
- Object o);
- }
- }
缺點是不能一次載入很多的資料,不然資料會顯示的很慢,最好分頁載入。說到分頁,之前都是在ListView上加footerView,在這裡也可以做到。
二. 升級:
[html] view plain copy- public class MyListView extends LinearLayout{
- private BaseAdapter adapter;
- private MyOnItemClickListener onItemClickListener;
- boolean footerViewAttached = false;
- private View footerview;
- /**
- * 通知更新listview
- */
- 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() {
- @Override
- public void onClick(View v) {
- if (onItemClickListener != null) {
- onItemClickListener.onItemClick(MyListView.this, layout, index,
- adapter.getItem(index));
- }
- }
- });
- ImageView imageView = new ImageView(getContext());
- imageView.setBackgroundResource(R.drawable.divider_list);
- imageView.setLayoutParams(params);
- layout.addView(v);
- layout.addView(imageView);
- addView(layout, index);
- }
- }
- public MyListView(Context context) {
- super(context);
- initAttr(null);
- }
- public MyListView(Context context, AttributeSet attrs) {
- super(context, attrs);
- initAttr(attrs);
- }
- public void initAttr(AttributeSet attrs) {
- setOrientation(VERTICAL);
- }
- /**
- * 初始化footerview
- *
- * @param footerView
- */
- public void initFooterView(final View footerView) {
- this.footerview = footerView;
- }
- /**
- * 設定footerView監聽事件
- *
- * @param onClickListener
- */
- public void setFooterViewListener(OnClickListener onClickListener) {
- this.footerview.setOnClickListener(onClickListener);
- }
- public BaseAdapter getAdapter() {
- return adapter;
- }
- /**
- * 設定adapter並模擬listview新增????資料
- *
- * @param adpater
- */
- public void setAdapter(BaseAdapter adpater) {
- this.adapter = adpater;
- removeAllViews();
- if (footerViewAttached)
- addView(footerview);
- notifyChange();
- }
- /**
- * 設定條目監聽事件
- *
- * @param onClickListener
- */
- 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) {
- addView(footerview);
- footerViewAttached = true;
- }
- }
- public static interface MyOnItemClickListener {
- public void onItemClick(ViewGroup parent, View view, int position, Object o);
- }
- }
個人測試結果:非常好用使用方法:跟listview使用一樣,只是重新整理方法不同,首先重新整理adater資料來源,再重新設定下其adapter。