zoukankan      html  css  js  c++  java
  • ListView多选和单选模式重新整理

    •    超简单的单选和多选ListView

        在开发过程中,我们经常会使用ListView去呈现列表数据,比如商品列表,通话记录,联系人列表等等,在一些情况下,我们还需要去选择其中的一些列表数据进行编辑。以前,我在项目开发中,都是在自定义的Adapter中去维护一个SparseBooleanArray变量来保存当前ListView中已经被选中的项,然后在自定义Adapter的getView()和ListView的setOnItemClickListener()方法中去实时更新SparseBooleanArray变量,从而当用户选择提交数据的时候,直接遍历SparseBooleanArray中的值就可以了,这种做法,虽然也能实现功能,但是无疑增加了代码开销。

        今天,在看文档的时候,发现了一个更好的解决方案(很多人已经用过了吧):使用ListView的choiceMode,官方文档见如下:

                             


        根据上面的文档说明,可以知道,android:choiceMode有以下几个值:默认(不设置android:choiceMode属性,即不支持单选或多选),singleChoice(单选),multipleChoice(多选),mutipleChoiceModal(特殊多选模式,可以通过设置MultiChoiceModeListener进行监听选择模式,类似ActionBar的ActionMode)。在XML中给ListView设置了android:choiceMode属性一个值后,我们还需要给ListView一个适配器,这里我们使用默认的ArrayAdapter:

     

        //如果是单选模式,则可以使用 android.R.layout.simple_list_item_single_choice
        ArrayAdapter<String> myAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_multiple_choice, mDatas);
        mListView.setAdapter(myAdapter);


        这样我们就已经完成了ListView的多选或单选实现。

        另外一个问题是:我们怎样才能获取当前ListView中被选中的那些项呢?

        我们其实可以通过ListView的isItemChecked(int position)方法判断一项是否被选中,或直接使用ListView.getCheckedItemPositions()来获取所有选中的项,这个方法返回一个SparseBooleanArray对象,遍历它就可以获取所有选中的项。

    • 自定义ListView的多选和单选项布局


      对于一些简单的列表,上面的方法可能已经能够满足需求。其实,上面的列表项只显示了一个标题和一个复选框,但在实际开发中,UE或产品经理可能要求我们去实现的列表远比上面的列表复杂得多,所以往往就需要使用自定义的Adapter来填充ListView。

         但是,如果我们使用自定义的Adapter来填充ListView,那怎么让我们自定义的Checkbox能够无缝衔接ListView的选择状态呢?

         一种普遍的做法是在重写自定义Adapter的getView()时,先通过convertView.findViewById()获取到Checkbox后,通过mList.isItemChecked(int position)判断当前position的状态后,再去更新Checkbox的选择状态。

         这里,我介绍的是另外一种方法。
         首先,我们先来看下为什么我们使用android.R.layout.simple_list_item_multiple_choice布局来填充ArrayAdapter时,不需要我们自己去维护CheckBox的选择状态?
         查看ListView的源码,在ListView的setupChild方法中,有下面的一段代码:
        

        if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {
            if (child instanceof Checkable) {
                ((Checkable) child).setChecked(mCheckStates.get(position));
            } else if (getContext().getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.HONEYCOMB)
           {
               child.setActivated(mCheckStates.get(position));
           }
        }


       即如果ListView的child(从自定义的Adapter的getView()方法中返回的View)实现了Checkable接口,那么当listView的项选择状态改变时,listView也会去同步更新这个child的状态(android 3.1或3.1以上平台,会触发setActivated方法),其实simple_list_item_multiple_choice.xml中只有一个CheckedTextView
      

    <CheckedTextView          
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@android:id/text1"
        android:layout_width="match_parent"    
        android:layout_height="?android:attr/listPreferredItemHeightSmall"
        android:textAppearance="?android:attr/textAppearanceListItemSmall"
        android:gravity="center_vertical"
        android:checkMark="?android:attr/listChoiceIndicatorMultiple"
        android:paddingStart="?android:attr/listPreferredItemPaddingStart"
        android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" />


        而CheckedTextView 是实现了Checkable接口的,所以当我们使用simple_list_item_multiple_choic.xml布局作为Adapter的getView()的返回值时,是不需要我们额外去关心Checkbox的状态问题。
        通过上面的分析,我们自定义一个View时,只需要实现了Checkable接口,那么就不用我们在getView中去额外维护选中状态了。如果android3.1或android3.1以上的平台,我们还可以重写setActivated方法来更新我们的选中状态。相关示例代码如下:

    package com.shaoxiong.li.marvel.myapplication;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.widget.CheckBox;
    import android.widget.Checkable;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    
    /**
     * Created by lishaoxiong on 16-2-22.
     */
    public class CustomCheckTextView extends LinearLayout implements Checkable {
    
        private TextView titleView;
        private CheckBox mCheckBox;
    
        public CustomCheckTextView(Context context) {
            this(context, null);
        }
    
        public CustomCheckTextView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public CustomCheckTextView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
    
    
            LayoutInflater mLayoutInflater = LayoutInflater.from(context);
            //将加载出来的View添加到当前View层级中去。
            //有两种方案,一种是加载布局时将rootView传进去,或直接使用addView添加进去
            //View v = mLayoutInflater.inflate(R.layout.layout_custom_ctv, null);
            View v = mLayoutInflater.inflate(R.layout.layout_custom_ctv, this, true);
            titleView = (TextView)v.findViewById(R.id.headListView_item_text);
            mCheckBox = (CheckBox)v.findViewById(R.id.headListView_item_cb);
            //this.addView(v);
        }
    
        @Override
        public void setChecked(boolean checked) {
            mCheckBox.setChecked(checked);
        }
    
        @Override
        public boolean isChecked() {
            return mCheckBox.isChecked();
        }
    
        @Override
        public void toggle() {
            mCheckBox.toggle();
        }
    
        public void setTitle(String title) {
            titleView.setText(title);
        }
    
        @Override
        public void setActivated(boolean activated) {
            super.setActivated(activated);
        }
    }
    <?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="match_parent"
       android:orientation="horizontal"
       android:padding="20dp">
        <CheckBox
            android:id="@+id/headListView_item_cb"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:focusable="false"
            android:clickable="false"
            android:focusableInTouchMode="false"/>
    
        <TextView
           android:id="@+id/headListView_item_text"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_marginRight="10dp"/>
    
    
    </LinearLayout>
        public class MyAdapter extends BaseAdapter {
    
            private Context mContext;
            private ArrayList<String> dataList;
    
            public MyAdapter(Context context, ArrayList<String> dataList) {
                this.mContext = context;
                this.dataList= dataList;
            }
    
            @Override
            public int getCount() {
                return dataList.size();
            }
    
            @Override
            public Object getItem(int position) {
                return dataList.get(position);
            }
    
            @Override
            public long getItemId(int position) {
                return position;
            }
    
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                ViewHolder viewHolder = null;
                if(convertView == null) {
                    convertView = LayoutInflater.from(mContext).inflate(R.layout.item_headlistview, null);
                    viewHolder = new ViewHolder();
                    //viewHolder.mTextView = (TextView)convertView.findViewById(R.id.headListView_item_text);
    //                viewHolder.checkedTv = (CheckedTextView)convertView.findViewById(R.id.item_checked_tv);
                    viewHolder.customCheckTextView = (CustomCheckTextView)convertView;
                    convertView.setTag(viewHolder);
                }else {
                    viewHolder = (ViewHolder)convertView.getTag();
                }
    //            viewHolder.checkedTv.setText(dataList.get(position));
    //            viewHolder.mTextView.setText(dataList.get(position));
                viewHolder.customCheckTextView.setTitle(dataList.get(position));
                return convertView;
            }
        }
    
        static class ViewHolder {
    //        TextView mTextView;
    //        CheckedTextView checkedTv;
            CustomCheckTextView customCheckTextView;
        }

      

        这样,通过上面的方法,你就可以去实现各种自己自定义好布局的多选或单选列表了。

  • 相关阅读:
    [cf582E]Boolean Function
    [atAGC029F]Construction of a tree
    [atAGC020E]Encoding Subsets
    [gym102769L]Lost Temple
    [atAGC034E]Complete Compress
    [cf566E]Restoring Map
    [atAGC023F]01 on Tree
    [gym102822I]Invaluable Assets
    [gym102900H]Rice Arrangement
    [Offer收割]编程练习赛32
  • 原文地址:https://www.cnblogs.com/xiaoyang2009/p/5209325.html
Copyright © 2011-2022 走看看