Android ListView点击Item展开隐藏项,单个展开,多个展开

时间:2023-01-12 19:38:09

版权声明:^_^ 尊重原创,共享知识,转载请注明"_程序猿大人_"http://blog.csdn.net/a_running_wolf


我做了一些修改


   手机屏幕毕竟有限,当我们要显示较多数据时便不得不舍去一些次要信息,将主要信息优先显示,也使显示效果更加简洁美观。遇到类似的需求,我们使用最多的就是 ListView ,而如果每次点击一个 Item 都要跳转到下一页查看详情,查看另一个还要返回列表重新进入另一条详情,使得操作繁琐体验降低。此时可隐藏和展开 Item 的 ListView 便应运而生,这不是一个新的控件,只是我们灵活使用造出来的用法,下边我就来实现 ListView 点击 Item 展开隐藏项,包括列表单项展开、多项展开、复杂布局展开的实现。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

一、单项展开

   OneExpandActivity 中就是模拟一些数据,使用 OneExpandAdapter 适配器加载:

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

   

private void requestData() {
    ArrayList<HashMap<String, String>> datas = new ArrayList<HashMap<String,String>>();
    for(int i = 1; i <= 10; i++){
        HashMap<String, String> item = new HashMap<String, String>();
        item.put("phoneType", "HTC-M" + i + "");
        item.put("discount", "9");
        item.put("price", (2000 + i) + "");
        item.put("time", "2016020" + i);
        item.put("num", (300 - i) + "");
        datas.add(item);
    }

    ListView lvProduct = (ListView) findViewById(R.id.lv_products);
    OneExpandAdapter adapter = new OneExpandAdapter(this, datas);
    lvProduct.setAdapter(adapter);
}

-------------------------------------------------------------------------------------------------------------------------------

Activity 的布局文件就不看了,只有一个 ListView。我们看 OneExpandAdapter.java:先看 Adapter 用到的布局样式:

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

  1. version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:background="@drawable/shape2"  
  6.     android:orientation="vertical" >  
  7.   
  8.     <LinearLayout  
  9.         android:id="@+id/layout_showArea"  
  10.         android:layout_width="match_parent"  
  11.         android:layout_height="wrap_content"  
  12.         android:orientation="horizontal"  
  13.         android:padding="10dp" >  
  14.   
  15.         <TextView  
  16.             android:id="@+id/tv_phoneType"  
  17.             android:layout_width="wrap_content"  
  18.             android:layout_height="wrap_content"  
  19.             android:text="HTC M8"  
  20.             android:textColor="#162834"  
  21.             android:textSize="25sp" />  
  22.   
  23.         <TextView  
  24.             android:id="@+id/tv_discount"  
  25.             android:layout_width="wrap_content"  
  26.             android:layout_height="wrap_content"  
  27.             android:layout_marginLeft="12dp"  
  28.             android:text="9"  
  29.             android:textColor="#F75252"  
  30.             android:textSize="15sp" />  
  31.   
  32.         <TextView  
  33.             android:layout_width="wrap_content"  
  34.             android:layout_height="wrap_content"  
  35.             android:text="折"  
  36.             android:textColor="#F75252"  
  37.             android:textSize="15sp" />  
  38.   
  39.         <TextView  
  40.             android:id="@+id/tv_price"  
  41.             android:layout_width="wrap_content"  
  42.             android:layout_height="wrap_content"  
  43.             android:layout_marginLeft="100dp"  
  44.             android:text="2000"  
  45.             android:textColor="#F75252"  
  46.             android:textSize="20sp" />  
  47.   
  48.         <TextView  
  49.             android:layout_width="wrap_content"  
  50.             android:layout_height="wrap_content"  
  51.             android:text="¥"  
  52.             android:textColor="#767171"  
  53.             android:textSize="15sp" />  
  54.     </LinearLayout>  
  55.   
  56.     <RelativeLayout  
  57.         android:id="@+id/layout_hideArea"  
  58.         android:layout_width="match_parent"  
  59.         android:layout_height="wrap_content"  
  60.         android:padding="10dp" >  
  61.   
  62.         <TextView  
  63.             android:id="@+id/tv_timeNote"  
  64.             android:layout_width="wrap_content"  
  65.             android:layout_height="wrap_content"  
  66.             android:layout_alignBottom="@+id/tv_time"  
  67.             android:text="活动截止时间:"  
  68.             android:textColor="#162834"  
  69.             android:textSize="12sp" />  
  70.   
  71.         <TextView  
  72.             android:id="@+id/tv_time"  
  73.             android:layout_width="wrap_content"  
  74.             android:layout_height="wrap_content"  
  75.             android:layout_toRightOf="@id/tv_timeNote"  
  76.             android:text="2016.02.10"  
  77.             android:textColor="#F09BED"  
  78.             android:textSize="15sp" />  
  79.   
  80.         <TextView  
  81.             android:id="@+id/tv_numNote"  
  82.             android:layout_width="wrap_content"  
  83.             android:layout_height="wrap_content"  
  84.             android:layout_below="@id/tv_timeNote"  
  85.             android:layout_marginTop="10dp"  
  86.             android:text="库存剩余:"  
  87.             android:textColor="#162834"  
  88.             android:textSize="12sp" />  
  89.   
  90.         <TextView  
  91.             android:id="@+id/tv_num"  
  92.             android:layout_width="wrap_content"  
  93.             android:layout_height="wrap_content"  
  94.             android:layout_alignBottom="@id/tv_numNote"  
  95.             android:layout_below="@id/tv_time"  
  96.             android:layout_toRightOf="@id/tv_numNote"  
  97.             android:gravity="bottom"  
  98.             android:text="888"  
  99.             android:textColor="#F09BED"  
  100.             android:textSize="15sp" />  
  101.   
  102.         <ImageView  
  103.             android:id="@+id/img_icon"  
  104.             android:layout_width="50dp"  
  105.             android:layout_height="50dp"  
  106.             android:layout_alignParentRight="true"  
  107.             android:src="@drawable/red_packet" />  
  108.   
  109.         <Button  
  110.             android:id="@+id/btn_buy"  
  111.             android:layout_width="wrap_content"  
  112.             android:layout_height="wrap_content"  
  113.             android:layout_below="@id/tv_num"  
  114.             android:padding="4dp"  
  115.             android:textSize="24sp"  
  116.             android:layout_alignParentBottom="true"  
  117.             android:layout_centerHorizontal="true"  
  118.             android:background="@drawable/select_btn"  
  119.             android:text="立即抢购" />  
  120.     </RelativeLayout>  
  121. </LinearLayout>  
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 看 Adapter 的代码(总体都还是常规用法,本次用到的逻辑都有注释):

  1. /** 
  2.  * 点击item展开隐藏部分,再次点击收起 
  3.  * 只可展开一条记录 
  4.  *  
  5.  * @author WangJ 
  6.  * @date 2016.01.31 
  7.  */  
  8. public class OneExpandAdapter extends BaseAdapter {  
  9.     private Context context;  
  10.     private ArrayList<HashMap<String, String>> list;  
  11.     private int currentItem = -1//用于记录点击的 Item 的 position,是控制 item 展开的核心  
  12.   
  13.     public OneExpandAdapter(Context context,  
  14.             ArrayList<HashMap<String, String>> list) {  
  15.         super();  
  16.         this.context = context;  
  17.         this.list = list;  
  18.     }  
  19.   
  20.     @Override  
  21.     public int getCount() {  
  22.         return list.size();  
  23.     }  
  24.   
  25.     @Override  
  26.     public Object getItem(int position) {  
  27.         return list.get(position);  
  28.     }  
  29.   
  30.     @Override  
  31.     public long getItemId(int position) {  
  32.         return position;  
  33.     }  
  34.   
  35.     @Override  
  36.     public View getView(final int position, View convertView, ViewGroup parent) {  
  37.         ViewHolder holder = null;  
  38.         if (convertView == null) {  
  39.             convertView = LayoutInflater.from(context).inflate(  
  40.                     R.layout.item_2, parent, false);  
  41.             holder = new ViewHolder();  
  42.             holder.showArea = (LinearLayout) convertView.findViewById(R.id.layout_showArea);  
  43.             holder.tvPhoneType = (TextView) convertView  
  44.                     .findViewById(R.id.tv_phoneType);  
  45.             holder.tvDiscount = (TextView) convertView  
  46.                     .findViewById(R.id.tv_discount);  
  47.             holder.tvPrice = (TextView) convertView  
  48.                     .findViewById(R.id.tv_price);  
  49.             holder.tvTime = (TextView) convertView  
  50.                     .findViewById(R.id.tv_time);  
  51.             holder.tvNum = (TextView) convertView  
  52.                     .findViewById(R.id.tv_num);  
  53.             holder.btnBuy = (Button) convertView  
  54.                     .findViewById(R.id.btn_buy);  
  55.             holder.hideArea = (RelativeLayout) convertView.findViewById(R.id.layout_hideArea);  
  56.               
  57.             convertView.setTag(holder);  
  58.         } else {  
  59.             holder = (ViewHolder) convertView.getTag();  
  60.         }  
  61.   
  62.         HashMap<String, String> item = list.get(position);  
  63.           
  64.         // 注意:我们在此给响应点击事件的区域(我的例子里是 showArea 的线性布局)添加Tag,为了记录点击的 position,我们正好用 position 设置 Tag  
  65.         holder.showArea.setTag(position);  
  66.           
  67.         holder.tvPhoneType.setText(item.get("phoneType"));  
  68.         holder.tvDiscount.setText(item.get("discount"));  
  69.         holder.tvPrice.setText(item.get("price"));  
  70.         holder.tvTime.setText(item.get("time"));  
  71.         holder.tvNum.setText(item.get("num"));  
  72.   
  73.         //根据 currentItem 记录的点击位置来设置"对应Item"的可见性(在list依次加载列表数据时,每加载一个时都看一下是不是需改变可见性的那一条)  
  74.         if (currentItem == position) {  
  75.             holder.hideArea.setVisibility(View.VISIBLE);  
  76.         } else {  
  77.             holder.hideArea.setVisibility(View.GONE);  
  78.         }  
  79.   
  80.         holder.showArea.setOnClickListener(new OnClickListener() {  
  81.   
  82.             @Override  
  83.             public void onClick(View view) {  
  84.                 //用 currentItem 记录点击位置  
  85.                 int tag = (Integer) view.getTag();  
  86.                 if (tag == currentItem) { //再次点击  
  87.                     currentItem = -1//给 currentItem 一个无效值  
  88.                 } else {  
  89.                     currentItem = tag;  
  90.                 }  
  91.                 //通知adapter数据改变需要重新加载  
  92.                 notifyDataSetChanged(); //必须有的一步  
  93.             }  
  94.         });  
  95.         holder.tvPhoneType.setOnClickListener(new OnClickListener() {  
  96.               
  97.             @Override  
  98.             public void onClick(View view) {  
  99.                 Toast.makeText(context, "hehe", Toast.LENGTH_SHORT).show();  
  100.             }  
  101.         });  
  102.         return convertView;  
  103.     }  
  104.   
  105.     private static class ViewHolder {  
  106.         private LinearLayout showArea;  
  107.   
  108.         private TextView tvPhoneType;  
  109.         private TextView tvDiscount;  
  110.         private TextView tvPrice;  
  111.         private TextView tvTime;  
  112.         private TextView tvNum;  
  113.         private Button btnBuy;  
  114.   
  115.         private RelativeLayout hideArea;  
  116.     }  
  117. }  
我们只是 给特定组件 setTag(int position),根据点击的 View 记录下这个 position,在 getView() 中判断当前加载 View 是 position 是不是和记录的 position 相等来进行特定组件的可见性设置 即可。

        这里我们需要明白:我们平时对 ListView 做的最多的操作就是 setOnItemClickListener,这个操作一般都是在 Activity 中进行的,此时响应区域是 Item 整体,不管你点击 Item 的哪个角落都会响应。而对于每个 Item 中子控件的事件监听(区别于整个Item,比如说 Item 中的按钮、输入框等等)都是在适配器类中添加,此时只有点击添加监听的子控件区域才会响应,相当于每个 Item 中的该控件都添加了监听。OnClick 的响应优先级:子控件(元控件)> 父布局(但是不像 onTouch 事件有 Boolean 返回值那样,OnClick 事件是没有返回值的,即是“阻断式式响应”,不会再响应它所归属的上层控件)。

        就不一一的列代码了,多项展开,表格展开的下载地址:http://download.csdn.net/detail/zhanghuaiwang/9912624