版权声明:^_^ 尊重原创,共享知识,转载请注明"_程序猿大人_"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 用到的布局样式:
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- 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:background="@drawable/shape2"
- android:orientation="vertical" >
- <LinearLayout
- android:id="@+id/layout_showArea"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:padding="10dp" >
- <TextView
- android:id="@+id/tv_phoneType"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="HTC M8"
- android:textColor="#162834"
- android:textSize="25sp" />
- <TextView
- android:id="@+id/tv_discount"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="12dp"
- android:text="9"
- android:textColor="#F75252"
- android:textSize="15sp" />
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="折"
- android:textColor="#F75252"
- android:textSize="15sp" />
- <TextView
- android:id="@+id/tv_price"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="100dp"
- android:text="2000"
- android:textColor="#F75252"
- android:textSize="20sp" />
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="¥"
- android:textColor="#767171"
- android:textSize="15sp" />
- </LinearLayout>
- <RelativeLayout
- android:id="@+id/layout_hideArea"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="10dp" >
- <TextView
- android:id="@+id/tv_timeNote"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignBottom="@+id/tv_time"
- android:text="活动截止时间:"
- android:textColor="#162834"
- android:textSize="12sp" />
- <TextView
- android:id="@+id/tv_time"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/tv_timeNote"
- android:text="2016.02.10"
- android:textColor="#F09BED"
- android:textSize="15sp" />
- <TextView
- android:id="@+id/tv_numNote"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/tv_timeNote"
- android:layout_marginTop="10dp"
- android:text="库存剩余:"
- android:textColor="#162834"
- android:textSize="12sp" />
- <TextView
- android:id="@+id/tv_num"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignBottom="@id/tv_numNote"
- android:layout_below="@id/tv_time"
- android:layout_toRightOf="@id/tv_numNote"
- android:gravity="bottom"
- android:text="888"
- android:textColor="#F09BED"
- android:textSize="15sp" />
- <ImageView
- android:id="@+id/img_icon"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:layout_alignParentRight="true"
- android:src="@drawable/red_packet" />
- <Button
- android:id="@+id/btn_buy"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/tv_num"
- android:padding="4dp"
- android:textSize="24sp"
- android:layout_alignParentBottom="true"
- android:layout_centerHorizontal="true"
- android:background="@drawable/select_btn"
- android:text="立即抢购" />
- </RelativeLayout>
- </LinearLayout>
看 Adapter 的代码(总体都还是常规用法,本次用到的逻辑都有注释):
- /**
- * 点击item展开隐藏部分,再次点击收起
- * 只可展开一条记录
- *
- * @author WangJ
- * @date 2016.01.31
- */
- public class OneExpandAdapter extends BaseAdapter {
- private Context context;
- private ArrayList<HashMap<String, String>> list;
- private int currentItem = -1; //用于记录点击的 Item 的 position,是控制 item 展开的核心
- public OneExpandAdapter(Context context,
- ArrayList<HashMap<String, String>> list) {
- super();
- this.context = context;
- this.list = list;
- }
- @Override
- public int getCount() {
- return list.size();
- }
- @Override
- public Object getItem(int position) {
- return list.get(position);
- }
- @Override
- public long getItemId(int position) {
- return position;
- }
- @Override
- public View getView(final int position, View convertView, ViewGroup parent) {
- ViewHolder holder = null;
- if (convertView == null) {
- convertView = LayoutInflater.from(context).inflate(
- R.layout.item_2, parent, false);
- holder = new ViewHolder();
- holder.showArea = (LinearLayout) convertView.findViewById(R.id.layout_showArea);
- holder.tvPhoneType = (TextView) convertView
- .findViewById(R.id.tv_phoneType);
- holder.tvDiscount = (TextView) convertView
- .findViewById(R.id.tv_discount);
- holder.tvPrice = (TextView) convertView
- .findViewById(R.id.tv_price);
- holder.tvTime = (TextView) convertView
- .findViewById(R.id.tv_time);
- holder.tvNum = (TextView) convertView
- .findViewById(R.id.tv_num);
- holder.btnBuy = (Button) convertView
- .findViewById(R.id.btn_buy);
- holder.hideArea = (RelativeLayout) convertView.findViewById(R.id.layout_hideArea);
- convertView.setTag(holder);
- } else {
- holder = (ViewHolder) convertView.getTag();
- }
- HashMap<String, String> item = list.get(position);
- // 注意:我们在此给响应点击事件的区域(我的例子里是 showArea 的线性布局)添加Tag,为了记录点击的 position,我们正好用 position 设置 Tag
- holder.showArea.setTag(position);
- holder.tvPhoneType.setText(item.get("phoneType"));
- holder.tvDiscount.setText(item.get("discount"));
- holder.tvPrice.setText(item.get("price"));
- holder.tvTime.setText(item.get("time"));
- holder.tvNum.setText(item.get("num"));
- //根据 currentItem 记录的点击位置来设置"对应Item"的可见性(在list依次加载列表数据时,每加载一个时都看一下是不是需改变可见性的那一条)
- if (currentItem == position) {
- holder.hideArea.setVisibility(View.VISIBLE);
- } else {
- holder.hideArea.setVisibility(View.GONE);
- }
- holder.showArea.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View view) {
- //用 currentItem 记录点击位置
- int tag = (Integer) view.getTag();
- if (tag == currentItem) { //再次点击
- currentItem = -1; //给 currentItem 一个无效值
- } else {
- currentItem = tag;
- }
- //通知adapter数据改变需要重新加载
- notifyDataSetChanged(); //必须有的一步
- }
- });
- holder.tvPhoneType.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View view) {
- Toast.makeText(context, "hehe", Toast.LENGTH_SHORT).show();
- }
- });
- return convertView;
- }
- private static class ViewHolder {
- private LinearLayout showArea;
- private TextView tvPhoneType;
- private TextView tvDiscount;
- private TextView tvPrice;
- private TextView tvTime;
- private TextView tvNum;
- private Button btnBuy;
- private RelativeLayout hideArea;
- }
- }
这里我们需要明白:我们平时对 ListView 做的最多的操作就是 setOnItemClickListener,这个操作一般都是在 Activity 中进行的,此时响应区域是 Item 整体,不管你点击 Item 的哪个角落都会响应。而对于每个 Item 中子控件的事件监听(区别于整个Item,比如说 Item 中的按钮、输入框等等)都是在适配器类中添加,此时只有点击添加监听的子控件区域才会响应,相当于每个 Item 中的该控件都添加了监听。OnClick 的响应优先级:子控件(元控件)> 父布局(但是不像 onTouch 事件有 Boolean 返回值那样,OnClick 事件是没有返回值的,即是“阻断式式响应”,不会再响应它所归属的上层控件)。
就不一一的列代码了,多项展开,表格展开的下载地址:http://download.csdn.net/detail/zhanghuaiwang/9912624