Android Studio ExpandableListView可扩展列表在其高度为wrap_content且其下有内容时不扩展

l0oc07j2  于 2023-04-12  发布在  Android
关注(0)|答案(7)|浏览(222)

这是我的布局代码。当我点击可展开的列表视图时,它不会展开。但是,如果我增加列表的高度,它会展开。有没有一种方法可以通过代码动态地增加列表的高度?我可以让它在布局的中间展开吗?因为如果我增加高度,它只会在折叠的列表中添加不必要白色。
验证码:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context="com.pocketcash.pocketcash.HomeActivity">

        <Switch
            android:id="@+id/detailedCashInfoSwitch"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentEnd="true"
            android:layout_alignParentRight="true"
            android:layout_alignParentTop="true"
            android:onClick="cashToggleSwitchClicked"
            android:text="Toggle Detailed Cash Info" />

        <Button
            android:id="@+id/addCashButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/expandableListView2"
            android:layout_centerHorizontal="true"
            android:onClick="launchAddCash"
            android:text="Add cash" />

        <Button
            android:id="@+id/addExpenditureButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/addCashButton"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="25dp"
            android:onClick="launchAddExpenditure"
            android:text="Add expenditure" />

        <TextView
            android:id="@+id/recentLogsText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:layout_below="@+id/addExpenditureButton"
            android:layout_marginTop="50dp"
            android:text="Recent Logs:"
            android:textAppearance="?android:attr/textAppearanceMedium" />

        <TextView
            android:id="@+id/logText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:layout_below="@+id/recentLogsText"
            android:layout_marginTop="0dp"
            android:text="Small Text"
            android:textAppearance="?android:attr/textAppearanceSmall" />

        <TextView
            android:id="@+id/recentViewAllText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignTop="@+id/recentLogsText"
            android:layout_marginLeft="10dp"
            android:layout_toEndOf="@+id/recentLogsText"
            android:layout_toRightOf="@+id/recentLogsText"
            android:onClick="recentViewLogClicked"
            android:text="(view all)"
            android:textAppearance="?android:attr/textAppearanceMedium" />

        <TextView
            android:id="@+id/addViewAllText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/addCashButton"
            android:layout_centerHorizontal="true"
            android:onClick="addViewLogClicked"
            android:text="(view logs)"
            android:textAppearance="?android:attr/textAppearanceSmall" />

        <TextView
            android:id="@+id/expenseViewAllText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/addExpenditureButton"
            android:layout_centerHorizontal="true"
            android:onClick="expenseViewLogClicked"
            android:text="(view logs)"
            android:textAppearance="?android:attr/textAppearanceSmall" />

        <ImageView
            android:id="@+id/userImage"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:layout_below="@+id/detailedCashInfoSwitch"
            android:layout_marginTop="34dp"
            android:background="@drawable/default_user" />

        <TextView
            android:id="@+id/nameText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignTop="@+id/userImage"
            android:layout_marginLeft="25dp"
            android:layout_toEndOf="@+id/userImage"
            android:layout_toRightOf="@+id/userImage"
            android:text="Name"
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <TextView
            android:id="@+id/logoutText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@+id/nameText"
            android:layout_alignStart="@+id/nameText"
            android:layout_below="@+id/nameText"
            android:clickable="true"
            android:onClick="logUserOut"
            android:text="logout"
            android:textAppearance="?android:attr/textAppearanceSmall" />

        <ImageButton
            android:id="@+id/settingsButton"
            android:layout_width="25dp"
            android:layout_height="25dp"
            android:layout_alignTop="@+id/nameText"
            android:layout_marginLeft="25dp"
            android:layout_toEndOf="@+id/nameText"
            android:layout_toRightOf="@+id/nameText"
            android:background="@drawable/settingsicon"
            android:onClick="launchSettingsActivity" />

        <fragment
            android:id="@+id/fragment_currentBalanceInfo"
            android:name="com.pocketcash.pocketcash.CurrentBalanceInfoFragment"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/userImage"
            android:layout_centerHorizontal="true"
            tools:layout="@layout/fragment_current_balance_info" />

        <ExpandableListView
            android:id="@+id/expandableListView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/fragment_currentBalanceInfo"
            android:layout_centerHorizontal="true"
            android:clickable="true" />

    </RelativeLayout>
</ScrollView>
xvw2m8pv

xvw2m8pv1#

经过对这个主题的大量研究,我只能得出这样的结论:像可扩展列表视图这样的可滚动对象不能在另一个可滚动视图中声明。然而,我在运行时对我的Java代码进行了一些调整,以解决这个问题。

expListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
        @Override
        public void onGroupExpand(int groupPosition) {
            int height = 0;
            for (int i = 0; i < expListView.getChildCount(); i++) {
                height += expListView.getChildAt(i).getMeasuredHeight();
                height += expListView.getDividerHeight();
            }
            expListView.getLayoutParams().height = (height+6)*10;
        }
    });

    // Listview Group collapsed listener
    expListView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {

        @Override
        public void onGroupCollapse(int groupPosition) {
            expListView.getLayoutParams().height = 61;
        }
    });

这种方式我调整了高度的小部件动态时,它被扩大或折叠.它不是一个可靠的方法,它的作品命中和审判,所以我最终不得不把这个小部件到一个全新的活动.然而,这确实工作完美.但如果有人发现一个更好的答案,请做分享.

lf5gs5x2

lf5gs5x22#

正如Romain Guy(谷歌工程师的UI工具包)说,在他的职位
通过将宽度设置为wrap_content,您将告诉ListView与其子级的最宽宽度一样宽。因此,ListView必须测量其项,并在适配器上调用getView()来获取项。这可能会发生几次,具体取决于布局通道的数量,父布局的行为等。
因此,如果您将ListView的布局宽度或布局高度设置为wrap_contentListView将尝试测量附加到它的每个视图-这肯定不是您想要的。

**请记住:避免在任何时候为ListViewsGridViewsExpandableListView设置wrap_content,有关详细信息,请参阅Google I/O video谈论列表视图的世界

因此将ExpandableListView设为match_parent

piok6c0g

piok6c0g3#

我知道这个问题已经得到了回答,但我有另一个解决方案,可以适用于更多情况:我通过计算项目的数量来设置列表视图的初始高度,然后通过检索展开/折叠组的子项计数来更新组的折叠/展开高度。下面是一个示例代码:

int item_size = 50;  // 50px
int sub_item_size = 40;  // 40px
expListView.getLayoutParams().height = item_size*myAdapter.getGroupCount();
expenseListView.setAdapter(myAdapter);
// ListView Group Expand Listener
expenseListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
    @Override
    public void onGroupExpand(int groupPosition) {
        int nb_children = myAdapter.getChildrenCount(groupPosition);
        expenseListView.getLayoutParams().height += sub_item_size*nb_children;
    }
});

// Listview Group collapsed listener
expenseListView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
    @Override
    public void onGroupCollapse(int groupPosition) {
        int nb_children = myAdapter.getChildrenCount(groupPosition);
        expenseListView.getLayoutParams().height -= sub_item_size*nb_children;
    }
});
wgxvkvu9

wgxvkvu94#

通常我们不能在Scrollview中使用ListView,GridView或ExpandableListView。如果你需要它,那么你必须给予你的可扩展ListView固定高度。

private void setListViewHeight(final ExpandableListView listView, final int groupPosition) {
    final ExpandableListAdapter listAdapter = (ExpandableListAdapter) listView.getExpandableListAdapter();
    int totalHeight = 0;
    // be careful with unspecified width measure spec, it will ignore all layout params and even
    // screen dimensions, so to get correct height, first get maximum width View can use and
    // call measure() this way
    final int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(), View.MeasureSpec.EXACTLY);
    for (int i = 0; i < listAdapter.getGroupCount(); i++) {
        final View groupItem = listAdapter.getGroupView(i, false, null, listView);
        groupItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);

        totalHeight += groupItem.getMeasuredHeight();
        // count only expanded other groups or the clicked collapsed one
        if (((listView.isGroupExpanded(i)) && (i != groupPosition))
                || ((!listView.isGroupExpanded(i)) && (i == groupPosition))) {
            for (int j = 0, childrenNumber = listAdapter.getChildrenCount(i); j < childrenNumber; j++) {

                final View listItem = listAdapter.getChildView(i, j, j == childrenNumber - 1, null, listView);
                listItem.measure(desiredWidth, View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
                totalHeight += listItem.getMeasuredHeight();
            }
        }
    }
    final ViewGroup.LayoutParams params = listView.getLayoutParams();
    final int height = totalHeight
            + (listView.getDividerHeight() * (listAdapter.getGroupCount() - 1));
    params.height = height;
    listView.setLayoutParams(params);
    listView.requestLayout();
}

并在列表组单击时分配此方法:

expandableListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
    @Override
    public boolean onGroupClick(final ExpandableListView expandableListView, final View view, final int groupPosition, final long id) {
        setListViewHeight(expandableListView, groupPosition);
        return false;
    }
});

注意事项:虽然这段代码在大多数情况下都可以工作,但当子列表项是android:layout_height="wrap_content"的TextView时,我遇到了一些问题,因此它们的高度取决于它们的宽度,这可能与这个问题有关:ViewGroup{TextView,...}.getMeasuredHeight gives wrong value is smaller than real height .请,写一个评论,如果你设法修复它.

bz4sfanl

bz4sfanl5#

不幸的是,似乎没有一种方法可以使用wrap_content作为ExpandableListView的高度。相反,设置一个固定的高度和android:nestedScrollingEnabled="true"对我来说是有效的。

8oomwypt

8oomwypt6#

我发现了一种更好的方法来实现这一现象,下面的Kotlin代码不太复杂,效率更高。
在此之前,请记住以下几点:
1.使用固定的height父视图和子视图。
1.将父项和子项的高度提取到dimens.xml文件中。
1.在可扩展列表视图中设置divider='@null'scrollbars="none"groupIndicator="@null"(对于自定义组指示符,否则忽略)。
1.切勿使用paddingVertical(包括paddingToppaddingBottom),对于具有动态高度的视图,请将其替换为layoutMargins

代码逻辑(对我来说,这个块是名为initUi(uiObject)的ViewModel函数的一部分)

//Here `ui` is a DataBinding object.
//You can use ViewBinding or simple Android findViewById as per your comfort.

val data: List<ModelClass> = listObject
val context = ui.root.context

ui.expandableList.apply {
    val mAdapter = MyExpandableListAdapter(data, context)
    setAdapter(mAdapter)

    //fetching parent height from dimens.xml
    val parentViewHeight = ceil(
        context.resources.getDimension(R.dimen.layout_menu_parent_height)
    ).toInt()

    //fetching child height from dimens.xml
    val childViewHeight = ceil(
        context.resources.getDimension(R.dimen.layout_menu_child_height)
    ).toInt()

    //Setting up the initial height of view when All parents are collapsed
    layoutParams.height = data.size * parentViewHeight

    setOnGroupExpandListener { groupPosition ->
        //Increasing the height for Expanded SubCategory
        layoutParams.height += mAdapter.getChildrenCount(groupPosition) * childViewHeight
    }

    setOnGroupCollapseListener { groupPosition ->
        //Decreasing the height for Collapsed SubCategory
        layoutParams.height -= mAdapter.getChildrenCount(groupPosition) * childViewHeight
    }
}

MyExpandableListAdapter.kt

class FragmentMenuExpandableListAdapter(
    val data: List<Data>, val context: Context
): BaseExpandableListAdapter() {
    //Declaring inflater Once can save a lot of CPU and RAM uses... 
    private val inflater = LayoutInflater.from(context)

    override fun getGroupCount(): Int = data.size

    override fun getChildrenCount(groupPosition: Int): Int = data[groupPosition].subcategories.size

    override fun getGroup(groupPosition: Int): Data = data[groupPosition]

    override fun getChild(groupPosition: Int, childPosition: Int) = data[groupPosition].subcategories[childPosition]

    override fun getGroupId(groupPosition: Int): Long = groupPosition.toLong()

    override fun getChildId(groupPosition: Int, childPosition: Int): Long = "$groupPosition$childPosition0".toLong()

    override fun hasStableIds(): Boolean = true

    override fun getGroupView(
        groupPosition: Int,
        isExpanded: Boolean,
        convertView: View?,
        parent: ViewGroup
    ): View {
        val binding = LayoutMenuParentBinding.inflate(inflater, parent, false)
        binding.apply {
            val temp = getGroup(groupPosition)
            title.text = temp.category_name

            //here I used a custom ImageView as GroupIndicator
            //So following code chunk is Optional
            if(temp.subcategories.isEmpty()) dropdownIcon.visibility = View.GONE
            else dropdownIcon.let { icon ->
                val view = parent as ExpandableListView
                icon.setImageResource(
                    if(view.isGroupExpanded(groupPosition)) {
                        icon.setOnClickListener { view.collapseGroup(groupPosition) }
                        R.drawable.ic_state_expanded
                    }
                    else {
                        icon.setOnClickListener {
                            view.expandGroup(groupPosition)
                        }
                        R.drawable.ic_state_collapsed
                    }
                )
            }

            root.setOnClickListener {
                TODO("Do on Parent click")
            }
        }
        return binding.root
    }

    override fun getChildView(
        groupPosition: Int,
        childPosition: Int,
        isLastChild: Boolean,
        convertView: View?,
        parent: ViewGroup?
    ): View {
        val binding = LayoutMenuChildBinding.inflate(
            inflater, parent, false
        ).apply {
            val temp = getChild(groupPosition, childPosition)
            title.text = temp.categoryName

            root.setOnClickListener {
                TODO("Do on Child click")
            }
        }
        return binding.root
    }

    override fun isChildSelectable(groupPosition: Int, childPosition: Int): Boolean = true
}
nkoocmlb

nkoocmlb7#

在我例子中,wrap_content和match_parent不起作用。我有一个解决方案,适用于所有屏幕分辨率。尝试添加一个自定义的可扩展列表视图,如下所示,并在XML文件中使用该视图。

public class CustomExpandableListview extends ExpandableListView { 
   
     public CustomExpandableListview(Context context, AttributeSet attrs) { 
            super(context, attrs);        
 }       

@Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
         int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);       
    super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);             
    ViewGroup.LayoutParams params = getLayoutParams();            
    params.height = getMeasuredHeight();         
   } 
}

<com.ui.CustomExpandableListview     
android:id="@+id/device_break_down_list"     
android:layout_width="match_parent"     
android:layout_height="wrap_content"     
android:groupIndicator="@null" />

相关问题