HardBirch

ListView Item 选择问题解决之道

时间:12-06-21 栏目:安卓源码解析与小应用 作者:张飞不张,文采横飞 评论:28 点击: 11,757 次

         在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();
	}
}

思考一下,有何不同?



     

声明: 本文由( 张飞不张,文采横飞 )原创编译,转载请保留链接: ListView Item 选择问题解决之道

ListView Item 选择问题解决之道:目前有28 条留言

  1. 28楼
    w1041966246:

    楼主 在Android应用开发中,很多时候都会遇到这样的需求,一个listView,含有N项,当点击某项时,该项展开,显示该项中隐藏的某些控件, 这些隐藏控件 如有Button 可以对Button进行监听吗??

    2012-06-21 12:18 [回复]
  2. [reply]w1041966246[/reply]
    你可以在自定义的Adapter里给button 设置onclick事件就能实现,但是有个问题,当item 里面有button的时候,注意焦点问题。

    2012-06-21 14:22 [回复]
  3. 学习了。加油哈。

    2012-06-23 19:08 [回复]
  4. 25楼
    liushanbo:

    学习中。。。

    2012-06-24 16:00 [回复]
  5. [reply]liushanbo[/reply]
    其实还是有问题的,待会修改一下。

    2012-06-24 20:52 [回复]
  6. [reply]liutengteng130[/reply]
    一直在加油。。。

    2012-06-24 20:53 [回复]
  7. 22楼
    xdhyan:

    学习了。加油哈。

    2012-06-25 09:14 [回复]
  8. [reply]xdhyan[/reply]
    谢谢鼓励,呵呵。。。

    2012-06-25 09:24 [回复]
  9. 20楼
    panjidong_3:

    还有个方法,你holder所使用的xml最外层的LinearLayout把它实例化出来,直接对这个LinearLayout的OnclickListener进行监听判断就好了。

    2012-06-27 17:28 [回复]
  10. [reply]panjidong_3[/reply]
    这样可以吗?我试一下吧,倒是第一次听说这个方法。

    2012-06-27 17:59 [回复]
  11. [reply]panjidong_3[/reply]
    没有试验出来,不知道能否给个示例看看。还是说,您凭空那么想出来的呢???

    2012-06-27 18:29 [回复]
  12. 17楼
    panjidong_3:

    [reply]aomandeshangxiao[/reply]
    我帮同事解决这个问题的时候试过了,就是这个问题当时有一个局限就是listView里面的一个item占用的布局一开始getview调用的时候就固定了,点击后剩下的view虽然状态设置为visible,但是还是不显示。当时我的adapter里面是加了List<User>作为holder的数据,然后User是提供给holder用的,解决方法是点击项后改变User的表示然后调用adapter的notifyDataSetChanged,在adapte的getView里面判断这个标示,来设置那块特殊的区域是否显示。

    (呵呵,你这边也是用这个原理在getView里面判断的,就是我是用holder项的点击事件来做触发,你是用listView的item选择事件作为触发)

    2012-06-28 14:37 [回复]
  13. 16楼
    panjidong_3:

    [reply]aomandeshangxiao[/reply]
    我这个方法可以多个holder都有展开效果,嘿嘿!

    2012-06-28 14:39 [回复]
  14. [reply]panjidong_3[/reply]
    哦,些许有些明白了。。。

    2012-06-29 20:35 [回复]
  15. 14楼
    hellokugoo:

    在changeImageVisable 最后加上notifyDataSetChanged会发生奇怪的错误~~

    2012-07-12 17:29 [回复]
  16. [reply]hellokugoo[/reply]
    什么错误阿,我的代码错误吗??

    2012-07-12 18:09 [回复]
  17. 12楼
    hellokugoo:

    [reply]aomandeshangxiao[/reply]
    是的~如果加上在changeImageVisable 最后加上notifyDataSetChanged显示的效果是这样子的:第一次点击0:7展开,第二次:0展开,第三次:7隐藏,第四次:0隐藏.其他行也是

    2012-07-17 10:25 [回复]
  18. [reply]hellokugoo[/reply]
    是使用我改动以后的代码吗?
    提供下载的那个代码是有这个问题的,但是,我文章的最后不适有改动吗?使用改动以后的代码,就没有这个问题了。

    2012-07-17 12:00 [回复]
  19. 10楼
    hellokugoo:

    [reply]aomandeshangxiao[/reply]
    确实~用了改动后的没有问题了~谢谢楼主分享~

    2012-07-17 17:19 [回复]
  20. [reply]hellokugoo[/reply]
    呵呵,还好,没有误导你。。。

    2012-07-17 17:59 [回复]
  21. notifyDataSetChanged()方法会强制刷新所有的item,有没有什么办法我只刷新当前点击的item

    2012-09-27 13:33 [回复]
  22. [reply]wangyl19890106[/reply]
    没有好的办法。你有什么好办法吗
    ??

    2012-09-27 14:15 [回复]
  23. Lz,你试下将长度 8 改为 20 ,然后点第一项,再然后滚动到底部点击最后一项,在滑动上去看看… 这个问题有好办法解决吗?

    2012-10-19 20:01 [回复]
  24. [reply]libei_march[/reply]
    你真的把这篇文章看完了吗?

    2012-10-21 19:02 [回复]
  25. [reply]libei_march[/reply]
    不好意思,中间那段没怎么注意看.心思放在代码上面了,最近项目里面碰到这种问题了,就是多于一屏的时候总是有bug,ListView.getChildCount(); 只能返回可视范围之内的子元素数量,导致程序无法按逻辑走. 找了很久资料了也没找到解决方案. 不知道Lz有没进展? 希望不吝赐教,谢谢.

    2012-10-21 22:30 [回复]
  26. 地板
    wang_yubin:

    这问题我也遇到了,用了一个boolean一个int,解决了,晚上回去分享下,原理一样,,,,只恨当初没看到此贴,,,,

    2012-10-24 10:00 [回复]
  27. [reply]wang_yubin[/re呵呵,好!

    2012-10-24 11:23 [回复]

发表评论


QQ群互动

Linux系统与内核学习群:194051772

WP建站技术学习交流群:194062106

魔豆之路QR

魔豆的Linux内核之路

魔豆的Linux内核之路

优秀工程师当看优秀书籍

优秀程序员,要看优秀书!

赞助商广告

友荐云推荐