ListView Item 選擇問題解決之道

傲慢的上校發表於2012-06-21

         在Android應用開發中,很多時候都會遇到這樣的需求,一個listView,含有N項,當點選某項時,該項展開,顯示該項中隱藏的某些控制元件,再點選,該項收回,重新隱藏部分控制元件,當一項開啟狀態,點選另一項,另一項展開,該項關閉。(說的有點繞,看下圖) 


        在去年的時候,自己的一篇文章http://blog.csdn.net/aomandeshangxiao/article/details/6643831),裡面有Item的選擇問題,用的方法比較笨,要遍歷一遍,把所有的item全部都設定一下,應該是很浪費資源的。還有一個問題就是,當listview的item多於一個螢幕的時候,會出現重複選擇問題,就是當你選中一項滑動的時候,可能會發現滑動後出現的某項也是在選中狀態,這個問題令人十分抓狂。見網上有個方法是:在adapter的getView裡面不使用convertview。每一個view都是重新建立一個。能夠解決問題,但是還是有點浪費資源。

        

        先看下效果圖:第二項被選中


第四項被選中:



        這個方法也是在他人的幫助下,努力得來,分享一下!

public class ListViewTestActivity extends Activity implements OnItemClickListener{
	private ListView mListView;
	private ListAdapter mAdapter;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        mListView = (ListView)findViewById(R.id.list);
        mAdapter = new  ListAdapter(this);
        mListView.setAdapter(mAdapter);
        mListView.setOnItemClickListener(this);
    }
    
	@Override
	public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
		mAdapter.changeImageVisable(view, position);
	}
}

        這裡應該注意到與平常的不同,onItemClick方法裡面呼叫了自定義ListAdapter裡面的自定義changeImageViewVisable方法。

看ListAdapter:

public class ListAdapter extends BaseAdapter {
	private Context mContext;
	private View mLastView;
	private int mLastPosition;
	
	public ListAdapter(Context context) {
		this.mContext = context;
	}

	@Override
	public int getCount() {
		return 8;
	}

	@Override
	public Object getItem(int position) {
		return null;
	}

	@Override
	public long getItemId(int position) {
		return 0;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		Holder holder;
		if(convertView == null ) {
			LayoutInflater inflater = LayoutInflater.from(mContext);
			convertView = inflater.inflate(R.layout.list_item, null);
			holder =new Holder();
			holder.textView = (TextView)convertView.findViewById(R.id.textView);
			holder.UEFAView = (ImageView)convertView.findViewById(R.id.image_uefa);
			holder.mascotView = (ImageView)convertView.findViewById(R.id.image_mascot);
			holder.hint = convertView.findViewById(R.id.hint_image);
			convertView.setTag(holder);
		} else {
			holder = (Holder) convertView.getTag();
		}
		holder.textView.setText("Hello,It is " + position);
		return convertView;
	}
	
	class Holder {
		TextView textView;
		ImageView UEFAView;
		ImageView mascotView;
		View hint;
	}
	
	public void changeImageVisable(View view,int position) {
		if(mLastView != null && mLastPosition != position ) {
			Holder holder = (Holder) mLastView.getTag();
			switch(holder.hint.getVisibility()) {
			case View.VISIBLE:
				holder.hint.setVisibility(View.GONE);
				break;
			default :
				break;
			}
		}
		mLastPosition = position;
        mLastView = view;
        Holder holder = (Holder) view.getTag();
		switch(holder.hint.getVisibility()) {
		case View.GONE:
			holder.hint.setVisibility(View.VISIBLE);
			break;
		case View.VISIBLE:
			holder.hint.setVisibility(View.GONE);
			break;
		}
	}

}

          程式碼的最下端是changeImageVisable方法。(注意:在這個方法中,部落格程式碼版本和提供下載程式碼版本中有細微差異,部落格程式碼較下載程式碼效能更優,這也體現了Holder類的優越性,一定要好好用好Holder,應好好思考下,為什麼這樣寫效能就更好些呢?歡迎留言討論)。

        佈局檔案:

main.xml:

<?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="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="ListView Test" />
    <ListView 
        android:id="@+id/list"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        ></ListView>

</LinearLayout>

list_item.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    >
    <TextView 
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Test"
        android:textSize="20sp"
        />
    <LinearLayout
        android:id="@+id/hint_image"
    	android:layout_width="match_parent"
    	android:layout_height="wrap_content"
    	android:orientation="horizontal"
    	android:visibility="gone">
        <ImageView 
            android:id="@+id/image_uefa"
            android:layout_width="0dp"
            android:layout_height="60dp"
            android:layout_weight="1"
            android:src="@drawable/uefa"
            />
        <ImageView 
            android:id="@+id/image_mascot"
            android:layout_width="0dp"
            android:layout_height="60dp"
            android:layout_weight="1"
            android:src="@drawable/mascot"
            />
        
    </LinearLayout>
    
</LinearLayout>

         佈局只是簡單的寫了下,弄了兩張歐洲盃的圖。

      最後程式碼下載地址:http://download.csdn.net/detail/aomandeshangxiao/4384922

        如果是有所幫助,在下面微微頂一個吧。

      其實這樣做的話,如果多於一屏,還是會出現問題。有沒有參與討論的???

      如果ListView的Item裡面有Button,想要響應OnItemClickListener()方法,加上:

android:descendantFocusability= "blocksDescendants"




       改動如下:

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class ListAdapter extends BaseAdapter {
	private Context mContext;
	private int mLastPosition = -1;
	
	public ListAdapter(Context context) {
		this.mContext = context;
	}

	@Override
	public int getCount() {
		return 100;
	}

	@Override
	public Object getItem(int position) {
		return null;
	}

	@Override
	public long getItemId(int position) {
		return 0;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		Holder holder = new Holder();;
		if(convertView == null ) {
			LayoutInflater inflater = LayoutInflater.from(mContext);
			convertView = inflater.inflate(R.layout.list_item, null);
			holder.textView = (TextView)convertView.findViewById(R.id.textView);
			holder.UEFAView = (ImageView)convertView.findViewById(R.id.image_uefa);
			holder.mascotView = (ImageView)convertView.findViewById(R.id.image_mascot);
			holder.hint = convertView.findViewById(R.id.hint_image);
			convertView.setTag(holder);
		} else {
			holder = (Holder) convertView.getTag();
		}
		holder.textView.setText("Hello,It is " + position);
		if (position == mLastPosition) {
		    holder.hint.setVisibility(View.VISIBLE);
		} else {
		    holder.hint.setVisibility(View.GONE);
		}
		return convertView;
	}
	
	class Holder {
		TextView textView;
		ImageView UEFAView;
		ImageView mascotView;
		View hint;
	}
	
	public void changeImageVisable(int position) {
	    if(position != mLastPosition) {
	        mLastPosition = position;
	    } else {
	        mLastPosition = -1;
	    }
	    notifyDataSetChanged();
	}
}


思考一下,有何不同?


     

相關文章