EditText content inside ExpandableListView disappear when clicking next ExpandableListView header
Asked Answered
T

4

12

I have an edittext inside an expandablelistview item child. Then, I entered a text inside this edittext, but whenever I click other expandablelistview header, the text I entered disappear.

I already used android:windowSoftInputMode="adjustPan" inside my Manifest.xml and many other possible fixes, but didn't work.

this is my adapter:

public class ExpendableAdapter extends BaseExpandableListAdapter {
    private Context _context;
    private List<String> _listDataHeader;
    private HashMap<String, List<ExpandItemModel>> _listDataChild;

public ExpendableAdapter(Context context, List<String> listDataHeader,
                             HashMap<String, List<ExpandItemModel>> listChildData) {
    this._context = context;
    this._listDataHeader = listDataHeader;
    this._listDataChild = listChildData;
}

@Override
public Object getChild(int groupPosition, int childPosititon) {
    return this._listDataChild.get(this._listDataHeader.get(groupPosition))
            .get(childPosititon);
}

@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) {

    final ExpandItemModel childText = (ExpandItemModel) getChild(groupPosition, childPosition);

    if (convertView == null) {
        LayoutInflater infalInflater = (LayoutInflater) this._context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = infalInflater.inflate(R.layout.list_item, null);
    }

    final EditText etTotal = (EditText)convertView
            .findViewById(R.id.et_total);

    etTotal.setText(childText.getTotal);

    return convertView;
}

@Override
public int getChildrenCount(int groupPosition) {
    return this._listDataChild.get(this._listDataHeader.get(groupPosition))
            .size();
}

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

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

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

@Override
public View getGroupView(int groupPosition, boolean isExpanded,
                         View convertView, ViewGroup parent) {
    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 tvHeader = (TextView) convertView
            .findViewById(R.id.tv_header);
    tvHeader.setTypeface(null, Typeface.BOLD);
    tvHeader.setText(headerTitle);

    return convertView;
}

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


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

And this is the layout:

<RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/rl_expen_but"
        android:layout_below="@+id/rl_ats_draft2"
        android:layout_above="@+id/selanjutnya"
        >



        <ExpandableListView
            android:background="@color/cardview_light_background"
            android:id="@+id/lvExp"
            android:descendantFocusability="beforeDescendants"
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:animateLayoutChanges="true"/>

        <View
            android:layout_below="@+id/lvExp"
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#bebebe"/>

    </RelativeLayout>

Is there something wrong I did with above codes? Thank you.

EDIT:

This is how my code looks like after I edited it as suggested by chandil03. The expandablelistview no longer refreshes when I expand headers. But strangely, when I typed values in edittext at groupposition 0 and child position 0, then in some other edittext in different goupposition and childposition appear the same exact values I typed at previous edittext. Or even stranger, the values at previous edittext sometimes dissapeared.

static class ViewHolder {
    protected View et;

    public void addView(View et){
        this.et = et;
    }
}

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

       final ExpandItemModel childText = (ExpandItemModel) getChild(groupPosition, childPosition);

       ViewHolder viewHolder;

       if (convertView == null) {
           LayoutInflater infalInflater = (LayoutInflater) this._context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
           convertView = infalInflater.inflate(R.layout.list_item, null);
           viewHolder = new ViewHolder();
           viewHolder.addView(convertView
                .findViewById(R.id.et_total));
           convertView.setTag(viewHolder);
       }else{
           viewHolder = (ViewHolder)convertView.getTag();
       }

       final EditText etTotal = (EditText)convertView
        .findViewById(R.id.et_total);

       etTotal.setText(childText.getTotal);

       return convertView;
  }
Turves answered 13/4, 2016 at 9:27 Comment(0)
T
1

I finally able to handle this by using this library:

http://bignerdranch.github.io/expandable-recycler-view/

Then by using AddTextChangedListener, I inserted the value I type. After that, check the inserted values at ViewHolderChild. For example:

public void bind(final MyModel model) {
            tvName.setText(model.getName());
            tvPrice.setText(model.getPrice());
            tvNote.setText(model.getNote());

            for(int i=0;i<listProduct.size();i++){
                if(listProduct.get(i).getIdProduct().equals(model.getIdProduct())){
                    et.setText(listProduct.get(i).getQuantity());
                    break;
                }
            }

            et.addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {

                }

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {

                }

                @Override
                public void afterTextChanged(Editable s) {
                    if(m!=null){
                        listProduct.remove(m);
                    }

                    if (!s.toString().equals("")) {

                        m = new MyModel();
                        m.setName(model.getName());
                        m.setNote(model.getNote());
                        m.setIdProduct(model.getIdProduct());
                        m.setPrice(model.getPrice());
                        m.setQuantity(s.toString());
                        m.setSubtotal(Long.parseLong(s.toString()) * Long.parseLong(model.getPrice()) + "");
                        m.setStock(model.getStock());
                        listProduct.add(m);
                    }
                }
            });
        }
Turves answered 8/8, 2016 at 13:42 Comment(0)
S
4

Whenever you expand another group list refreshes and you get an other instance of EditText there that has no text. The EditText you entered text in would have become child of another groupView.

So I would recommend you to create a ViewHolder class and keep your view in it and set it as a tag and in getView() check if convertView is null that you have already done. Just add else part and getTag from convertView and set values accordingly.

For example:

@Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent)
    {
        View v = convertView;
        if (v == null)
        {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = inflater.inflate(R.layout.my_layout, parent, false);
            ViewHolder holder = new ViewHolder(); // View holder to save views.
            holder.addView(v.findViewById(R.id.myView));
            v.setTag(holder);
        }
        else{
        ViewHolder holder = (ViewHolder) v.getTag();  // get tag and set values
        // Do whatever you need to with the group view
        }
        return v;
    }

EDIT 1

I have modified your code. Check out comments also.

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

        final ExpandItemModel childText = (ExpandItemModel) getChild(groupPosition, childPosition);
        ViewHolder holder;
        if (convertView == null) {
            LayoutInflater infalInflater = (LayoutInflater) this._context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = infalInflater.inflate(R.layout.list_item, null);
            holder = new ViewHolder(convertView);
            convertView.setTag(holder);
        }else {
            holder = (ViewHolder) convertView.getTag();
        }

        holder.editText.setText(childText.getTotal); // Here whatever you will type in edittext will be overwritten by the value of 'childText.getTotal'. So after you are done writing in edit text make sore you change that in "_listDataChild" list. 

        return convertView;
    }

    /**This is a class that holds view, Here i m not talking about support.v7.widget.RecyclerView.ViewHolder class. Though concept is more or less same.*/
    class ViewHolder{
        EditText editText;

        public ViewHolder(View v)
        {
            editText = (EditText) v.findViewById(R.id.et_total);
        }
    }

EDIT 2

Add following code in getChildView() method.

holder.editText.setOnFocusChangeListener(new View.OnFocusChangeListener()
    {
        @Override
        public void onFocusChange(View v, boolean hasFocus)
        {
            if(!hasFocus)
                childText.getTotal = holder.editText.getText().toString(); 
// In java variable contains reference of Object so when you change childText object, it will be reflected in same HashMap you are getting data from.

        }
    });
Staphylorrhaphy answered 13/4, 2016 at 10:11 Comment(4)
I tried that and the result is indeed the expandablelistview didn't refresh. But strangely, when I typed values in edittext at groupposition 0 and child position 0, then in some other edittext in different goupposition and childposition appear the same exact values I typed at previous edittext. Or even stranger, the values at previous edittext sometimes dissapeared. Why is that happened?Turves
ListView cycles/uses its views to make it memory efficient. So if you are not handling views using viewHolder using setTag and getTag. You will face this problem. You are setting same reference of edittext to more than one child that is why you have this problem. Edit your question with your modified code so i can look into.Staphylorrhaphy
I've edited my question. Now I want to ask which one in the adapter, groupview or childview that have to use the viewHolder, settag(), and gettag()? I made them both use it but nothing changes. Also can you tell me about holder.addview in your code above? I don't know if I correctly use that.Turves
Okay. By the way, according one of your comments in your edited code, I have to change "_listDataChild" as I type at the edittext. But "_listDataChild" is a hashmap, I can't change it by its ordering like in array. So, how can I change it?Turves
R
1

The EditText is recycled every time you scroll down or click on another header in the ExpandableListView.

Your best bet will be to save the text the user enters in your model e.g:

etTotal.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        public void onFocusChange(View v, boolean hasFocus) {
            if (!hasFocus) {
                childText.setTotal(etTotal.getText().toString().trim());
            }
        }
    });
Repellent answered 13/4, 2016 at 10:16 Comment(1)
aren't the model itself became recycled and lose its values as well?Turves
S
1

First create a dummy model class to store your data from edittext like this :

public class DummyModel {
    String edt_field;
    //
    //And any other data you might want to store
    //
    public DummyModel(String field)
    {
        this.edt_field=field;
    }
}

Then create a static arraylist to store your data :

public class DummyStatic  {
public static ArrayList<DummyModel> arl_static=new ArrayList();
}

Then in your adapter class change your getChildView() method like this :

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

    final ExpandItemModel childText = (ExpandItemModel) getChild(groupPosition, childPosition);

    if (convertView == null) {
        LayoutInflater infalInflater = (LayoutInflater) this._context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = infalInflater.inflate(R.layout.list_item, null);
    }

    final EditText etTotal = (EditText)convertView
            .findViewById(R.id.et_total);
    etTotal.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

        }

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
             DummyStatic.arl_static.add(childPosition,new DummyModel(charSequence.toString()));
        }

        @Override
        public void afterTextChanged(Editable editable) {

        }
    });

    etTotal.setText(childText.getTotal);

    return convertView;
}

What this code is going to do is that as you type the characters in the edittext they will get stored in the DummyModel object inside the arraylist.

You can retrieve this data by :

String value = DummyStatic.arl_static.get(position).edt_field;
Selle answered 2/8, 2016 at 4:44 Comment(0)
T
1

I finally able to handle this by using this library:

http://bignerdranch.github.io/expandable-recycler-view/

Then by using AddTextChangedListener, I inserted the value I type. After that, check the inserted values at ViewHolderChild. For example:

public void bind(final MyModel model) {
            tvName.setText(model.getName());
            tvPrice.setText(model.getPrice());
            tvNote.setText(model.getNote());

            for(int i=0;i<listProduct.size();i++){
                if(listProduct.get(i).getIdProduct().equals(model.getIdProduct())){
                    et.setText(listProduct.get(i).getQuantity());
                    break;
                }
            }

            et.addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {

                }

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {

                }

                @Override
                public void afterTextChanged(Editable s) {
                    if(m!=null){
                        listProduct.remove(m);
                    }

                    if (!s.toString().equals("")) {

                        m = new MyModel();
                        m.setName(model.getName());
                        m.setNote(model.getNote());
                        m.setIdProduct(model.getIdProduct());
                        m.setPrice(model.getPrice());
                        m.setQuantity(s.toString());
                        m.setSubtotal(Long.parseLong(s.toString()) * Long.parseLong(model.getPrice()) + "");
                        m.setStock(model.getStock());
                        listProduct.add(m);
                    }
                }
            });
        }
Turves answered 8/8, 2016 at 13:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.