重庆分公司,新征程启航

为企业提供网站建设、域名注册、服务器等服务

支持多项选择的ExpandableListView怎么用-创新互联

这篇文章主要介绍支持多项选择的ExpandableListView怎么用,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

创新互联是一家集网站建设,包河企业网站建设,包河品牌网站建设,网站定制,包河网站建设报价,网络营销,网络优化,包河网站推广为一体的创新建站企业,帮助传统企业提升企业形象加强企业竞争力。可充分满足这一群体相比中小企业更为丰富、高端、多元的互联网需求。同时我们时刻保持专业、时尚、前沿,时刻以成就客户成长自我,坚持不断学习、思考、沉淀、净化自己,让我们为更多的企业打造出实用型网站。

目标(需求):

1. 创建一个可展开可收缩的列表;

2. 其列表项包含多个checkable的部件,当选择某一行时,该行包含的checkable的部件需要作出相应的变化;

3. 可以选择多个列表项,并且这些列表项可被读出

结果图:

支持多项选择的ExpandableListView怎么用

实现:

1. 创建主layout用于规划列表显示。对于具体的列表项,为了实现的方便我们也创建一个layout文件。

 
 
  
   
   
 
  

2. 类似ListView,ExpandableListView也是通过Adapter来管理其包含的各种元素和操作,这里我们创建一个扩展自BaseExpandableListAdapter的Adapter。与ListView不同的是,ExpandableListAdapter要渲染实现两级View(Group级和列表项级)的操作。它通过getGroupView()渲染Group项,通过getChildView()渲染列表子项。

@Override 
  public View getGroupView(int groupPosition, boolean isExpanded, 
      View convertView, ViewGroup parent) { 
    View groupView = convertView; 
    if (groupView == null) { 
      groupView = new TextView(context); 
      ((TextView)groupView).setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); 
      groupView.setPadding(50,0,0,0); 
    } 
    ((TextView)groupView).setText(groupData[groupPosition]); 
    ((TextView)groupView).setTextColor(context.getResources().getColor(R.color.fgcolor)); 
     
    return groupView; 
  } 
 
  @Override 
  public View getChildView(final int groupPosition, final int childPosition, 
      boolean isLastChild, View convertView, ViewGroup parent) { 
    View itemView = convertView; 
    final ViewHolder vh; 
    if (itemView == null) { 
      LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      itemView = inflater.inflate(R.layout.item_view, null); 
       
      vh = new ViewHolder(); 
      vh.layout = (CheckableLinearLayout)itemView.findViewById(R.id.layout); 
      vh.item = (TextView)itemView.findViewById(R.id.item); 
      itemView.setTag(vh); 
    } else { 
      vh = (ViewHolder)itemView.getTag(); 
    } 
    vh.item.setText(itemData[groupPosition][childPosition]); 
    final ExpandableListView listView = ((ExpandableListView)((MainActivity)context).findViewById(R.id.list)); 
    final int position = listView.getFlatListPosition(ExpandableListView.getPackedPositionForChild(groupPosition, childPosition)); 
    listView.setItemChecked(position, checkedState[groupPosition][childPosition]); 
    vh.layout.setOnClickListener(new OnClickListener() { 
 
      @Override 
      public void onClick(View v) { 
        ((CheckableLinearLayout)v).toggle(); 
        checkedState[groupPosition][childPosition] = !checkedState[groupPosition][childPosition];  
        listView.setItemChecked(position, ((CheckableLinearLayout)v).isChecked()); 
      } 
    }); 
    return itemView; 
  }

3. 为每一列表子项容器创建OnClickListener监听鼠标的点击事件。在这里要注意,由于列表子项包含了CheckBox,所以为了使点击事件不要被CheckBox捕获,我们需要创建一个扩展自CheckBox的类来屏蔽鼠标和键盘事件。同时,需要在这个容器里搜索其包含的checkable的部件并将check操作传给这些部件。

Adapter中的方法getChildView()需要实现鼠标点击监听器:

public View getChildView(final int groupPosition, final int childPosition, 
      boolean isLastChild, View convertView, ViewGroup parent) { 
  View itemView = convertView; 
  final ViewHolder vh; 
... 
 
    final int position = listView.getFlatListPosition(ExpandableListView.getPackedPositionForChild(groupPosition, childPosition)); 
    listView.setItemChecked(position, checkedState[groupPosition][childPosition]); 
  vh.layout.setOnClickListener(new OnClickListener() { 
 
  @Override 
  public void onClick(View v) { 
    ((CheckableLinearLayout)v).toggle(); 
    checkedState[groupPosition][childPosition] = !checkedState[groupPosition][childPosition];  
     listView.setItemChecked(position, ((CheckableLinearLayout)v).isChecked()); 
  } 
 }); 
 return itemView; 
}

扩展自CheckBox的InertCheckBox需要屏蔽键盘和鼠标事件

public class InertCheckBox extends CheckBox { 
  @Override 
  public boolean onKeyDown(int keyCode, KeyEvent event) { 
  //直接返回false 
  return false; 
  } 
 
  @Override 
  public boolean onKeyUp(int keyCode, KeyEvent event) { 
  //直接返回false 
  return false; 
} 
 
  @Override 
  public boolean onTouchEvent(MotionEvent event) { 
  //直接返回false 
  return false; 
  } 
 
   @Override 
   public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 
  //直接返回false 
  return false; 
  ... 
}

列表项容器需要实现Checkable接口并且把check操作传递给其checkable的子部件

public class CheckableLinearLayout extends LinearLayout implements Checkable { 
... 
  @Override 
  public void setChecked(boolean checked) { 
  this.isChecked = checked; 
  for (Checkable view : checkableViews) { 
   view.setChecked(checked); 
   } 
  } 
   
  @Override 
  public boolean isChecked() { 
   return this.isChecked; 
  } 
 
  @Override 
  public void toggle() { 
   isChecked = !isChecked; 
   for (Checkable view : checkableViews)    { 
  view.toggle(); 
   } 
  } 
 
  @Override 
  protected void onFinishInflate() { 
  super.onFinishInflate(); 
     
    for (int i=0; i

开发中遇到的问题:

1. 渲染后的child view类似于放在一个cache中,下一次再通过convertView取时,由于Group的收缩或扩展操作会隐藏/显示一些child view,导致某一child View的flat position发生变化,获取到的convertView不是原来希望获取的view。所以,每次获取到view后都需要对其内容重新设置(比如设置正确文本,设置监听器等)

2. check的状态设置很tricky。我开始认为直接在监听器中调用容器的toggle()方法即可。结果发现一旦某个group做了expand或collapse操作后,所有列表项的check状态全没了。后来发现原来group做了expand/collapse操作后,ListView会对其所有子项重新设置check状态,而check状态的值是存在ListView的一个SparseBooleanArray表里(mCheckStates)。由于没有对这个表进行设置,所以一刷新check状态就全丢了。并且由于这个表的key是基于拉平后所有可见的列表项的位置定的,当group扩展或收缩后,同一个列表项,它拉平后的位置还会变化。所以,为了解决这个问题,我在adapter里增加了一个二维表用于记录每一列表项的check状态。在执行 listView的setItemChecked函数时,其check状态是从这个自己创建的表中读出的,不能通过ListView的mCheckStates来读。这个我认为是ExpandableListView的一个缺陷。

遗留的已知问题:

我使用了@drawable/checkbox 来定义checkbox check 和uncheck时的图片,但当checkbox被check上时,这个checked的图片没有生效。不知道为什么,还需要进一步debug.

以上是“支持多项选择的ExpandableListView怎么用”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注创新互联行业资讯频道!


分享名称:支持多项选择的ExpandableListView怎么用-创新互联
文章路径:http://cqcxhl.cn/article/cejhoh.html

其他资讯

在线咨询
服务热线
服务热线:028-86922220
TOP