March3April4 March3April4 - 4 months ago 52
Android Question

Android recyclerView item layout params not working

enter image description hereI'm writing a simple chat UI. I am using a nine-patch file to to this work.

When I first initialize my Adapter with some mock data, it works fine, but if I add something during runtime, the layout inside the recyclerView breaks.

It doesn't throw any errors, though the layout params which I used to set the alignment don't seem to work. Actually, the aligment works, but it's size becomes match_parent rather than wrap_content.

Here's my Adapter code.

public class Adapter_Chat extends RecyclerView.Adapter<Adapter_Chat.Adapter_Chat_ViewHolder> {

private List<ChatMessageModel> data = Collections.EMPTY_LIST;

public Adapter_Chat(List<ChatMessageModel> data) {
this.data = data;
}

@Override
public Adapter_Chat_ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new Adapter_Chat_ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_rv_chat_message, parent, false));
}


public void addNewMessage(ChatMessageModel model) {
data.add(model);
notifyDataSetChanged();
}

@Override
public void onBindViewHolder(Adapter_Chat_ViewHolder holder, int position) {
ChatMessageModel item = data.get(position);

switch (item.getType()) {
case mine: {
holder.iv_chat_profileImage.setVisibility(View.INVISIBLE);
holder.tv_item_chat_message_nameText.setVisibility(View.INVISIBLE);
holder.tv_item_chat_message_contentText.setBackgroundResource(R.drawable.in_message_bg);
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) holder.tv_item_chat_message_contentText.getLayoutParams();
params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
params.height = RelativeLayout.LayoutParams.WRAP_CONTENT;
params.width = RelativeLayout.LayoutParams.WRAP_CONTENT;
holder.tv_item_chat_message_contentText.setLayoutParams(params);

}
break;

case others: {
holder.iv_chat_profileImage.setVisibility(View.VISIBLE);
holder.tv_item_chat_message_nameText.setVisibility(View.VISIBLE);
holder.tv_item_chat_message_contentText.setBackgroundResource(R.drawable.out_message_bg);
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) holder.tv_item_chat_message_contentText.getLayoutParams();
params.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
params.height = RelativeLayout.LayoutParams.WRAP_CONTENT;
params.width = RelativeLayout.LayoutParams.WRAP_CONTENT;
holder.tv_item_chat_message_contentText.setLayoutParams(params);

}
break;
}


holder.tv_item_chat_message_contentText.setText(item.getMessage().trim());
holder.tv_item_chat_message_nameText.setText(item.getSender().trim());
}

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

public class Adapter_Chat_ViewHolder extends RecyclerView.ViewHolder {

public TextView tv_item_chat_message_nameText, tv_item_chat_message_contentText;
public ImageView iv_chat_profileImage;

public Adapter_Chat_ViewHolder(View itemView) {
super(itemView);
tv_item_chat_message_contentText = (TextView) itemView.findViewById(R.id.tv_item_chat_message_contentText);
tv_item_chat_message_nameText = (TextView) itemView.findViewById(R.id.tv_item_chat_message_nameText);
iv_chat_profileImage = (ImageView) itemView.findViewById(R.id.iv_chat_profileImage);
}
}
}


And the layout is,

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">

<ImageView
android:src="@drawable/bg"
android:scaleType="fitXY"
android:layout_margin="16dp"
android:layout_width="48dp"
android:layout_height="48dp"
android:id="@+id/iv_chat_profileImage" />

<TextView
android:id="@+id/tv_item_chat_message_nameText"
android:text="name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="64dp"
android:layout_marginTop="16dp" />

<TextView
android:layout_marginTop="32dp"
android:layout_marginLeft="64dp"
android:layout_marginRight="16dp"
android:gravity="right"
android:background="@drawable/out_message_bg"
android:id="@+id/tv_item_chat_message_contentText"
android:text="content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>




Is there something wrong with my onBindViewHolder method? Isn't changing the alignment of the item supposed to be like this?

sJy sJy
Answer

The addRule() method will keep the existing rules added to the View. So adding the rules dynamically without removing the existing ones will not give the desired effect.

Update the switch case like below.

switch (item.getType()) {
    case mine: {
        ---------- exisiting code ----------
        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) holder.tv_item_chat_message_contentText.getLayoutParams();
        params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
        params.addRule(RelativeLayout.ALIGN_PARENT_LEFT, 0);
        params.height = RelativeLayout.LayoutParams.WRAP_CONTENT;
        params.width = RelativeLayout.LayoutParams.WRAP_CONTENT;
        holder.tv_item_chat_message_contentText.setLayoutParams(params);

    }
    break;

    case others: {
        ---------- exisiting code ----------          
        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) holder.tv_item_chat_message_contentText.getLayoutParams();
        params.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
        params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 0);
        params.height = RelativeLayout.LayoutParams.WRAP_CONTENT;
        params.width = RelativeLayout.LayoutParams.WRAP_CONTENT;
        holder.tv_item_chat_message_contentText.setLayoutParams(params);

    }
    break;
}

For API Level >= 17, a new method is available to remove any existing rules rather than setting their value as 0. We can use

 params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 0);

becomes

 params.removeRule(RelativeLayout.ALIGN_PARENT_RIGHT);