没有调用getChildView

时间:2013-03-27 03:12:13

标签: android expandablelistview expandablelistadapter

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

我知道正在使用适配器,因为正在显示组视图(由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兼容),就像在评论中一样,我会回复一个链接。

3 个答案:

答案 0 :(得分:20)

问题是,您的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>

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

答案 1 :(得分:6)

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

我在查看微调器的源代码时找到了解决方案(因为我想创建一个带有自定义条目的微调器)。代码中的关键点在于它的“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个孩子的高)。

答案 2 :(得分:0)

查看您的控件是否可见。我以编程方式将其设置为不可见。