android - 每行有多个 child 的 ExpandableListView

标签 android expandablelistview

我想达到以下结果:

enter image description here

为此,我正在使用 ExpandableListView 但使用它我设法在每一行中只显示一个 child 。实际上我想要的是在每一行中显示三个 child 。

有什么方法可以用 ExpandableListView 实现吗? 如果无法使用 ExpandableListView 那么还有其他解决方案吗?

最佳答案

看起来您希望将 GridView 作为可扩展 ListView 的项目获取。以下博客文章似乎很有前途。试一试:

https://nishantsh.blogspot.com/2017/05/android-gridview-as-expandablelistview.html

以下是博文中提供的内容:

  1. 首先创建一个名为 MyCustomGridView.java 的自定义 gridView 类,并向其中添加以下代码 fragment :
public class MyCustomGridView extends GridView {

    private final Context mContext;
    int mHeight;

    public MyCustomGridView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
    }

    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int desiredWidth = 100;
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int width;
        // Measure Width
        if (widthMode == MeasureSpec.EXACTLY) {
            // Must be this size
            width = widthSize;
        } else if (widthMode == MeasureSpec.AT_MOST) {
            // Can't be bigger than...
            width = Math.min(desiredWidth, widthSize);
        } else { // Be whatever you want
            width = desiredWidth;
        }
        // MUST CALL THIS
        setMeasuredDimension(width, mHeight);
        getGridViewSpanCount(width, mHeight);
    }

    public void setGridViewItemHeight(int height) {
        mHeight = height;
    }
}
  1. 现在创建名为 gridview_item.xml 的布局文件,它将用作 GridView 的项目:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/item_gridView_imgView"
        android:layout_width="@dimen/dimen_img_width"
        android:layout_height="@dimen/dimen_img_height"
        android:scaleType="centerCrop" />

    <TextView
        android:id="@+id/item_gridView_txtView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:maxLines="1"
        android:textAlignment="center"
        android:textColor="@color/black"
        android:textSize="16sp" />

</RelativeLayout>
  1. 现在创建名为 MyCustomGridViewAdapter.java 的适配器,用于在您的 gridView 中设置 View ,如下所示:
public class MyCustomGridViewAdapter extends BaseAdapter {

    private Context mContext;
    private final ArrayList<YOUR_CLASS_TYPE> arrayList;

    public MyCustomGridViewAdapter(Context context, ArrayList<YOUR_CLASS_TYPE> arrayList) {
        this.mContext = context;
        this.arrayList = arrayList;
    }

    @Override
    public int getCount() {
        return arrayList.size();
    }

    @Override
    public YOUR_CLASS_TYPE getItem(int position) {
        return arrayList.get(position);
    }

    @Override
    public long getItemId(int arg0) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) mContext
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.gridview_item, parent, false);
            holder = new ViewHolder();
            holder.text = (TextView) convertView.findViewById(R.id.item_gridView_txtView);
            holder.imageView = (ImageView) convertView.findViewById(R.id.item_gridView_imgView);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.text.setText(arrayList.get(position).getName());
  // Glide is the library used to laod an image into an imageView
        Glide.with(mContext).load(arrayList.get(position).getThumbnail_url())
                .asBitmap().centerCrop()
                .diskCacheStrategy(DiskCacheStrategy.SOURCE)
                .into(holder.imageView);
        return convertView;
    }

    private static class ViewHolder {
        TextView text;
        ImageView imageView;
    }
}

  1. 现在创建一个名为 ExpandableListViewFragment.java 的 fragment 并添加以下代码 fragment :
public class ExpandableListViewFragment extends Fragment implements GridViewItemClickInterface {

    private List<String> listDataHeader;
    private HashMap<String, ArrayList<YOUR_CLASS_TYPE>> listDataChild;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.layout_fragment_expandable_listvw, container, false);

        ExpandableListView mExpandablelistView = (ExpandableListView) rootView.findViewById(R.id.fragment_expandable_listview);
        prepareListData();
        CustomExpandableListAdapter mExpandableListAdapter = new CustomExpandableListAdapter(getActivity(), listDataHeader, listDataChild, this);
        mExpandablelistView.setAdapter(mExpandableListAdapter);
        mExpandablelistView.setOnGroupClickListener(new OnGroupClickListener() {
         @Override
         public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
                // This way the expander cannot be collapsed
                // on click event of group item
                return false;
            }
        });
        return rootView;
    }

    private void prepareListData() {
        listDataHeader = new ArrayList<>();
        listDataHeader.add("Folder 1");
        listDataHeader.add("Folder 2");
        listDataChild = new HashMap<>();
        ArrayList<YOUR_CLASS_TYPE> details = new ArrayList<YOUR_CLASS_TYPE>();// fill the data as per your requirements
        listDataChild.put(listDataHeader.get(0), details);
        listDataChild.put(listDataHeader.get(1), null); // just to show null item view
    }

    @Override
    public void onGridViewItemClick(YOUR_CLASS_TYPE item) {
        Toast.makeText(getActivity(), "Currently selected is: " + item.getName(), Toast.LENGTH_SHORT).show();
    }
}
  1. 上述 fragment 的布局文件如下:layout_fragment_expandable_listvw.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

        <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ExpandableListView
            android:id="@+id/fragment_expandable_listview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:divider="@color/transparent"
            android:listSelector="@color/transparent" />

    </RelativeLayout>

</LinearLayout>
  1. 现在使用以下代码 fragment 创建名为 CustomExpandableListAdapter.java 的适配器文件:
public class CustomExpandableListAdapter extends BaseExpandableListAdapter {

    private Context mContext;
    private List<String> mListDataHeader;
    private HashMap<String, ArrayList<YOUR_CLASS_TYPE>> mListDataChild;
    private LayoutInflater mInflater;
    private GridViewItemClickInterface gridViewItemClickListener;
    private int columnsCount = 3;

    public CustomExpandableListAdapter(Context context, List<String> listDataHeader, HashMap<String, ArrayList<YOUR_CLASS_TYPE>> listChildData, GridViewItemClickInterface listener) {
        this.mContext = context;
        this.mListDataHeader = listDataHeader;
        this.mListDataChild = listChildData;
        this.mInflater = LayoutInflater.from(context);
        this.gridViewItemClickListener = listener;
    }

    @Override
    public int getGroupCount() {
        return mListDataHeader.size();
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        return 1;
    }

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

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return mListDataChild.get(this.mListDataHeader.get(groupPosition))
                .size();
    }

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

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

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

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        String headerTitle = (String) getGroup(groupPosition);
        if (convertView == null) {
            // layout view of header group
            convertView = mInflater.inflate(R.layout.expandable_listvw_header, null);
        }
        TextView headerLabel = (TextView) convertView.findViewById(R.id.txtView_header);
        headerLabel.setTypeface(null, Typeface.BOLD);
        headerLabel.setText(headerTitle);
        return convertView;
    }

    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        convertView = mInflater.inflate(R.layout.expandable_listvw_item, null);
        final ArrayList<YOUR_CLASS_TYPE> items = mListDataChild.get(mListDataHeader.get(groupPosition));
        if (items.size() > 0) {
            MyCustomGridView gridView = (MyCustomGridView) convertView.findViewById(R.id.item_custom_gridView);
            gridView.setNumColumns(columnsCount);
            gridView.setVerticalSpacing(10);
            gridView.setHorizontalSpacing(10);
            MyCustomGridViewAdapter adapter = new MyCustomGridViewAdapter(mContext, items);
            gridView.setAdapter(adapter);
            int totalHeight = 0;
// This is to get the actual size of gridView at runtime while filling the items into it
            for (int size = 0; size < adapter.getCount(); size++) {
                RelativeLayout relativeLayout = (RelativeLayout) adapter.getView(size, null, gridView);
                relativeLayout.measure(0, 0);
                totalHeight += relativeLayout.getMeasuredHeight();
            }
            gridView.setGridViewItemHeight(v);
            gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    gridViewItemClickListener.onGridViewItemClick(items.get(position));
                }
            });
        } else {
            convertView = mInflater.inflate(R.layout.layout_blank, null);
        }

        return convertView;
    }

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

}
  1. ExpandableListView组和item的布局文件如下:

a) expandable_listvw_header.xml

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

    <TextView
        android:id="@+id/txtView_header"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="@color/colorBlack"
        android:textSize="22sp" />

</LinearLayout>

b) expandable_listvw_item.xml

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

    <com.nishant.sample.ExpandableListPac.MyCustomGridView
        android:id="@+id/item_custom_gridView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

c) layout_blank.xml - 这是在没有项目可用时显示的布局。

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

    <TextView
        android:id="@+id/item_txt_no_items"
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:gravity="center_horizontal|center_vertical"
        android:text="No items available"
        android:textSize="22sp" />

</LinearLayout>
  1. 接口(interface)类GridViewItemClickInterface.java如下:
public interface GridViewItemClickInterface {

    void onGridViewItemClick(YOUR_CLASS_TYPE item);
}

关于android - 每行有多个 child 的 ExpandableListView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56505736/

相关文章:

android - 如何从 SD 卡中检索文本并相应地设置 TextView ?

android - 手机上 NETWORK_PROVIDER 的 getLastKnownLocation 返回 null

java - 如何使用 ExpandableListView 创建小部件?

listview - Android ListView 滚动到底部时动态加载更多项目(来自 MysqlDatabase)

Android ExpandableListView 如何保存展开/折叠状态?

android - 如何实现绘画更新循环?

java - mStartTime 无法解析为变量

java - 启动 Intent 查看器以显示来自 url 的图像

android - 如何获取 ExpandableListView 在 Android 上可绘制的组指示器的宽度?

android - 使用 SimpleCursorTreeAdapter 单击 ExpandableListView subview 中按钮的监听器