我正在制作一个包含自定义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兼容),就像在评论中一样,我会回复一个链接。
答案 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)
查看您的控件是否可见。我以编程方式将其设置为不可见。