GiveEmTheBoot
GiveEmTheBoot

Reputation: 544

Move checked item into expandable list view

I'm facing with a big problem with the ExpandableListView. My goal is to let user change item's position into this single selection expandable list view:

enter image description here

When an user clicks on an item, the item becomes checked and a context action bar appears. So user can move up or down an item in this way:

enter image description here

The move up/down function that i've implemented works fine (it's based on swap position over an ArrayList, that's the datasource of my BaseExpandableListAdapter, and notify changes to the UI). Unfortunately when i move a checked item, it looses the checked state...and if i move the item out of the visible bounds (in the example, after "Locked" or before "Attachements" view) the expandablelistview doesn't scroll to the new position.

How can i achieve that?

Below, my "moveDownFocusedItem()" coded into my custom Adapter class:

 //This class is ok!
 //Contains Group and Child position of an ExpandableListView
 public class Position{
    int GroupPosition;
    int ChildPosition;

    public boolean isChild(){
        return (ChildPosition != AbsListView.INVALID_POSITION);
    }


    public Position getPreviousPosition(){
        if(ChildPosition==AbsListView.INVALID_POSITION)
            if(GroupPosition>0)
                return new Position(GroupPosition-1);
            else
                return null;
        else
            if(ChildPosition>0)
                return new Position(GroupPosition, ChildPosition-1);
            else
                return null;
    }


    public Position getNextPosition(){
        if(ChildPosition==AbsListView.INVALID_POSITION)
            if(GroupPosition<_fieldConfigurationList.size()-1)
                return new Position(GroupPosition+1);
            else
                return null;
        else
              if(ChildPosition<_fieldConfigurationList.get(GroupPosition).getChildren().size()-1)
                return new Position(GroupPosition, ChildPosition+1);
            else
                return null;
    }

    public Position(int groupPosition){
        this.GroupPosition = groupPosition;
        this.ChildPosition = AbsListView.INVALID_POSITION;
    }

    public Position(int groupPosition, int childPosition){
        this.GroupPosition = groupPosition;
        this.ChildPosition = childPosition;
    }
}


public void moveDownFocusedItem(){

    //This function returns the next position to move to 
    //(_focusedPosition is the current checked item position)
    Position nextPosition = this._focusedPosition.getNextPosition();

    //Swap ArrayList (This works!)
    if(nextPosition!=null){ 
        Collections.swap(this._fieldConfigurationList,  //that's my datasource
                         this._focusedPosition.GroupPosition,  //Start position for swapping
                         nextPosition.GroupPosition);   //Destination position for swapping

    //Set the new focused position (This works!)
    this._focusedPosition = nextPosition;

    //TODO:
    //Now i have to call "SetItemChecked()" method to uncheck old focused position and check the new one.
    //How to do it? How can i get the required "position" argument from _focusedPosition.GroupPosition and _focusedPosition.ChildPosition?
    //And also...if the focused view has moved to an invisible position (such as the end of the expandablelistview) how can i scroll 
    //to this position?

    //Notify changes (This works!)
    this.notifyDataSetChanged();

    }
}

Upvotes: 2

Views: 2303

Answers (1)

GiveEmTheBoot
GiveEmTheBoot

Reputation: 544

After studying the code behind the expandablelistview, i found a fairly simple way to the required task. I 'll publish part of my adapter that allows to check a listview items and move it up and down. Remember: 1) make sure your expandablelistview is in "single selection" mode (ExpandableListView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);)

2) Your custom row view has android:descendantFocusability="blocksDescendants"

I've done several tests on android J.B and seems to work correctly without errors or memory leaks. In case of bugs, please post improovements or fixes. This is my code:

public class MyAdapter extends BaseExpandableListAdapter {

//protected ArrayList<Object> _list; //TODO: Replace with your datasource
private ExpandableListView _expandableListView;
private long _checkedPosition;

public long getCheckedPosition(){
    return _checkedPosition;
}
public void setCheckedPosition(int groupPosition){
    long packedPosition = ExpandableListView.getPackedPositionForGroup(groupPosition);
    this.setCheckedPosition(packedPosition);
}
public void setCheckedPosition(int groupPosition, int childPosition){
    long packedPosition = ExpandableListView.getPackedPositionForChild(groupPosition, childPosition);
    this.setCheckedPosition(packedPosition);
}
public void setCheckedPosition(long position){
    final int flatPosition;

    //Gets flat position
    flatPosition = _expandableListView.getFlatListPosition(position);

    //Set the new position, checked and focused
    _expandableListView.setItemChecked(flatPosition , true);
    _checkedPosition = position;

    //If it's out of bounds, set focus on it and force scroll (postpone because row's views may not exists yes)
    if(flatPosition<_expandableListView.getFirstVisiblePosition() || 
       flatPosition>_expandableListView.getLastVisiblePosition())
        _expandableListView.post(new Runnable() {

            @Override
            public void run() {
                _expandableListView.setSelection(flatPosition);     
            }
        });
}

public void clearCheckedPosition(){
    final int flatPosition;

    flatPosition = _expandableListView.getFlatListPosition(getCheckedPosition());
    _expandableListView.setItemChecked(flatPosition , false);
}


private long getPreviousPosition(long position){
    int group = ExpandableListView.getPackedPositionGroup(position);
    int child = ExpandableListView.getPackedPositionChild(position);

    if(child==-1)
        if(group>0)
            return ExpandableListView.getPackedPositionForGroup(group-1); 
        else
            return -1;
    else
        if(child>0)
            return ExpandableListView.getPackedPositionForChild(group, child-1);
        else
            return -1;
}

private long getNextPosition(long position){
    int group = ExpandableListView.getPackedPositionGroup(position);
    int child = ExpandableListView.getPackedPositionChild(position);

    if(child==-1)
        if(group<getGroupCount()-1)
            return ExpandableListView.getPackedPositionForGroup(group+1);
        else
            return -1;
    else
        if(child<getChildrenCount(group)-1)
            return ExpandableListView.getPackedPositionForChild(group, child+1);
        else
            return -1;
}


public boolean canMoveUpCheckedItem(){

    if(getCheckedPosition()!=-1)
        if(getPreviousPosition(getCheckedPosition())!=-1)
            return true;
    return false;
}

public boolean canMoveDownCheckedItem(){
    if(getCheckedPosition()!=-1)
        if(getNextPosition(getCheckedPosition())!=-1)
            return true;
    return false;
}


public void moveUpFocusedItem(){

    long prevPosition = this.getPreviousPosition(getCheckedPosition());
    if(prevPosition!=-1L){  
        //Swap position
        switch(ExpandableListView.getPackedPositionType(getCheckedPosition())){
        case ExpandableListView.PACKED_POSITION_TYPE_GROUP:
            //Collapse group if expanded
            _expandableListView.collapseGroup(ExpandableListView.getPackedPositionGroup(getCheckedPosition()));

            //TODO:Implement group swap
            /*Collections.swap(this._list,
                             ExpandableListView.getPackedPositionGroup(getCheckedPosition()),
                             ExpandableListView.getPackedPositionGroup(prevPosition));*/
            break;

        case ExpandableListView.PACKED_POSITION_TYPE_CHILD:

            //TODO:Implement child swap
            /**Collections.swap(this._list.get(ExpandableListView.getPackedPositionGroup(getCheckedPosition())).getChildren(), 
                            ExpandableListView.getPackedPositionChild(getCheckedPosition()), 
                            ExpandableListView.getPackedPositionChild(prevPosition));**/
            break;

        }

        //Set new focused position
        this.setCheckedPosition(prevPosition);

        //Notify changes
        this.notifyDataSetChanged();

    }
}

public void moveDownFocusedItem(){
    long nextPosition =  this.getNextPosition(getCheckedPosition());
    if(nextPosition!=-1L){
        switch(ExpandableListView.getPackedPositionType(getCheckedPosition())){
        case ExpandableListView.PACKED_POSITION_TYPE_GROUP:
            //Collapse group if expanded
            _expandableListView.collapseGroup(ExpandableListView.getPackedPositionGroup(getCheckedPosition()));

            //TODO:Implement group swap
            /*Collections.swap(this._list, 
                             ExpandableListView.getPackedPositionGroup(getCheckedPosition()), 
                             ExpandableListView.getPackedPositionGroup(nextPosition));*/
            break;

        case ExpandableListView.PACKED_POSITION_TYPE_CHILD: 

            //TODO:Implement child swap
            /*Collections.swap(this._list.get(ExpandableListView.getPackedPositionGroup(getCheckedPosition())).getChildren(), 
                             ExpandableListView.getPackedPositionChild(getCheckedPosition()), 
                             ExpandableListView.getPackedPositionChild(nextPosition));*/
            break;
        }

        //Set new focused position
        this.setCheckedPosition(nextPosition);

        //Notify changes
        this.notifyDataSetChanged();

    }
}







@Override
public Object getChild(int groupPosition, int childPosition) {
    //TODO: Implement
}

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

@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
    //TODO: Implement
}

@Override
public int getChildrenCount(int groupPosition) {
    //TODO: Implement
}

@Override
public Object getGroup(int groupPosition) {
    //TODO: Implement
}

@Override
public int getGroupCount() {
    //TODO: Implement
}

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

@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
    //TODO: Implement your getGroupView
}

@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
    //TODO: Implement
}

@Override
public boolean hasStableIds() {
    //TODO: Implement
}

}

Upvotes: 1

Related Questions