[英]Recyclerview row format changes after search filter
我有一个显示联系人列表的回收视图。 为了区分同时也是我的应用程序用户的联系人(我们将这些称为应用程序联系人)和所有其他联系人(非应用程序联系人),我将所有应用程序联系人的字体设为粗体(Typeface.BOLD),和非应用程序联系人正常(Typeface.NORMAL)。 但是,如果在搜索联系人时过滤了 recyclerview,并且应用程序联系人以粗体显示在某些行(比如第 1 行和第 2 行)中,那么这些行将保留为粗体。 即使当我更改搜索时,非应用程序联系人(应该是普通字体)现在占据了那些行(1 和 2),它是粗体。 基本上第 1 行和第 2 行现在保留为粗体,无论其中显示的联系人类型如何。
public class SearchRecipientHintsAdapter extends RecyclerView.Adapter<SearchRecipientHintsAdapter.ViewHolder> {
private Context context;
private List<RecipientsContactItem> contactItems;
private final int SELECT_DROPOFF_REQUEST_CODE = 77;
public SearchRecipientHintsAdapter (Context context, List<RecipientsContactItem> contactItems) {
this.context = context;
this.contactItems = contactItems;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recipients_contact_row,parent,false);
return new ViewHolder(view, context);
}
@Override
public void onBindViewHolder(@NonNull SearchRecipientHintsAdapter.ViewHolder holder, int position) {
RecipientsContactItem contactItem = contactItems.get(position);
holder.name.setText(contactItem.getName());
holder.phoneNumber.setText(contactItem.getPhoneNumber());
if (contactItem.getImage() != null && !contactItem.getImage().isEmpty()) {
try {
Picasso.get().load(contactItem.getImage()).into(holder.image);
} catch (Throwable ignored) { }
} else {
holder.image.setImageDrawable(context.getResources().getDrawable(R.drawable.user_default_img));
}
if (contactItem.isVerified()) {
holder.verificationIcon.setVisibility(View.VISIBLE);
} else {
holder.verificationIcon.setVisibility(View.GONE);
}
if (contactItem.isSumaContact()) {
holder.name.setTypeface(holder.name.getTypeface(), Typeface.BOLD);
switch (contactItem.getPrivacy()) {
case "Public":
holder.publicIcon.setVisibility(View.VISIBLE);
holder.privateIcon.setVisibility(View.GONE);
holder.allowedIcon.setVisibility(View.GONE);
holder.inviteButton.setVisibility(View.GONE);
break;
case "Private":
holder.publicIcon.setVisibility(View.GONE);
holder.privateIcon.setVisibility(View.VISIBLE);
holder.allowedIcon.setVisibility(View.GONE);
holder.inviteButton.setVisibility(View.GONE);
break;
case "Allowed":
holder.publicIcon.setVisibility(View.GONE);
holder.privateIcon.setVisibility(View.GONE);
holder.allowedIcon.setVisibility(View.VISIBLE);
holder.inviteButton.setVisibility(View.GONE);
break;
}
} else {
holder.name.setTypeface(holder.name.getTypeface(), Typeface.NORMAL);
holder.inviteButton.setVisibility(View.VISIBLE);
holder.publicIcon.setVisibility(View.GONE);
holder.privateIcon.setVisibility(View.GONE);
holder.allowedIcon.setVisibility(View.GONE);
}
}
@Override
public int getItemCount() {
return contactItems.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView name;
private TextView phoneNumber;
private ImageView image;
private ImageView verificationIcon;
private Button inviteButton;
private ImageView publicIcon;
private ImageView privateIcon;
private ImageView allowedIcon;
public ViewHolder(@NonNull View itemView, Context ctx) {
super(itemView);
context = ctx;
name = itemView.findViewById(R.id.recipientsCRowNameID);
phoneNumber = itemView.findViewById(R.id.recipientsCRowPhoneID);
image = itemView.findViewById(R.id.recipientsCRowImageID);
verificationIcon = itemView.findViewById(R.id.recipientsCRowVerifiedID);
inviteButton = itemView.findViewById(R.id.recipientsCRowInviteID);
publicIcon = itemView.findViewById(R.id.recipientsCRowPublicID);
privateIcon = itemView.findViewById(R.id.recipientsCRowPrivateID);
allowedIcon = itemView.findViewById(R.id.recipientsCRowAllowedID);
itemView.setOnClickListener(v -> {
//Get position of row
int position = getAdapterPosition();
RecipientsContactItem contactItem = contactItems.get(position);
String uID = contactItem.getUID();
String name = contactItem.getName();
String phoneNumber = contactItem.getPhoneNumber();
String lat = contactItem.getLat();
String lng = contactItem.getLng();
boolean isSumaContact = contactItem.isSumaContact();
if (isSumaContact) {
if (contactItem.getPrivacy().equals("Public") || contactItem.getPrivacy().equals("Allowed")) {
Intent returnRecipientIntent = ((Activity) context).getIntent();
returnRecipientIntent.putExtra("uID", uID);
returnRecipientIntent.putExtra("name", name);
returnRecipientIntent.putExtra("phoneNumber", phoneNumber);
returnRecipientIntent.putExtra("lat", lat);
returnRecipientIntent.putExtra("lng", lng);
returnRecipientIntent.putExtra("isSumaContact", true);
((Activity) context).setResult(Activity.RESULT_OK, returnRecipientIntent);
((Activity) context).finish();
} else {
Toast.makeText(context, R.string.recipients_search_disallowed_toast, Toast.LENGTH_LONG).show();
}
} else {
Intent dropOffSearchIntent = new Intent(context, SelectDropoff.class);
((Activity) context).startActivityForResult(dropOffSearchIntent, SELECT_DROPOFF_REQUEST_CODE);
}
});
inviteButton.setOnClickListener(view -> {
Intent sendInvite = new Intent(android.content.Intent.ACTION_VIEW);
sendInvite.putExtra("address", contactItems.get(getAdapterPosition()).getPhoneNumber());
sendInvite.putExtra("sms_body", context.getResources().getString(R.string.recipients_invite_link));
sendInvite.setType("vnd.android-dir/mms-sms");
try {
context.startActivity(sendInvite);
} catch (Throwable t) {
Toast.makeText(context, "Sorry, invite not working. Please use the invite in your main menu", Toast.LENGTH_LONG).show();
}
});
}
}
@Override
public int getItemViewType(int position) {
return position;
}
public void updateWithSearchFilter (List<RecipientsContactItem> newList) {
contactItems = new LinkedList<>();
contactItems.addAll(newList);
notifyDataSetChanged();
}
}
public boolean onQueryTextChange(String newText) {
String userInput = newText.toLowerCase();
if (userInput.startsWith("0")) {userInput = userInput.substring(1);}
List<RecipientsContactItem> newList = new LinkedList<>();
for (RecipientsContactItem contactItem : sumaContacts) {
if (contactItem.getName().toLowerCase().contains(userInput) || contactItem.getPhoneNumber().contains(userInput)) {
newList.add(contactItem);
}
}
((SearchRecipientHintsAdapter) searchRHintsAdapter).updateWithSearchFilter(newList);
return true;
}
镜头 1:显示的 2 个联系人是非应用程序联系人,所以他们的字体是正常的(不是粗体)
镜头 2. 过滤搜索后显示应用程序联系人:第一个联系人是联系人(粗体),第二个是非应用程序联系人(普通字体 - 非粗体)
镜头 3. 清除搜索过滤器以显示镜头 1 中的联系人后:两个联系人都是非应用程序联系人,应使用普通字体(不是粗体)。 但是第一个联系人显示为粗体,因为在过滤搜索时,应用程序联系人(粗体)曾短暂地显示在那里(在镜头 2 中)
最初,每当我滚动 recyclerview 时,粗体字体都会错误地应用于不应该是粗体的行/联系人。 直到我找到一个解决方案,我不得不像这样覆盖 recyclerview 适配器的 getItemViewType() 方法:
@Override
public int getItemViewType(int position) {
return position;
}
然后它被固定(用于滚动)。 直到我意识到过滤问题仍然存在。 所以这就是我现在要解决的问题
问题是
holder.name.setTypeface(holder.name.getTypeface(), Typeface.NORMAL);
当重新绑定一个带有粗体的 viewholder 时, holder.getTypeface()
返回之前的粗体字体。 现在, Typeface.NORMAL
的值为0
。 这是来自cs.android.com的setTypeface()
实现:
public void setTypeface(@Nullable Typeface tf, @Typeface.Style int style) {
if (style > 0) {
if (tf == null) {
tf = Typeface.defaultFromStyle(style);
} else {
tf = Typeface.create(tf, style);
}
setTypeface(tf);
// now compute what (if any) algorithmic styling is needed
int typefaceStyle = tf != null ? tf.getStyle() : 0;
int need = style & ~typefaceStyle;
mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0);
mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0);
} else {
mTextPaint.setFakeBoldText(false);
mTextPaint.setTextSkewX(0);
setTypeface(tf);
}
}
注意那里的if (style > 0)
部分。 因此,传入Typeface.NORMAL
将按原样设置字体,而不对其进行任何样式设置,因此您的粗体样式将保持粗体。
要解决此问题,请传入null
作为适合您的字体,或者将字体重置为适合您需要的默认值。
另外,你的性能也有问题
@Override
public int getItemViewType(int position) {
return position;
}
这使得每一行都有自己特定的视图类型。 但是您实际上只有一种视图类型,因此根本不需要重写此方法。 或者,如果这样做,您可以返回一个常量值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.