2013-03-27 89 views
8

我正在制作一个包含自定义ExpandableListView适配器的菜单。尽管试图将我的代码与API示例以及我在网上看到的任何其他示例(包括多个密切相关的SO问题)进行匹配,但仍然无法使其工作。getChildView不被调用

我知道正在使用适配器,因为正在显示组视图(它是由xml构成的)。点击组项目也会调用“getGroupView”,但代码从不运行“getChildView”,“getChild”或“getChildId”。

我甚至已经通过Android-15源代码来了解我可能做错了什么,但没有什么奇怪的。

=基本活动

public class SettingsM extends FragmentActivity 
{ 
    static Context context; 
    ViewPager mViewPager; 
    CollectionPagerAdapter mDemoCollectionPagerAdapter; 
    //ColorPicker picker; 

    SharedPreferences preferences; 

    public void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
      WindowManager.LayoutParams.FLAG_FULLSCREEN); 

     context = this; 
     // Set up action bar. 
     final ActionBar actionBar = getActionBar(); 

     actionBar.setDisplayHomeAsUpEnabled(false); 
     actionBar.setDisplayUseLogoEnabled(false); 
     actionBar.setTitle("Particle emitter settings"); 

     // get the preferences for this screen 
     preferences = this.getSharedPreferences("base_world", 0); 

     // tab holder 
     setContentView(R.layout.tabmenu_holder); 
     mViewPager = (ViewPager) findViewById(R.id.pager); 

     mDemoCollectionPagerAdapter = new CollectionPagerAdapter(getSupportFragmentManager()); 
     mViewPager.setAdapter(mDemoCollectionPagerAdapter); 
    } 

    public class CollectionPagerAdapter extends FragmentStatePagerAdapter 
    { 
     public CollectionPagerAdapter(FragmentManager fm) 
     { 
      super(fm); 
     } 

     @Override 
     public Fragment getItem(int i) 
     { 
      Fragment fragment = new TabFragment(); 
      Bundle args = new Bundle(); 
      if(preferences != null) 
       { 
       if(i == 0) 
       {// world 
        args.putBoolean("world", true); 
       } else 
       {// emitter 
        args.putBoolean("world", false); 
        args.putInt("emitter", i-1); 
       } 
      } 
      fragment.setArguments(args); 
      return fragment; 
     } 

     @Override 
     public int getCount() 
     { 
      return 100; 
     } 

     @Override 
     public CharSequence getPageTitle(int position) 
     { 
      if(position == 0) 
      { 
       return "World"; 
      } else 
      { 
       return "Emitter #" + position; 
      } 
     } 
    } 

    public static class TabFragment extends Fragment 
    {   
     @Override 
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
     { 
      Bundle args = getArguments(); 
      View rootView = new TextView(context);// use a textview as the default 

      if(args.getBoolean("world")) 
      { 
       rootView = inflater.inflate(R.layout.m_backdrop, container, false); 

       // add face drop-down 
       ExpandableListView face_list = (ExpandableListView) rootView.findViewById(R.id.FaceList); 
       if(face_list != null) 
       { 
        face_list.setAdapter(new ExpandableFaceList(context)); 
        face_list.setOnGroupClickListener(new OnGroupClickListener() 
        { 

         @Override 
         public boolean onGroupClick(ExpandableListView parent, 
          View v, int groupPosition, long id) 
         { 
          Log.i("FaceList", "Clicked:" + groupPosition); 
          return false; 
         } 
        }); 
       } 

      } else 
      { 
       return rootView; 
      } 
      return rootView; 
     } 
    } 
} 

=扩展列表视图适配器

public class ExpandableFaceList extends BaseExpandableListAdapter implements ExpandableListAdapter 
{ 
    public Context context; 
    private LayoutInflater inflator; 
    private float mDensity = 1f; 

    private boolean bShowSw = true; 
    private ColorPickerMenuView cp; 
    private Switch sw; 


    public ExpandableFaceList(Context context) 
    { 
     this.context = context; 
     this.inflator = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 

     mDensity = context.getResources().getDisplayMetrics().density; 
    } 

    @Override 
    public int getGroupCount() 
    { 
     return 1; 
    } 

    @Override 
    public int getChildrenCount(int groupPosition) 
    { 
     return 6;// because there are 6 faces to a cube 
    } 

    // list views 
    @Override 
    public View getGroupView(int groupPosition, boolean isExpanded, 
      View convertView, ViewGroup parent) 
    { 
     View v = convertView; 
     TextView tv; 

     if(v == null) 
     { 
      v = inflator.inflate(R.layout.exlist_head, parent, false); 

      tv = (TextView) v.findViewById(R.id.exList_Title); 
      if(tv != null) 
       tv.setText("Face Colors"); 

      tv = (TextView) v.findViewById(R.id.exList_Summary); 
      String s_text = "The color for each face, click to "; 
      s_text += ((isExpanded)? "collaspe": "expand"); 
      if(tv != null) 
       tv.setText(s_text); 
     } else 
     { 
      tv = (TextView) v.findViewById(R.id.exList_Summary); 
      String s_text = "The color for each face, click to "; 
      s_text += ((isExpanded)? "collaspe": "expand"); 
      if(tv != null) 
       tv.setText(s_text); 
      parent.invalidate(); 
     }   

     return v; 
    } 

    @Override 
    public View getChildView(int groupPosition, int childPosition, 
      boolean isLastChild, View convertView, ViewGroup parent) 
    { 
     View v = convertView; 

     if(v == null) 
     { 
      if(bShowSw) 
      { 
       v = (LinearLayout) inflator.inflate(R.layout.face_info_sw, parent, false); 
      } else 
      { 
       v = (LinearLayout) inflator.inflate(R.layout.face_info, parent, false); 
      } 
     } 

     switch(childPosition) 
     { 
     case 0: 
      v.setTag("Front"); 
      break; 
     case 1: 
      v.setTag("Back"); 
      break; 
     case 2: 
      v.setTag("Left"); 
      break; 
     case 3: 
      v.setTag("Right"); 
      break; 
     case 4: 
      v.setTag("Top"); 
      break; 
     case 5: 
      v.setTag("Bottom"); 
      break; 
      } 

     Log.i("ELV", "Pos:" + childPosition); 

     cp = (ColorPickerMenuView) v.findViewById(R.id.face_color); 
     cp.setTitle((String) v.getTag()); 

     cp.setOnClickListener(new OnClickListener() { 
      public void onClick(View v) { UpdateData(v); } 
     }); 

     if(bShowSw) 
     { 
      sw = (Switch) v.findViewById(R.id.face_sw); 
      sw.setOnClickListener(new OnClickListener() { 
       public void onClick(View v) { UpdateData(v); } 
      }); 
     } 

     return v; 
    } 

    private void UpdateData(View v) { } 

    @Override 
    public Object getGroup(int groupPosition) 
    { 
     return groupPosition; 
    } 

    @Override 
    public Object getChild(int groupPosition, int childPosition) 
    { 
     return "Child:" + groupPosition + "." + childPosition; 
    } 

    @Override 
    public long getGroupId(int groupPosition) 
    { 
     return groupPosition; 
    } 

    @Override 
    public long getChildId(int groupPosition, int childPosition) 
    { 
     return childPosition; 
    } 

    @Override 
    public boolean hasStableIds() 
    { 
     return true; 
    } 

    @Override 
    public boolean isChildSelectable(int groupPosition, int childPosition) 
    { 
     return true; 
    } 
} 

=活动的XML视图

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/pager" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <android.support.v4.view.PagerTitleStrip android:id="@+id/pager_title_strip" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:layout_gravity="top" 
     android:background="#33b5e5" 
     android:textColor="#fff" 
     android:paddingTop="4dp" 
     android:paddingBottom="4dp" /> 

</android.support.v4.view.ViewPager> 

= m_backdrop.xml(对于背景设置菜单)

<?xml version="1.0" encoding="utf-8"?> 
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    xmlns:app="http://schemas.android.com/apk/res/com.zyphronics.aquafinger"> 

     <RelativeLayout 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:orientation="vertical" > 

      <TextView 
      android:id="@+id/Title_GeneralSettings_text" 
      style="?android:attr/listSeparatorTextViewStyle" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:layout_marginTop="5dip" 
      android:text="General Settings" /> 

     <ExpandableListView 
      android:id="@+id/FaceList" 
      android:layout_width="match_parent" 
      android:layout_height="fill_parent" 
      android:layout_below="@id/Title_GeneralSettings_text" > 
     </ExpandableListView> 

     </RelativeLayout> 

</ScrollView> 

= face_info.sw.xml(该face_info.xml是相同的,但没有开关)

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:orientation="vertical" > 

    <Switch 
     android:id="@+id/face_sw" 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
     android:layout_marginLeft="10dp" 
     android:tag="face_sw" 
     android:text="Enabled?" 
     android:textOff="No" 
     android:textOn="Yes" /> 

    <com.zyphronics.AF.Controls.colorpicker.ColorPickerMenuView 
     android:id="@+id/face_color" 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
     android:tag="face_color" /> 
</LinearLayout> 

即使没有在face_info_sw.xml了“ColorPickerMenuView”的一部分,该子视图仍然不被称为。我也尝试过使用相对布局本身,而不是在滚动视图中,但是这阻止了进一步添加的项目被滚动到(并且使得自定义控件具有奇怪的大小)。

任何帮助解决这个问题都会很好。如果任何人需要这个(eclipse兼容)的打包源代码,就像在评论中一样,我会回复一个链接。

回答

6

不好意思,没有人能够回答这个......但是,幸运的是我能够找到解决这个问题的方法,所以其他人也可以将可扩展列表视图添加到他们的片段中。

我发现了解决方案,同时检查了微调器的源代码(因为我想用自定义条目制作微调器)。代码中的关键点在于它在测量所有孩子时的“onMeasure”......好,达到预先定义的极限值15,但测量孩子是最重要的。

=解决方案= 创建适配器时,您需要传递父视图。这是关键,因为它是从适配器查看唯一的链接(只有简单的方法)。

public Context context; 
public ExpandableListView parent; 
private LayoutInflater inflator; 
// Only measure this many items to get a decent max height. 
private static final int MAX_ITEMS_MEASURED = 15; 

public ExpandableFaceList(Context context, final ExpandableListView parent) 
{ 
    this.context = context; 
    this.parent = parent; 
    this.inflator = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 

    mDensity = context.getResources().getDisplayMetrics().density; 
} 

接下来,在你的“getGroupView”,因为这似乎是它通常被称为唯一的事情,你需要添加以下代码:

public View getGroupView(int groupPosition, boolean isExpanded, 
View convertView, ViewGroup parent) 
{ 
    if(convertView != null) 
    { 
     int nH = 0; 
     if(isExpanded) 
     { 
      nH = measureChildrenHeight(groupPosition); 
     } else 
     { 
      nH = convertView.getMeasuredHeight(); 
     } 
     parent.getLayoutParams().height = (int) (nH * mDensity); 

     parent.invalidate(); 
    } 

    return convertView; 
} 

中的关键部分上面的代码是“measureChildrenHeight”,“convertView.getMeasuredHeight()”只是在折叠时恢复ELV。这项措施的儿童代码如下:

int measureChildrenHeight(int groupPosition) 
{ 
    int height = 0; 
    View itemView = null; 
    LinearLayout viewGroup = new LinearLayout(context); 
    viewGroup.setOrientation(LinearLayout.VERTICAL); 

    final int widthMeasureSpec = 
    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 
    final int heightMeasureSpec = 
    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 

    // Make sure the number of items we'll measure is capped. If it's a huge data set 
    // with wildly varying sizes, oh well. 
    int start = 0;//Math.max(0, getSelectedItemPosition()); 

    final int end = Math.min(getChildrenCount(groupPosition), start + MAX_ITEMS_MEASURED); 
    final int count = end - start; 
    start = Math.max(0, start - (MAX_ITEMS_MEASURED - count)); 
    for (int i = start; i < end; i++) 
    { 
     itemView = getChildView(groupPosition, i, (i+1 == end), itemView, viewGroup); 
     if (itemView.getLayoutParams() == null) 
     { 
      itemView.setLayoutParams(new ViewGroup.LayoutParams(
      ViewGroup.LayoutParams.WRAP_CONTENT, 
      ViewGroup.LayoutParams.WRAP_CONTENT)); 
     } 
     itemView.measure(widthMeasureSpec, heightMeasureSpec); 

     if(i+1 != end) 
     height += itemView.getMeasuredHeight();//Math.max(height, itemView.getMeasuredHeight()); 
    } 

    return height; 
} 

注:我不得不调整的代码,以排除最后一个项目的高度,因为它是最后一个项目下增加额外的空间。如果你有不同身高的孩子,可能会有麻烦。我仍然在儿童/小组标题下面留下了一些空白空间,但这是可以原谅的(不像之前的数量,这是3-4个孩子的高度)。

+0

http://stackoverflow.com/a/14159666/390014有助于错误计算高度 – draw 2013-06-09 16:53:31

+0

don'r为我工作,在哪里使用从构造函数传递的ExpandableListView父对象? – 2013-09-02 15:05:00

17

问题是,您的ExpandableListView位于ScrollView中。这是大多数时间都是糟糕的布局造成的,你应该尽量避免它。

但有时它是唯一的解决方案(实际上并非如此,但其他解决方案可能超出了范围)。您的解决方案也可以工作,但有点复杂。相反编写自定义ExpandableListView这样的:

public class ExpandExpandableListView extends ExpandableListView{ 
    boolean expanded = true; 

    public ExpandExpandableListView(Context context) { 
     super(context); 
    } 

    public ExpandExpandableListView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    public ExpandExpandableListView(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
    } 

    public boolean isExpanded() 
    { 
     return expanded; 
    } 

    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
     if (isExpanded()) 
     { 
      // Calculate entire height by providing a very large height hint. 
      // View.MEASURED_SIZE_MASK represents the largest height possible. 
      int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK, MeasureSpec.AT_MOST); 
      super.onMeasure(widthMeasureSpec, expandSpec); 

      ViewGroup.LayoutParams params = getLayoutParams(); 
      params.height = getMeasuredHeight(); 
     }else{ 
      super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
     } 
    } 

    public void setExpanded(boolean expanded) 
    { 
     this.expanded = expanded; 
    } 
} 

,并在您m_backdrop.xml:

<?xml version="1.0" encoding="utf-8"?> 
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" 
    ...  

     <RelativeLayout 
     ... 

     <com.package.name.to.class.ExpandExpandableListView 
      android:id="@+id/FaceList" 
      android:layout_width="match_parent" 
      android:layout_height="fill_parent" 
      android:layout_below="@id/Title_GeneralSettings_text" > 
     </ExpandableListView> 

     </RelativeLayout> 

</ScrollView> 

这已经是。它应该按预期工作。