Kurlicue Kurlicue - 7 months ago 16
Java Question

Android: adding views to a grid RecyclerView

I've created a RecyclerView with a GridLayoutManager, I want to add a custom view to the grid everytime I click a button, each view has to have a diffrent ID, and when the view is clicked it gets destroyed.

What's happening is, if I add 5 views, and click on the 3rd view to destroy it, the next time I add a view it adds the 3rd view again, instead of a fresh 6th view.

Custom view layout (grid_item_button.xml)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#864643">

<Button
android:id="@+id/grid_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

<EditText
android:id="@+id/editName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:ems="2"
android:textColor="#ffffff"/>

<TextView
android:id="@+id/ClassName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="hmm"
android:textColor="#ffffff"/>




MyAdapter.java

class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

private List<String> items = new ArrayList<>();

public void addItem(String name) {
items.add(name);
notifyItemInserted(items.size() - 1);
}

public void removeItem(int position) {
items.remove(position);
notifyItemRemoved(position);
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.grid_item_button, parent, false);

return new ViewHolder(view);
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
}

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


static int i;

class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

private Button button;
private TextView ClassName;

public ViewHolder(View itemView) {
super(itemView);
ClassName = (TextView) itemView.findViewById(R.id.ClassName);
button = (Button) itemView.findViewById(R.id.grid_button);
button.setOnClickListener(this);
ClassName.setId(++i);
}

@Override
public void onClick(View v) {
removeItem(getAdapterPosition());
}
}

}


activity_main.xml

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="m.testingsubjects.MainActivity">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<Button
android:id="@+id/button_add_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

<android.support.v7.widget.RecyclerView
android:layout_marginTop="50dp"
android:id="@+id/recycler_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

</LinearLayout>

</ScrollView>


MainActivity.java

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);


RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
assert recyclerView != null;
recyclerView.setLayoutManager(new GridLayoutManager(this, NUMBER_COLUMNS));
recyclerView.addItemDecoration(new SampleItemDecoration());
final MyAdapter adapter = new MyAdapter();
recyclerView.setAdapter(adapter);
recyclerView.setNestedScrollingEnabled(false);

adapter.addItem("");

findViewById(R.id.button_add_item).setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
adapter.addItem("");
}
});


}


So what I need is to destroy a view when it's clicked instead of just removing it temporarly as it is what it seems to be happening.

Answer

You've missed onBindViewHolder implementation. It's important since Android uses this to update the content of the view which is reused. Check onBindViewHolder documentation

What's exactly happening is that android adds your 6th content to the 3rd view (since it's destroyed, system want to reuse this resource), but it doesn't know how to refresh the content so it's displayed with the previous one.

Android uses only several views to display all data in your adapter. When RecycleView needs a new ViewHolder it calls onCreateViewHolder, otherwise it uses onBindViewHolder and you must specify how to update the content of reused ViewHolder

Comments