1

I know this question is already asked in here but my question is bit different in the sense how items are inserted. I also tried all of the solutions of this post still no luck.

Background:

I have a RecyclerView whose items have been divided into 3 columns. First one is a TextView and the remaining are EditText. Initially I present the user with a list of just one item whose TextView is set to 1 (position of item) and EditText are to be populated with some value. Once the user populates both of the EditText and hit enter key I insert a new item with TextView as 2 (position of next item) and EditText which are to be populated. On each new item insertion I want to scroll to bottom of RecyclerView so that user can edit the EditText easily. I keep inserting new item unit user clicks on the Save button which is going to insert the items of the list into a database table.

Problem:

After inserting of 7th item the RecyclerView doesn't get scrolled to button so I fixed it with this code:

linearLayoutManager.setStackFromEnd(true);

With above code I can now go past 7 items but once I reach 10th item the RecyclerView doesn't scroll to bottom so I would have to manually scroll. How would I keep scrolling now matter how many items are inserted ?

My Code:

Adapter:

public class ListAdapter extends RecyclerView.Adapter<ListAdapter.ViewHolder> {

    private List<ListModel> original;

    public ListAdapter(List<ListModel> list){ original = list; }

    @NonNull
    @Override
    public ListAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, 
                                                    int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View view = inflater.inflate(R.layout.list_layout, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ListAdapter.ViewHolder holder, 
                                 int position) {
        String sNo = original.get(position).getsNo();
        String product = original.get(position).getProduct();
        String price = original.get(position).getPrice();
        holder.sNo.setText(sNo);
        holder.product.setText(product);
        holder.product.requestFocus();
        holder.price.setText(price);
        holder.bind();
    }

    @Override
    public int getItemCount() { return original.size(); }

    public class ViewHolder extends RecyclerView.ViewHolder {
        EditText product, price;
        TextView sNo;
        public ViewHolder(View itemView){
            super(itemView);
            sNo = (TextView) itemView.findViewById(R.id.sno);
            product = (EditText) itemView.findViewById(R.id.newProduct);
            price = (EditText) itemView.findViewById(R.id.newPrice);
        }

        public void bind() {
            addListener(product);
            addListener(price);
        }

        private void addListener(final EditText editText){
            editText.setOnKeyListener(new View.OnKeyListener() {
                @Override
                public boolean onKey(View v, int keyCode, KeyEvent event) {
                    if (event.getAction() == KeyEvent.ACTION_UP && 
                        keyCode == KeyEvent.KEYCODE_ENTER) {
                        if (!anyEmptyEditText()){
                            // insert new empty row
                            ListModel item = new ListModel(
                                             String.valueOf(getItemCount()+1),
                                             "", "", "");
                            original.add(item);
                            notifyItemInserted(getItemCount());
                        } else {
                            if (editText == product)
                                price.requestFocus();
                            else if (editText == price)
                                product.requestFocus();
                        }
                    }else{
                        // modify adapter by keeping it consistent with 
                        // the data being inserted in `EditText`
                        ListModel item = new ListModel(String.valueOf(getItemCount()),
                                                      product.getText().toString(),
                                                      price.getText().toString());
                        original.set(getItemCount() - 1,item);
                    }
                    return false;
                }
            });
        }
    }

    private boolean anyEmptyEditText(){
        for (int idx = 0; idx < original.size(); idx++)
            if (original.get(idx).getProduct().isEmpty() || 
                original.get(idx).getPrice().isEmpty())
                return true;
        return false;
    }
}

Activity:

public class FormActivity extends AppCompatActivity {
    
    private ArrayList<ListModel> list;
    private RecyclerView listView;
    private ListAdapter listAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_order_form);        
        setupAdapter();        
    }

    private void setupAdapter(){
        listView = (RecyclerView) findViewById(R.id.newTableContent);    
        final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        linearLayoutManager.setStackFromEnd(true);
        listView.setLayoutManager(linearLayoutManager);
        list = new ArrayList<>();
        listAdapter = new ListAdapter(list);
        listView.setAdapter(listAdapter);
    }    
}

I would also like to get the optimized version of my code.

Ahtisham
  • 5,216
  • 3
  • 29
  • 42
  • There are unaccepted answers that could help: https://stackoverflow.com/a/52754932/7210237. The idea is correct - listen to data changes and when something has changed scroll to the last row available, if appropriate. – Jenea Vranceanu Aug 12 '20 at 06:44

1 Answers1

0

I fixed it by having an interface talk to activity after a new item is inserted like this:

Adapater: (create and setup the listener)

private final NewItem listener;

public interface NewItem {
    void onNewItemInsert(boolean inserted);
}

public ListAdapter(List<ListModel> list, NewItem listener){
    original = list;
    this.listener = listener;
}

in addListener() where I add an item I set the value to listener:

if (!anyEmptyEditText()){
    // reset of the code
    listener.onNewItemInsert(true);
}

Activity: (inside setupAdapter() get listener and scroll to newly created item)

 private void setupAdapter(){
    // reset of the code
    listAdapter = new ListAdapter(list, new ListAdapter.NewItem() {
          @Override
          public void onNewItemInsert(boolean inserted) {
              if (inserted)
                 listView.scrollToPosition(listAdapter.getItemCount() - 1);
          }
    });
    // reset of the code
 }

Event though the original problem is solved It introduced two minor issues which are:

On insertion of new item the RecyclerView seems to come down a bit and then come back to its original position and the requestFocus() is always applied to the last EditText under consideration. I want the requestFocus() to always be on first EditText when new item is inserted.

Ahtisham
  • 5,216
  • 3
  • 29
  • 42