ImageView not updating in RecyclerView

Nathan Sokalski 4,111 Reputation points
2024-10-18T18:02:52.0833333+00:00

I have a RecyclerView with the following item layout:

<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:columnCount="3" android:rowCount="1" android:paddingHorizontal="0dp" android:paddingVertical="2dp" tools:ignore="RequiredSizeWidth,RequiredSizeHeight,MissingInputType,HardcodedText,HardcodedSize,MissingDimension">	<!--paddingLeft = (layout_width - (width of drawable)) / 2-->
	<Button android:id="@+id/btnPiece" style="@style/PieceButton" android:layout_column="0" android:drawableLeft="@drawable/meepledrawable" android:paddingLeft="7.5dp" android:drawableTint="@color/RoyalBlue"/>
	<EditText android:id="@+id/txtPlayerName" style="@style/PlayerNameEditTextStyle" android:layout_column="1" android:layout_columnWeight="1"/>
	<Button android:id="@+id/btnDeletePlayerName" style="@style/BasicDeleteButton" android:layout_column="2" android:layout_marginVertical="0dp" android:layout_marginLeft="0dp" android:layout_marginRight="5dp" android:layout_gravity="center"/>
</GridLayout>

This gives the following in the Visual Studio 2022 Designer:

User's image

Notice that the first Button (btnPiece) uses a drawableLeft, not an image. This is done so that I can change the color using drawableTint. In the Adapter, I define OnBindViewHolder as follows:

public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
	PlayerNameViewHolder vh = holder as PlayerNameViewHolder;
	vh.txtPlayerName.Text = this.Players[position].Name;
	vh.btnDeletePlayerName.Visibility = position == (this.ItemCount - 1) ? ViewStates.Invisible : ViewStates.Visible;
	vh.btnPiece.Visibility = position == (this.ItemCount - 1) ? ViewStates.Invisible : ViewStates.Visible;
	if (position < (this.ItemCount - 1))
	{
		vh.btnPiece.SetCompoundDrawables(this.GetPieceDrawable, null, null, null);
		//vh.btnPiece.SetPadding((int)(((vh.btnPiece.Width - 40) / 2) * vh.btnPiece.Context.Resources.DisplayMetrics.Density), 0, 0, 0);
		vh.btnPiece.BackgroundTintList = ColorStateList.ValueOf(this.Players[position].PlayerColor);
	}
	vh.btnPiece.Click += btnPiece_Click;
	vh.txtPlayerName.TextChanged += this.txtPlayerName_TextChanged;
	vh.txtPlayerName.FocusChange += this.txtPlayerName_FocusChange;
	vh.btnDeletePlayerName.Click += this.btnDeletePlayerName_Click;
}

I also define the TextChanged EventHandler as follows:

private void txtPlayerName_TextChanged(object sender, TextChangedEventArgs e)
{
	GridLayout grdRoot = (sender as EditText).Parent as GridLayout;
	RecyclerView rvPlayerNames = grdRoot.Parent as RecyclerView;
	int index = rvPlayerNames.GetChildAdapterPosition(grdRoot);
	PlayerNameViewHolder vh = rvPlayerNames.FindViewHolderForAdapterPosition(index) as PlayerNameViewHolder;

	if (index != -1)
	{
		if (index == (this.Players.Count - 1) && this.Players[this.Players.Count - 1].Name.Trim().Length == 0 && e.Text.ToString().Trim().Length > 0)
		{
			//A new name is being added
			this.Players.Add(new PlayerData());
			vh.btnPiece.Visibility = ViewStates.Visible;

			vh.btnPiece.SetCompoundDrawables(Application.Context.GetDrawable(Resource.Drawable.meepledrawable), null, null, null);
			//vh.btnPiece.SetPadding((int)(((vh.btnPiece.Width - 40) / 2) * vh.btnPiece.Context.Resources.DisplayMetrics.Density), 0, 0, 0);
			vh.btnPiece.BackgroundTintList = ColorStateList.ValueOf(this.Players[index].PlayerColor);

			vh.btnDeletePlayerName.Visibility = ViewStates.Visible;
			this.NotifyItemInserted(index + 1);
			rvPlayerNames.SmoothScrollToPosition(index);
		}
		else if (index == (this.Players.Count - 2) && this.Players[this.Players.Count - 2].Name.Length > 0 && e.Text.ToString().Trim().Length == 0)
		{
			//The last name (2nd last item) is deleted
			this.Players.RemoveAt(index + 1);
			vh.btnPiece.Visibility = ViewStates.Invisible;
			vh.btnDeletePlayerName.Visibility = ViewStates.Invisible;
			this.NotifyItemRemoved(index + 1);
		}

		this.Players[index].Name = e.Text.ToString();
	}
}

My goal is to have another item added to the RecyclerView when the EditText (txtPlayerName) has text added to it, as well as unhide the Buttons (btnPiece & btnDeletePlayerName). I also wish to modify the drawableLeft, paddingLeft & drawableTint of the first Button (btnPiece). This all works fine for the EditText (txtPlayerName) & second Button (btnDeletePlayerName), but if I attempt to set the drawableLeft of the first Button (btnPiece) using SetCompoundDrawables (as shown in the code above), it is hidden. Setting only the drawableTint (using BackgroundTintList as shown above) it is still visible, but the color does not change. Setting the paddingLeft (using SetPadding as shown above), however, does work. I'm sure that all of this can somehow be solved using the Notify methods (such as NotifyItemInserted & NotifyItemChanged), but I can't seem to get it to work. Can someone please help? Thanks!

Developer technologies | .NET | Xamarin
Developer technologies | .NET | Other
Developer technologies | C#
Developer technologies | C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
{count} votes

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.