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

一、效果图

单项展开:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="单项展开">

多项展开:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="多项展开">

复杂布局时的实现:

二、单项展开

直接上代码,没有难度,OneExpandActivity 中就是模拟一些数据,使用 OneExpandAdapter 适配器载入:

  1. public class OneExpandActivity extends Activity {
  2.  
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_one_expand);
  7. requestData();
  8. }
  9.  
  10. private void requestData() {
  11. ArrayList<HashMap<String, String>> datas = new ArrayList<HashMap<String,String>>();
  12. for(int i = 1; i <= 10; i++){
  13. HashMap<String, String> item = new HashMap<String, String>();
  14. item.put("phoneType", "HTC-M" + i + "");
  15. item.put("discount", "9");
  16. item.put("price", (2000 + i) + "");
  17. item.put("time", "2016020" + i);
  18. item.put("num", (300 - i) + "");
  19. datas.add(item);
  20. }
  21.  
  22. ListView lvProduct = (ListView) findViewById(R.id.lv_products);
  23. OneExpandAdapter adapter = new OneExpandAdapter(this, datas);
  24. lvProduct.setAdapter(adapter);
  25. }
  26. }

Activity 的布局文件就不看了,仅仅有一个 ListView。

我们看 OneExpandAdapter.java:

先看 Adapter 用到的布局样式:

  1. <?xml version="1.0" encoding="utf-8"?
  2.  
  3. >
  4. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. android:background="@drawable/shape2"
  8. android:orientation="vertical" >
  9.  
  10. <LinearLayout
  11. android:id="@+id/layout_showArea"
  12. android:layout_width="match_parent"
  13. android:layout_height="wrap_content"
  14. android:orientation="horizontal"
  15. android:padding="10dp" >
  16.  
  17. <TextView
  18. android:id="@+id/tv_phoneType"
  19. android:layout_width="wrap_content"
  20. android:layout_height="wrap_content"
  21. android:text="HTC M8"
  22. android:textColor="#162834"
  23. android:textSize="25sp" />
  24.  
  25. <TextView
  26. android:id="@+id/tv_discount"
  27. android:layout_width="wrap_content"
  28. android:layout_height="wrap_content"
  29. android:layout_marginLeft="12dp"
  30. android:text="9"
  31. android:textColor="#F75252"
  32. android:textSize="15sp" />
  33.  
  34. <TextView
  35. android:layout_width="wrap_content"
  36. android:layout_height="wrap_content"
  37. android:text="折"
  38. android:textColor="#F75252"
  39. android:textSize="15sp" />
  40.  
  41. <TextView
  42. android:id="@+id/tv_price"
  43. android:layout_width="wrap_content"
  44. android:layout_height="wrap_content"
  45. android:layout_marginLeft="100dp"
  46. android:text="2000"
  47. android:textColor="#F75252"
  48. android:textSize="20sp" />
  49.  
  50. <TextView
  51. android:layout_width="wrap_content"
  52. android:layout_height="wrap_content"
  53. android:text="¥"
  54. android:textColor="#767171"
  55. android:textSize="15sp" />
  56. </LinearLayout>
  57.  
  58. <RelativeLayout
  59. android:id="@+id/layout_hideArea"
  60. android:layout_width="match_parent"
  61. android:layout_height="wrap_content"
  62. android:padding="10dp" >
  63.  
  64. <TextView
  65. android:id="@+id/tv_timeNote"
  66. android:layout_width="wrap_content"
  67. android:layout_height="wrap_content"
  68. android:layout_alignBottom="@+id/tv_time"
  69. android:text="活动截止时间:"
  70. android:textColor="#162834"
  71. android:textSize="12sp" />
  72.  
  73. <TextView
  74. android:id="@+id/tv_time"
  75. android:layout_width="wrap_content"
  76. android:layout_height="wrap_content"
  77. android:layout_toRightOf="@id/tv_timeNote"
  78. android:text="2016.02.10"
  79. android:textColor="#F09BED"
  80. android:textSize="15sp" />
  81.  
  82. <TextView
  83. android:id="@+id/tv_numNote"
  84. android:layout_width="wrap_content"
  85. android:layout_height="wrap_content"
  86. android:layout_below="@id/tv_timeNote"
  87. android:layout_marginTop="10dp"
  88. android:text="库存剩余:"
  89. android:textColor="#162834"
  90. android:textSize="12sp" />
  91.  
  92. <TextView
  93. android:id="@+id/tv_num"
  94. android:layout_width="wrap_content"
  95. android:layout_height="wrap_content"
  96. android:layout_alignBottom="@id/tv_numNote"
  97. android:layout_below="@id/tv_time"
  98. android:layout_toRightOf="@id/tv_numNote"
  99. android:gravity="bottom"
  100. android:text="888"
  101. android:textColor="#F09BED"
  102. android:textSize="15sp" />
  103.  
  104. <ImageView
  105. android:id="@+id/img_icon"
  106. android:layout_width="50dp"
  107. android:layout_height="50dp"
  108. android:layout_alignParentRight="true"
  109. android:src="@drawable/red_packet" />
  110.  
  111. <Button
  112. android:id="@+id/btn_buy"
  113. android:layout_width="wrap_content"
  114. android:layout_height="wrap_content"
  115. android:layout_below="@id/tv_num"
  116. android:padding="4dp"
  117. android:textSize="24sp"
  118. android:layout_alignParentBottom="true"
  119. android:layout_centerHorizontal="true"
  120. android:background="@drawable/select_btn"
  121. android:text="马上抢购" />
  122. </RelativeLayout>
  123. </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 中的button、输入框等等)都是在适配器类中加入,此时仅仅有点击加入监听的子控件区域才会响应,相当于每一个 Item 中的该控件都加入了监听。OnClick
的响应优先级:子控件(元控件)> 父布局(可是不像 onTouch 事件有 Boolean 返回值那样,OnClick 事件是没有返回值的。即是“阻断式式响应”,不会再响应它所归属的上层控件)。

搞定!

是不是比你想象中的简单呢?以下我们继续看多项 Item 展开咋实现。

三、多项展开

事实上和单项展开非常像,仅仅是在就点击位置和 getView() 中载入时决定可见性的推断有点小差别而已。所以 Activity 就不看了(使用的 adapter 改成下边这个就能够了)。adapter 用的布局还是上边那个,看 MultiExpandAdapter 代码:

  1. /**
  2. * 点击item展开隐藏部分,再次点击收起 可展开多条 Item
  3. *
  4. * @author WangJ
  5. * @date 2016.02.01
  6. */
  7. public class MultiExpandAdapter extends BaseAdapter {
  8. private Context context;
  9. private ArrayList<HashMap<String, String>> list;
  10. private boolean[] showControl; // 用一个布尔数组记录list中每一个item是否要展开
  11.  
  12. public MultiExpandAdapter(Context context,
  13. ArrayList<HashMap<String, String>> list) {
  14. super();
  15. this.context = context;
  16. this.list = list;
  17. showControl = new boolean[list.size()]; // 构造器中初始化布尔数组
  18. }
  19.  
  20. /**
  21. * 省略别的 @Override 方法
  22. */
  23.  
  24. @Override
  25. public View getView(final int position, View convertView, ViewGroup parent) {
  26. ViewHolder holder = null;
  27. if (convertView == null) {
  28. convertView = LayoutInflater.from(context).inflate(R.layout.item_2,
  29. parent, false);
  30. /**
  31. * 省略 findView 方法
  32. */
  33. convertView.setTag(holder);
  34. } else {
  35. holder = (ViewHolder) convertView.getTag();
  36. }
  37.  
  38. final HashMap<String, String> item = list.get(position);
  39.  
  40. // 注意:我们在此给响应点击事件的区域(我的样例里是 showArea 的线性布局)加入Tag,
  41. // 为了记录点击的 position。我们正好用position 设置 Tag
  42. holder.showArea.setTag(position);
  43.  
  44. holder.tvPhoneType.setText(item.get("phoneType"));
  45. holder.tvDiscount.setText(item.get("discount"));
  46. holder.tvPrice.setText(item.get("price"));
  47. holder.tvTime.setText(item.get("time"));
  48. holder.tvNum.setText(item.get("num"));
  49.  
  50. // list依次载入每一个item。载入的同一时候查看showControl控制数组中相应位置的true/false
  51. // true显示隐藏部分
  52. // false不显示
  53. if (showControl[position]) {
  54. holder.hideArea.setVisibility(View.VISIBLE);
  55. } else {
  56. holder.hideArea.setVisibility(View.GONE);
  57. }
  58.  
  59. holder.showArea.setOnClickListener(new OnClickListener() {
  60. @Override
  61. public void onClick(View view) {
  62. // 依据点击位置改变控制数组中相应位置的布尔值
  63. int tag = (Integer) view.getTag();
  64. // 假设已经是true则改为false。反过来同理(即点击展开。再次点击收起)
  65. if (showControl[tag]) {
  66. showControl[tag] = false;
  67. } else {
  68. showControl[tag] = true;
  69. }
  70. //通知adapter数据改变须要又一次载入
  71. notifyDataSetChanged(); //必须要有一步
  72. }
  73. });
  74.  
  75. // 对于 Item 中子控件的监听(差别于整个Item)都是在适配器类中加入,
  76. // 不要和在Activity中给ListView加入setOnItemClickListener搞混了
  77. holder.btnBuy.setOnClickListener(new OnClickListener() {
  78.  
  79. @Override
  80. public void onClick(View arg0) {
  81. Toast.makeText(context, "快快下单!
  82.  
  83. 剩余" + item.get("num") + "台",
  84. Toast.LENGTH_SHORT).show();
  85. }
  86. });
  87. return convertView;
  88. }
  89. /**
  90. * 省略ViewHolder
  91. */
  92. }

改变不大吧?仅仅是(和上边的"单项展开"对照)记录点击位置的方式和推断是否须要显示时的推断略微改一下就能够了。

四、Item 布局较复杂情况下的实现

上边两个 Adapter 中使用的布局比較简单(简单是指比較easy区分控制),假设对于一个比較麻烦一点的布局怎么办呢?比方我们几个样例:

  1. <?
  2.  
  3. xml version="1.0" encoding="utf-8"?>
  4. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. android:orientation="vertical" >
  8.  
  9. <!-- 明明 TableLayout 就能够作为根节点
  10. 为什么在 TableLayout 外再加一个 LinearLayout ?-->
  11. <TableLayout
  12. android:id="@+id/table"
  13. style="@style/table"
  14. android:background="@drawable/shape2"
  15. android:layout_marginTop="0dp" >
  16.  
  17. <TableRow
  18. android:layout_width="match_parent"
  19. android:layout_height="wrap_content"
  20. android:gravity="center_vertical"
  21. android:padding="10dp" >
  22.  
  23. <TextView
  24. style="@style/textNormal"
  25. android:text="还款期数:" />
  26.  
  27. <TextView
  28. android:id="@+id/tv_repayCycle"
  29. style="@style/textNormal"
  30. android:singleLine="true"
  31. android:text="1" />
  32. </TableRow>
  33.  
  34. <View style="@style/viewLine" />
  35.  
  36. <TableRow
  37. android:layout_width="match_parent"
  38. android:layout_height="wrap_content"
  39. android:gravity="center_vertical"
  40. android:padding="10dp" >
  41.  
  42. <TextView
  43. style="@style/textNormal"
  44. android:text="共计本息:" />
  45.  
  46. <TextView
  47. android:id="@+id/tv_total"
  48. style="@style/textNormal"
  49. android:singleLine="true"
  50. android:text="500" />
  51. </TableRow>
  52.  
  53. <View
  54. android:id="@+id/splitLine1"
  55. style="@style/viewLine" />
  56.  
  57. <TableRow
  58. android:id="@+id/rowRepayDate"
  59. android:layout_width="match_parent"
  60. android:layout_height="wrap_content"
  61. android:gravity="center_vertical"
  62. android:padding="10dp" >
  63.  
  64. <TextView
  65. style="@style/textNormal"
  66. android:text="还款时间:" />
  67.  
  68. <TextView
  69. android:id="@+id/tv_repayDate"
  70. style="@style/textNormal"
  71. android:singleLine="true"
  72. android:text="20160121" />
  73. </TableRow>
  74.  
  75. <View
  76. android:id="@+id/splitLine2"
  77. style="@style/viewLine" />
  78.  
  79. <TableRow
  80. android:id="@+id/rowPrinciple"
  81. android:layout_width="match_parent"
  82. android:layout_height="wrap_content"
  83. android:gravity="center_vertical"
  84. android:padding="10dp" >
  85.  
  86. <TextView
  87. style="@style/textNormal"
  88. android:text="剩余待还本金:" />
  89.  
  90. <TextView
  91. android:id="@+id/tv_notRepayPrincipal"
  92. style="@style/textNormal"
  93. android:singleLine="true"
  94. android:text="500" />
  95. </TableRow>
  96.  
  97. <View
  98. android:id="@+id/splitLine3"
  99. style="@style/viewLine" />
  100.  
  101. <TableRow
  102. android:id="@+id/rowInterest"
  103. android:layout_width="match_parent"
  104. android:layout_height="wrap_content"
  105. android:gravity="center_vertical"
  106. android:padding="10dp" >
  107.  
  108. <TextView
  109. style="@style/textNormal"
  110. android:text="剩余待还利息:" />
  111.  
  112. <TextView
  113. android:id="@+id/tv_notRepayInterest"
  114. style="@style/textNormal"
  115. android:singleLine="true"
  116. android:text="5.35" />
  117. </TableRow>
  118.  
  119. <ImageView
  120. android:id="@+id/img_more"
  121. android:layout_width="wrap_content"
  122. android:layout_height="wrap_content"
  123. android:layout_marginBottom="3dp"
  124. android:src="@drawable/arrow_d" />
  125. </TableLayout>
  126. </LinearLayout>

表格布局是一个总体,要隐藏哪些部分须要一一对 xxxView 设置,不是不能实现。仅仅是会减少我们的"水平",这代码看起来太低级了,怎么办?但这样有两种方法:(1)改造布局,改成和上边类似的布局,但这工作量相对较大并且会造成其它地方的修改;(2)就是我们下边的方法(事实上仅仅是个技巧。算不得方法):

以上代码结构如图

红色虚线框所看到的,将要隐藏的组件包装一下。打包处理。看 Adapter 代码:

  1. /**
  2. * 点击item展开隐藏部分,再次点击收起
  3. * 仅仅可展开一条记录
  4. *
  5. * @author WangJ
  6. */
  7. public class TableExpandAdapter extends BaseAdapter {
  8. private Context context;
  9. private ArrayList<HashMap<String, String>> list;
  10. private int currentItem = -1; //用于记录点击的 Item 的 position
  11.  
  12. public TableExpandAdapter(Context context,
  13. ArrayList<HashMap<String, String>> list) {
  14. super();
  15. this.context = context;
  16. this.list = list;
  17. }
  18.  
  19. @Override
  20. public int getCount() {
  21. return list.size();
  22. }
  23.  
  24. @Override
  25. public Object getItem(int position) {
  26. return list.get(position);
  27. }
  28.  
  29. @Override
  30. public long getItemId(int position) {
  31. return position;
  32. }
  33.  
  34. @Override
  35. public View getView(final int position, View convertView, ViewGroup parent) {
  36. ViewHolder holder = null;
  37. if (convertView == null) {
  38. convertView = LayoutInflater.from(context).inflate(
  39. R.layout.item_1, parent, false);
  40. holder = new ViewHolder();
  41. holder.table = (TableLayout) convertView.findViewById(R.id.table);
  42. holder.tvRepayCycle = (TextView) convertView
  43. .findViewById(R.id.tv_repayCycle);
  44. holder.tvTotal = (TextView) convertView
  45. .findViewById(R.id.tv_total);
  46. holder.tvRepayDate = (TextView) convertView
  47. .findViewById(R.id.tv_repayDate);
  48. holder.tvNotRepayPrincipal = (TextView) convertView
  49. .findViewById(R.id.tv_notRepayPrincipal);
  50. holder.tvNotRepayInterest = (TextView) convertView
  51. .findViewById(R.id.tv_notRepayInterest);
  52. holder.imgMore = (ImageView) convertView.findViewById(R.id.img_more);
  53.  
  54. //** 把要隐藏的控件"装起来"——開始 **
  55. holder.splitLine1 = convertView.findViewById(R.id.splitLine1);
  56. holder.rowRepayDate = (TableRow) convertView
  57. .findViewById(R.id.rowRepayDate);
  58. holder.splitLine2 = convertView.findViewById(R.id.splitLine2);
  59. holder.rowNotRepayPrincipal = (TableRow) convertView
  60. .findViewById(R.id.rowPrinciple);
  61. holder.splitLine3 = convertView.findViewById(R.id.splitLine3);
  62. holder.rowNotRepayInterest = (TableRow) convertView
  63. .findViewById(R.id.rowInterest);
  64. holder.hideViews.add(holder.splitLine1);
  65. holder.hideViews.add(holder.rowRepayDate);
  66. holder.hideViews.add(holder.splitLine2);
  67. holder.hideViews.add(holder.rowNotRepayPrincipal);
  68. holder.hideViews.add(holder.splitLine3);
  69. holder.hideViews.add(holder.rowNotRepayInterest);
  70. //** 把要隐藏的控件"装起来"——结束 **
  71.  
  72. convertView.setTag(holder);
  73. } else {
  74. holder = (ViewHolder) convertView.getTag();
  75. }
  76.  
  77. HashMap<String, String> item = list.get(position);
  78.  
  79. // 注意:我们在此给响应点击事件的区域(我的样例里是 table 布局)加入Tag,为了记录点击的 position,我们正好用 position 设置 Tag
  80. holder.table.setTag(position);
  81.  
  82. holder.tvRepayCycle.setText(item.get("data1"));
  83. holder.tvTotal.setText(item.get("data2"));
  84. holder.tvRepayDate.setText(item.get("data3"));
  85. holder.tvNotRepayPrincipal.setText(item.get("data4"));
  86. holder.tvNotRepayInterest.setText(item.get("data5"));
  87.  
  88. //依据 currentItem 记录的点击位置设置"相应Item"的可见性
  89. if (currentItem == position) {
  90. setViewsVisibility(holder.hideViews, true);
  91. holder.imgMore.setVisibility(View.GONE); //item展开时让箭头不可见
  92. } else {
  93. setViewsVisibility(holder.hideViews, false);
  94. holder.imgMore.setVisibility(View.VISIBLE); //item收起时让箭头可见
  95. }
  96.  
  97. holder.table.setOnClickListener(new OnClickListener() {
  98.  
  99. @Override
  100. public void onClick(View view) {
  101. //用 currentItem 记录点击位置
  102. int tag = (Integer) view.getTag();
  103. if (tag == currentItem) {
  104. currentItem = -1;
  105. } else {
  106. currentItem = tag;
  107. }
  108. //通知adapter数据改变须要又一次载入
  109. notifyDataSetChanged();
  110. }
  111. });
  112. return convertView;
  113. }
  114.  
  115. /**
  116. * 一次性设置一系列控件的可见性
  117. *
  118. * @param views
  119. * ArrayList<View>类型,要设置可见性的控件封装
  120. * @param visivility
  121. * boolean类型。true表示可见,false表示不可见
  122. */
  123. private void setViewsVisibility(ArrayList<View> views, boolean visivility) {
  124. for (View view : views) {
  125. view.setVisibility(visivility ? View.VISIBLE : View.GONE);
  126. }
  127. }
  128.  
  129. private static class ViewHolder {
  130. private TableLayout table;
  131.  
  132. private TextView tvRepayCycle;
  133. private TextView tvTotal;
  134. private TextView tvRepayDate;
  135. private TextView tvNotRepayPrincipal;
  136. private TextView tvNotRepayInterest;
  137.  
  138. //** 须要隐藏控件——開始 **
  139. private View splitLine1;
  140. private TableRow rowRepayDate;
  141. private View splitLine2;
  142. private TableRow rowNotRepayPrincipal;
  143. private View splitLine3;
  144. private TableRow rowNotRepayInterest;
  145. //** 须要隐藏控件——结束 **
  146. private ArrayList<View> hideViews = new ArrayList<View>(); //用来封装隐藏的控件。使便于管理
  147.  
  148. private ImageView imgMore; //向下展开的箭头
  149. }
  150. }

在 Activity 中也仅仅是简单模拟一些数据:

  1. private void requestData() {
  2.  
  3. HashMap<String, String> accountInfo = new HashMap<String, String>();
  4. accountInfo.put("type", "数码产品");
  5. accountInfo.put("repayAccount", "622200******0000");
  6.  
  7. ArrayList<HashMap<String, String>> datas = new ArrayList<HashMap<String,String>>();
  8. for(int i = 1; i <= 10; i++){
  9. HashMap<String, String> item = new HashMap<String, String>();
  10. item.put("data1", i + "");
  11. item.put("data2", 510.50 + "");
  12. item.put("data3", "20160" + i + "21");
  13. item.put("data4", "500");
  14. item.put("data5", "10.00");
  15. datas.add(item);
  16. }
  17.  
  18. showData(accountInfo);
  19.  
  20. ListView lvRepayInfo = (ListView) findViewById(R.id.lv_repayInfoList);
  21. TableExpandAdapter adapter = new TableExpandAdapter(this, datas);
  22. lvRepayInfo.setAdapter(adapter);
  23. }
  24.  
  25. private void showData(HashMap<String, String> maps) {
  26. TextView tvType = (TextView) findViewById(R.id.tv_type);
  27. TextView tvRepayAccount = (TextView) findViewById(R.id.tv_repayAccount);
  28.  
  29. if(maps != null){
  30. tvType.setText(maps.get("type"));
  31. tvRepayAccount.setText(maps.get("repayAccount"));
  32. }
  33. }

看完不要说“楼主。你 TMD 地在逗我!

”。楼主有言在先。这仅仅是一个技巧,算不得方法,让我的代码没有大段大段的在设置可见性看起来那么低级。事实上。那几个 holder.hideViews.add(View view) 放到 ViewHolder 类中更好一点。

忘了说 TableLayout 外加 LinearLayout 作为根节点的问题:我们在 Adapter 的 getView() 方法中复用 convertView 时要 convertView.setTag(holder),而我们还要给 TableLayout 加入一个 int 类型的Tag。假设用 TableLayout 作为布局的根节点是无法完毕的。

没什么技术难度,假设你没有时间,我把代码上传了,能够去下载——ListView Item点击展开隐藏项Demo下载

ListView点击Item展开隐藏项(单项展开、多项展开、复杂布局时的展开处理)的更多相关文章

  1. Android中Listview点击item不变颜色以及设置listselector 无效

    Android中Listview点击item不变颜色以及设置listselector 无效 这是同一个问题,Listview中点击item是会变颜色的,因为listview设置了默认的listsele ...

  2. android ListView点击item返回后listview滚动位置

    1.Don't work when dynamically loading content Parcelable state; @Override public void onPause() { // ...

  3. 解决listview点击item失效

    开发中很常见的一个问题,项目中的listview不仅仅是简单的文字,常常需要自己定义listview,自己的Adapter去继承BaseAdapter,在adapter中按照需求进行编写,问题就出现了 ...

  4. ListView中点击Item没有任何响应

    不多说,上代码:如下图 红色方框的东西, android:descendantFocusability=”blocksDescendants” 如果不添加的话,在android的8.0手机上点击没有响 ...

  5. android的ListView点击item使item展开的做法

    直接上代码把.主要是又一次给item measure高度,直接上代码把 import java.util.ArrayList; import android.app.Activity; import ...

  6. listview实现点击条目上的箭头展开隐藏菜单。

    效果如下图,当点击listview中的小三角时,显示出下面布局,再点隐藏, 点击其他条目的三角时,上一个展开的条目隐藏的同时展开当前条目. 思路是在item布局中放入展开菜单的布局,并设置状态为隐藏, ...

  7. 使用jQuery 中的显示与隐藏动画效果实现折叠下拉菜单的收缩和展开,在页面的列表中有若干项,列表的每项中有一个二级列表,二级列表默认为隐藏状态。点击列表的项,切换二级列表的显示或隐藏状态

    查看本章节 查看作业目录 需求说明: 使用jQuery 中的显示与隐藏动画效果实现折叠下拉菜单的收缩和展开,在页面的列表中有若干项,列表的每项中有一个二级列表,二级列表默认为隐藏状态.点击列表的项,切 ...

  8. Android处理ListView中的Item中的Button按钮不能点击的问题

    问题描述:ListView列表中的Button按钮按钮不能点击 解决办法:在ListView中的Item项的布局文件中加上:android:descendantFocusability="b ...

  9. listview指定某item的点击效果

    需求:listview的某些item能够点击,需要点击效果,有些item不能点击,需要屏蔽点击效果. 实现: 1.layout: <ListView android:id="@+id/ ...

随机推荐

  1. PowerDesigner添加表注释

    之前同事用PowerDesigner 建立数据模型后,生成到数据库中,没有注释.这导致数据库使用起来不是很方便,特别是对数据表结构不熟悉的同事. 其实,可以添加注释(并且可以逆向,即从数据库中反向更新 ...

  2. ORA-01654错误

    问题现象: 测试库使用如下方式创建索引: create index IDX_ANA_OFFICE on ANA (OFFICE_CITY, OFFICE_NO)   tablespace IDX    ...

  3. 微信小程序 - 弹出层组件

    需要的可以下载示例:maskalert

  4. Go语言中使用MySql数据库

    Go语言中使用MySql数据库 1.MySQL驱动 Go中支持MySQL的驱动目前比较多,有如下几种,有些是支持database/sql标准,而有些是采用了自己的实现接口,常用的有如下几种: http ...

  5. 朴素贝叶斯分类器(Naive Bayes)

    1. 贝叶斯定理 如果有两个事件,事件A和事件B.已知事件A发生的概率为p(A),事件B发生的概率为P(B),事件A发生的前提下.事件B发生的概率为p(B|A),事件B发生的前提下.事件A发生的概率为 ...

  6. oracle列自增实现(1)-Sequence+Trigger实现Oracle列自增

    Sequence+Trigger实现Oracle列自增 序列的语法格式为: CREATE SEQUENCE 序列名 [INCREMENT BY n] [START WITH n] [{MAXVALUE ...

  7. Java ConcurrentHashMap (Java代码实战-005)

    package Threads; import com.google.common.collect.Maps; import java.util.concurrent.ConcurrentMap; i ...

  8. Red Hat7.2 上安装 MySQL5.5.58

    1.首先查看linux版本:cat /etc/redhat-release Red Hat Enterprise Linux Server release 7.2 (Maipo) 2.Linux查看版 ...

  9. 微服务(Microservice)那点事

    WHAT - 什么是微服务 微服务简介 这次参加JavaOne2015最大的困难就是听Microservice相关的session,无论内容多么水,只要题目带microservice,必定报不上名,可 ...

  10. ios中 radioButton和DataPIcker,九宫格封装好使用

    下载地址 http://pan.baidu.com/share/link?shareid=2894506499&uk=923776187 引用这几个文件 radiobutton.封装好单选按钮 ...