GridView inside ExpandableListView with multiple choice on Android
Asked Answered
I

2

8

In my app I need to show images inside a expandableListView and it has to be a gridview of images, and these images can be selectable so I have an expandableListAdapter and inside of it I'm implementing a gridview adapter, the images are showing fine as you can see in the picture 1, now what I'm trying to achieve is the picture 2, how can I pass the groupPosition and the childPosition to the gridAdapter and whe I click on the image make it highlight? :

enter image description here

Picture 2: enter image description here

public class ExpandListAdapter extends BaseExpandableListAdapter {


    public static final int CHOICE_MODE_MULTIPLE = AbsListView.CHOICE_MODE_MULTIPLE;


    public static final int CHOICE_MODE_MULTIPLE_MODAL = AbsListView.CHOICE_MODE_MULTIPLE_MODAL;

    /**
     * No child could be selected
     */
    public static final int CHOICE_MODE_NONE = AbsListView.CHOICE_MODE_NONE;

    /**
     * One single choice per group
     */
    public static final int CHOICE_MODE_SINGLE_PER_GROUP = AbsListView.CHOICE_MODE_SINGLE;

    /**
     * One single choice for all the groups
     */
    public static final int CHOICE_MODE_SINGLE_ABSOLUTE = 10001;

    private Context context;
    private ArrayList<Group> groups;
    private ArrayList<ArrayList<Child>> child = new ArrayList();
    private ArrayList<Child> listchild;
    private GridAdapter adapter;
    private CustomGridView gridView;
    private SparseArray<SparseBooleanArray> checkedPositions;
    private static final String LOG_TAG = ExpandListAdapter.class.getSimpleName();

    private int choiceMode = CHOICE_MODE_MULTIPLE;

    public ExpandListAdapter(Context context, ArrayList<Group> groups) {
        this.context = context;
        this.groups = groups;
        checkedPositions = new SparseArray<SparseBooleanArray>();
        child = new ArrayList();
        for (int i = 0; i < groups.size(); i++) {
            child.add(i, groups.get(i).getItems());
        }
    }

    public ExpandListAdapter(Context context, ArrayList<Group> children, int choiceMode) {
        this(context, children);
        // For now the choice mode CHOICE_MODE_MULTIPLE_MODAL
        // is not implemented
        if (choiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
            throw new RuntimeException("The choice mode CHOICE_MODE_MULTIPLE_MODAL " +
                    "has not implemented yet");
        }
        this.choiceMode = choiceMode;
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return child.get(childPosition);
    }

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

    @Override
    public View getChildView(final int groupPosition, final int childPosition,
                             boolean isLastChild, View convertView, ViewGroup parent) {


        if (convertView == null) {
            LayoutInflater infalInflater = (LayoutInflater) context
                    .getSystemService(context.LAYOUT_INFLATER_SERVICE);
            convertView = infalInflater.inflate(R.layout.gridview, null);
        }


        listchild = new ArrayList<Child>();

        for (int j = 0; j < groups.get(groupPosition).getItems().size(); j++) {

            listchild.add(child.get(groupPosition).get(j));

        }

        gridView = (CustomGridView) convertView.findViewById(R.id.GridView_toolbar);

        gridView.setExpanded(true);
        adapter = new GridAdapter(context, listchild, checkedPositions, groupPosition, childPosition);
        gridView.setAdapter(adapter);// Adapter
        gridView.setChoiceMode(CustomGridView.CHOICE_MODE_MULTIPLE);
        gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                setClicked(groupPosition, childPosition);
                System.out.println("position" + checkedPositions.get(groupPosition));
                if (checkedPositions.get(groupPosition) != null) {
                    boolean isChecked = checkedPositions.get(groupPosition).get(childPosition);

                    if(!isChecked){
                    }

                } else {
                    System.out.println("false");
                }

            }
        });


        return convertView;

    }

    public void setClicked(int groupPosition, int childPosition) {
        switch (choiceMode) {
            case CHOICE_MODE_MULTIPLE:
                SparseBooleanArray checkedChildPositionsMultiple = checkedPositions.get(groupPosition);
                // if in the group there was not any child checked
                if (checkedChildPositionsMultiple == null) {
                    checkedChildPositionsMultiple = new SparseBooleanArray();
                    // By default, the status of a child is not checked
                    // So a click will enable it
                    checkedChildPositionsMultiple.put(childPosition, true);
                    checkedPositions.put(groupPosition, checkedChildPositionsMultiple);
                } else {
                    boolean oldState = checkedChildPositionsMultiple.get(childPosition);
                    checkedChildPositionsMultiple.put(childPosition, !oldState);
                }
                break;
            // TODO: Implement it
            case CHOICE_MODE_MULTIPLE_MODAL:
                throw new RuntimeException("The choice mode CHOICE_MODE_MULTIPLE_MODAL " +
                        "has not implemented yet");
            case CHOICE_MODE_NONE:
                checkedPositions.clear();
                break;
            case CHOICE_MODE_SINGLE_PER_GROUP:
                SparseBooleanArray checkedChildPositionsSingle = checkedPositions.get(groupPosition);
                // If in the group there was not any child checked
                if (checkedChildPositionsSingle == null) {
                    checkedChildPositionsSingle = new SparseBooleanArray();
                    // By default, the status of a child is not checked
                    checkedChildPositionsSingle.put(childPosition, true);
                    checkedPositions.put(groupPosition, checkedChildPositionsSingle);
                } else {
                    boolean oldState = checkedChildPositionsSingle.get(childPosition);
                    // If the old state was false, set it as the unique one which is true
                    if (!oldState) {
                        checkedChildPositionsSingle.clear();
                        checkedChildPositionsSingle.put(childPosition, !oldState);
                    } // Else does not allow the user to uncheck it
                }
                break;
            // This mode will remove all the checked positions from other groups
            // and enable just one from the selected group
            case CHOICE_MODE_SINGLE_ABSOLUTE:
                checkedPositions.clear();
                SparseBooleanArray checkedChildPositionsSingleAbsolute = new SparseBooleanArray();
                checkedChildPositionsSingleAbsolute.put(childPosition, true);
                checkedPositions.put(groupPosition, checkedChildPositionsSingleAbsolute);
                break;
        }

        // Notify that some data has been changed
        notifyDataSetChanged();
        Log.v(LOG_TAG, "List position updated");
        Log.v(LOG_TAG, PrintSparseArrays.sparseArrayToString(checkedPositions));
    }

    public void setChoiceMode(int choiceMode) {
        this.choiceMode = choiceMode;
        // For now the choice mode CHOICE_MODEL_MULTIPLE_MODAL
        // is not implemented
        if (choiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
            throw new RuntimeException("The choice mode CHOICE_MODE_MULTIPLE_MODAL " +
                    "has not implemented yet");
        }
        checkedPositions.clear();
        Log.v(LOG_TAG, "The choice mode has been changed. Now it is " + this.choiceMode);
    }

    @Override
    public int getChildrenCount(int nGroup) {
        return 1;

    }

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

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

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

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded,
                             View convertView, ViewGroup parent) {
        Group group = (Group) getGroup(groupPosition);
        if (convertView == null) {
            LayoutInflater inf = (LayoutInflater) context
                    .getSystemService(context.LAYOUT_INFLATER_SERVICE);
            convertView = inf.inflate(R.layout.group_item, null);
        }
        ExpandableListView mExpandableListView = (ExpandableListView) parent;
        mExpandableListView.expandGroup(groupPosition);
        TextView tv = (TextView) convertView.findViewById(R.id.group_name);
        tv.setText(group.getName());

        return convertView;
    }

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

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

}

GridAdapter:

public class GridAdapter extends BaseAdapter {

    private Context mContext;
    private ArrayList<Child> child;
    ImageLoader imageLoader = AppController.getInstance().getImageLoader();
    private SparseArray<SparseBooleanArray> checkedPositions;
    int groupPosition, childPosition;

    public GridAdapter(Context context, ArrayList<Child> childValues, SparseArray<SparseBooleanArray> checkedPositions, int groupPosition, int childPosition) {
        mContext = context;
        child = childValues;
        this.checkedPositions = checkedPositions;
        this.childPosition = childPosition;
        this.groupPosition = groupPosition;
    }


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

    @Override
    public Object getItem(int position) {
        return position;
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ViewHolder holder = null;
        NetworkImageView i;
        childPosition = position;

        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) mContext
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.child_item, null);
            holder = new ViewHolder();

            if (imageLoader == null)
                imageLoader = AppController.getInstance().getImageLoader();

            i = (NetworkImageView) convertView
                    .findViewById(R.id.flag);

            i.setImageUrl(String.valueOf(child.get(childPosition).getImage()), imageLoader);


            convertView.setTag(holder);

            System.out.println("position" + checkedPositions.get(groupPosition));
            if (checkedPositions.get(groupPosition) != null) {
                boolean isChecked = checkedPositions.get(groupPosition).get(childPosition);
                i.setBackgroundResource(R.color.bg);

                if(!isChecked){
                }

            } else {
                System.out.println("false");
            }


        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.text = (TextView) convertView.findViewById(R.id.label);
        holder.text.setText(child.get(position).getName());


        return convertView;
    }


    static class ViewHolder {
        TextView text;
    }


}
Ilmenite answered 2/5, 2015 at 19:19 Comment(2)
May you add your layout and main as well?Antigen
u need similar like this ans: https://mcmap.net/q/507171/-pinnedheader-google-plus-gridview/1168654Wizened
K
1

In My Assumption

ExpandListAdapter Class

  • In getChildView() method childPosition does not depends on what country flag is being clicked , Because childPosition here returns the position of the Grid view, not the flags under it

  • So, no need to pass childPosition in constructor of GridView ,since childPosition will always return 1

  • To get actual flag clicked position Use onClickListener inside your GridAdapter like:

@Override public View getView(int position, View convertView, ViewGroup parent) {

        ViewHolder holder = null;
        NetworkImageView i;
        childPosition = position;

        if (convertView == null) {

        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        convertView.setOnclickListener(new OnClickListener{

          @Override 
          onClick(View v){
      isChecked=child.get(childPosition).isChecked();
         if(!isChecked){
            child.get(childPosition).setChecked(true);
         }
         else {
            child.get(childPosition).setChecked(false);
         }        

      });

No need to handle checked positions separately create two methods in your child class isChecked() and setChecked() to maintain check-uncheck state of flags. Change color of selected or checked flag here

        holder.text = (TextView) convertView.findViewById(R.id.label);
        holder.text.setText(child.get(position).getName());


        return convertView;
  }

and remove your Check logic from ExpandListAdapter Class :

gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                    setClicked(groupPosition, childPosition);
                    System.out.println("position" + checkedPositions.get(groupPosition));
                    if (checkedPositions.get(groupPosition) != null) {
                        boolean isChecked = checkedPositions.get(groupPosition).get(childPosition);

                        if(!isChecked){
                        }

                    } else {
                        System.out.println("false");
                    }

                }
            });
Kosey answered 1/6, 2015 at 10:32 Comment(4)
can you edit your code, I'm getting nullpointerexception at isChecked=checkedPositions.get(groupPosition) .get(childPosition);Ilmenite
it is better maintain a checked- unchecked boolean flag inside your Child class. isChecked() return boolean It will reduce the workload and no need to maintain seperate *sparse array of checked positions. Hence Code can be : //for retreiving flag isChecked=child.get(childPosition).IsChecked(); //for setting flag child.get(childPosition).setChecked(true); I am editing the code accordinglyKosey
I've added a method in my child class like so: public boolean isChecked() { return false; } but that will always return false, is that correct? I can't see how it toggles when i click on the flagIlmenite
create a new variable in your child class example: private boolean mFlagCheckedState; //Method to receive Flag public boolean isChecked(){ return mFlagCheckedState; } //Method to Toggle Flag public boolean setChecked(boolean state){ this.mFlagCheckedState=state; }Kosey
W
0

You need to set an 'OnItemClickListener' to your gridAdapter, and overide the onItemClick method as following.

Note :- This will highlight the ImageView you click and if you happened to click another ImageView in the same GridView, that ImageView also will be highlighted! Like in a 'multiple selection'.

gridAdapter.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            ImageView selectedFlagImageView = (ImageView) view;
            selectedFlagImageView.setBackgroundColor(Color.parseColor("#37a93400"));
        }
    });

This will color the background of the selected ImageView. Color code I've used in here is simply, more alpha and less RGBs.(I used Android Studio color chooser)

android studio color chooser

Following images will give you an idea about how it will look when giving a background color like this.

Without background color :

image view with no background colors

With background color :

image view with background color

Whitsun answered 3/6, 2015 at 15:10 Comment(1)
No listener can be added to adaptersTedesco

© 2022 - 2024 — McMap. All rights reserved.