可扩展列表视图将组图标指示器移动到右侧

67

关于可扩展列表视图,组图标指示器位于左侧,我可以将指示器移动并放置在右侧吗?谢谢。

编辑:由于我不想扩展视图,我采用了获取宽度的解决方法。只是分享我的解决方案。

Display newDisplay = getWindowManager().getDefaultDisplay(); 
int width = newDisplay.getWidth();
newListView.setIndicatorBounds(width-50, width);


1
在Nexus 7上无法正常工作。在实施此解决方案之前,请查看https://dev59.com/QG025IYBdhLWcg3wyJGV#18013962。 - SkyWalker
16个回答

71

setIndicatorBounds(int, int)在Android 4.3上无法正常工作。 他们引入了一个新方法setIndicatorBoundsRelative(int, int),该方法适用于4.3。

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
       mExpandableListView.setIndicatorBounds(myLeft, myRight);
    } else {
       mExpandableListView.setIndicatorBoundsRelative(myLeft, myRight);
    }
}

3
我曾因为所有网络上的代码都不起作用而感到疯狂!!!这个答案肯定需要更多的关注。 - AndroidNoob
我已将目标API级别设置为18,但我收到了“ExpandableListView”没有此方法的错误。可能出了什么问题? - Rat-a-tat-a-tat Ratatouille
1
我在此处找到了解决方案,谢谢。 - Rat-a-tat-a-tat Ratatouille
你应该将API 18设置为项目的构建目标 - 这与AndroidManifest.xml中的“targetSdk”属性不同。例如,您可以将targetSdk =“14”和项目BUILD目标=“18”。 - luben
哦天啊!终于可以工作了,但是为什么会这样?有什么具体的说明吗? - skygeek

46

完全的XML解决方案! 我发现了一种更好的解决方法。这不需要你干扰显示度量,也不需要编程技巧。

以下是你需要做的:

1)将布局方向设置为从右到左

<ExpandableListView
...
android:layoutDirection="rtl" />

2) 确保您的列表项布局包括以下内容(是的,您需要自定义布局):

android:gravity="left" //to adjust the text to align to the left again
android:layoutDirection="ltr"  //OR this line, based on your layout

然后您就可以开始使用了!


3
它会影响子项,确保也更新子项的布局。 - Abduaziz Kayumov
1
好的解决方案,但并非适用于所有人。滚动条将位于左侧。此外,还需要更改子视图。我应该说这是一个变通方法。 - Sevastyan Savanyuk

39
下面是最佳方法,但并非适用于所有Android版本,因此请使用下面指定的第二或第三种方法。
ViewTreeObserver vto = mExpandableListView.getViewTreeObserver();

    vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
                 mExpandableListView.setIndicatorBounds(mExpandableListView.getRight()- 40, mExpandableListView.getWidth());
        }
    });
或者这个:
@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    mExpandableListView.setIndicatorBounds(mExpandableListView.getRight()- 40, mExpandableListView.getWidth());
} 

甚至在设备和平板电脑上,都将把该指示符移动到列表视图的右侧。

或者你可以在一个postdelayed线程中实现这个功能。

 (new Handler()).post(new Runnable() {

        @Override
        public void run() {
              mExpandableListView.setIndicatorBounds(mExpandableListView.getRight()- 40, mExpandableListView.getWidth());
        }
    });

7
好的解决方案!但是请注意,setIndicatorBounds()方法设置的左右边界单位是像素(pixels),而不是设备独立像素(DIP)。您的答案在不同屏幕密度的设备上可能无法正常工作。确保在减去偏移量之前,将40 DP转换为像素[pixels],可以参考此链接 - Gautam
@Gautam 是的,你说得对,我在我的项目中也这样做了,但是忘记提到了。对你的评论点赞+1。 - varun bhardwaj
这里无论是 onWindowFocusChanged 代码还是 getViewTreeObserver 代码都不起作用。虽然 getRight 和 getWidth 均返回正确的值,但 setIndicatorBounds 似乎没有任何作用。可能还需要其他一些东西吗?例如项目和组的布局规则? - user153275
1
在哪里可以重写onWindowFocusChanged(boolean hasFocus)方法? - Ibrahim Disouki

20

根据ExpandableListView的源代码,将指示器移动到右侧的唯一方法是使用ExpandableListView.setIndicatorBounds()方法更改其边界。你可以在onSizeChanged()方法中计算边界。


谢谢Pixie。我尝试了newListView.setIndicatorBounds(newListView.getWidth()-40, newListView.getWidth()); 但是指示器消失了。当我获取getWidth()的值时,它返回零。这是否意味着我必须扩展可扩展列表视图以覆盖onSizeChanged()?谢谢。 - iamtheexp01
1
顺便提一下,我尝试设置一个静态值newListView.setIndicatorBounds(140, 150);,它起作用了。但是如何动态获取宽度呢?谢谢。 - iamtheexp01
我认为它的宽度为零,因为它尚未被测量。因此,获取其宽度并对大小更改做出反应的最明显方法是覆盖onSizeChanged()方法。也许有更简单的方法可以做到这一点,但我不知道任何方法。 - Michael

11

我尝试使用setIndicatorBounds和setIndicatorBoundsRelative,但图标的显示效果不如预期。所以我根据以下代码进行了更改:

创建一个组布局:

    <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="48dp"
    android:background="@drawable/header_selector" >

    <ImageView
        android:id="@+id/icon"
        android:layout_width="25dp"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:layout_marginLeft="12dp"
        android:layout_marginRight="12dp"
        android:contentDescription="@string/desc_list_item_icon"
        android:src="@drawable/ic_home" />

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_toRightOf="@id/icon"
        android:gravity="center_vertical"
        android:minHeight="?android:attr/listPreferredItemHeightSmall"
        android:paddingRight="40dp"
        android:textAppearance="?android:attr/textAppearanceListItemSmall"
        android:textColor="@color/list_item_title" />

    <TextView
        android:id="@+id/counter"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginRight="8dp"
        android:background="@drawable/counter_bg"
        android:textColor="@color/counter_text_color" />

    <ImageView
        android:id="@+id/icon_expand"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="200dp"
        android:layout_toRightOf="@+id/counter"
        android:contentDescription="@string/desc_list_item_icon"
        android:src="@drawable/navigation_expand"
        android:visibility="visible" />

    <ImageView
        android:id="@+id/icon_collapse"
        android:layout_width="25dp"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="200dp"
        android:layout_toRightOf="@+id/counter"
        android:contentDescription="@string/desc_list_item_icon"
        android:src="@drawable/navigation_collapse"
        android:visibility="gone" /> 

</RelativeLayout>

并在适配器类中的getGroupView方法中使用此布局:

 @Override
    public View getGroupView(int groupPosition, boolean isExpanded,
            View convertView, ViewGroup parent) {

        NavDrawerItem itemHeader = (NavDrawerItem) getGroup(groupPosition);

        LayoutInflater inflater = (LayoutInflater) this.context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        View view = null;
        if (convertView == null) {
            view = (View) inflater.inflate(R.layout.drawer_header_item, null);
        } else {
            view = convertView;
        }

        ImageView icon = (ImageView) view.findViewById(R.id.icon);

        if (itemHeader.isIconVisible()) {
            icon.setImageResource(itemHeader.getIcon());
        } else {
            icon.setVisibility(View.GONE);
        }

        TextView textTitle = (TextView) view.findViewById(R.id.title);
        textTitle.setText(" " + itemHeader.getTitle());

        TextView textCount = (TextView) view.findViewById(R.id.counter);

        if (itemHeader.getCounterVisibility()) {
            textCount.setText(itemHeader.getCount());
        } else {
            textCount.setVisibility(View.GONE);
        }

        ImageView iconExpand = (ImageView) view.findViewById(R.id.icon_expand);
        ImageView iconCollapse = (ImageView) view
                .findViewById(R.id.icon_collapse);

        if (isExpanded) {
            iconExpand.setVisibility(View.GONE);
            iconCollapse.setVisibility(View.VISIBLE);
        } else {
            iconExpand.setVisibility(View.VISIBLE);
            iconCollapse.setVisibility(View.GONE);
        }

        if (getChildrenCount(groupPosition) == 0) {
            iconExpand.setVisibility(View.GONE);
            iconCollapse.setVisibility(View.GONE);
        }

        return view;
    }

使用这种方法,您可以适当调整展开/折叠图标的位置。希望能对您有所帮助。


这种用户管理的方法更好、更干净。默认的使用9-patch底部指示器的方法对我来说已经过时了。 - WindRider

5

如何将可展开列表的组图标指示器移动到右侧

setIndicatorBounds(int left, int right) 方法用于设置可展开列表视图中组视图的指示器范围。

explvList.setIndicatorBounds(width-GetDipsFromPixel(35), width-GetDipsFromPixel(5));
Here width means device width.

/Convert pixel to dip 
public int GetDipsFromPixel(float pixels)
{
        // Get the screen's density scale
        final float scale = getResources().getDisplayMetrics().density;
        // Convert the dps to pixels, based on density scale
        return (int) (pixels * scale + 0.5f);
} 

注意: 宽度等于在 setBounds 方法中指定的宽度。在我的代码片段中,宽度为35,否则图标会受到干扰。有关更多详细信息,请访问以下链接:


3
在可扩展的基础适配器(Expandable Base adapter)中编写以下代码。
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
                         View convertView, ViewGroup parent) {
    ImageView imgs;

    String headerTitle = (String) getGroup(groupPosition);
    if (convertView == null) {
        LayoutInflater infalInflater = (LayoutInflater) this._context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = infalInflater.inflate(R.layout.list_group, null);
    }

    TextView lblListHeader = (TextView) convertView
            .findViewById(R.id.lblListHeader);
     imgs = (ImageView) convertView
            .findViewById(R.id.img_list);
    lblListHeader.setTypeface(null, Typeface.BOLD);
    lblListHeader.setText(headerTitle);
    if (isExpanded) {
  imgs.setImageResource(R.drawable.up_arrow);
    }
    else {
        imgs.setImageResource(R.drawable.downs_arrow);
    }

    return convertView;
}
  • 列表项

这是一种简单易行的方法。 - Shozab Hasan

2

如果代码在Fragment的onViewCreated()方法中

    ViewTreeObserver vto = Expnlist.getViewTreeObserver();
    vto.addOnGlobalLayoutListener(new      ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            Expnlist.setIndicatorBounds(Expnlist.getMeasuredWidth() - 80, Expnlist.getMeasuredWidth());
        }
    });

这对我有用!干杯!


2
FIX: 

自API 18开始,他们引入了一种名为setIndicatorBoundsRelative(int, int)的新方法。您应该检查Android版本并使用相应的API方法:

expListView = (ExpandableListView) v.findViewById(R.id.laptop_list);

metrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
width = metrics.widthPixels;

if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
    expListView.setIndicatorBounds(width - GetDipsFromPixel(50), width - GetDipsFromPixel(10));

} else {
    expListView.setIndicatorBoundsRelative(width - GetDipsFromPixel(50), width - GetDipsFromPixel(10));

}

2

首先你需要从你的 XML 中删除群组指示器。

<ExpandableListView
            android:id="@+id/expandableListView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/nav_header_height"
            android:background="@android:color/white"
            android:dividerHeight="0dp"
            android:focusable="false"
            android:groupIndicator="@null" />

在您的自定义适配器中,请按照以下步骤操作。
public View getGroupView(int groupPosition, boolean isExpanded,
    View convertView, ViewGroup parent) {

if (isExpanded) {
    groupHolder.img.setImageResource(R.drawable.group_down);
} else {
    groupHolder.img.setImageResource(R.drawable.group_up);
}}

这就是我也解决它的方式,只是为了澄清一下可能会错过这个的人:img 是列表项布局文件中的 ImageView,因此您可以将其放置在任何位置,并使其作为组指示器。 - Michele

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接