RecyclerView Adapter位置更改视图大小和可见性的问题

时间:2018-07-13 12:43:35

标签: android android-recyclerview visibility android-viewholder

我创建了一个标准的回收站视图适配器,但是它存在一个奇怪的问题,即某些视图会随机更改其可见性或大小,

好吧,我随机地说,显然是我在更改这些视图的大小和/或可见性,因此让我们举一个简短的例子,如果我将适配器位置为0时,由于对象内部没有文本,则将位置0的可见性更改为消失被称为位置0的确会消失,但是如果我向下滚动并返回视图,则我的文本视图也会发生类似的情况,因此,如果它的字符数少于10个,则其大小应为x,否则应为y。加载大小是正确的,但是向下和向后滚动更改大小,我知道在后台加载并回收了视图(因此命名为recycler view),但是我认为该位置已传递给onBindViewHolder(最终MyViewHolder支架,最终int位置)始终是正确的,因为它来自主列表,如果有人可以在这里帮助我,我将不胜感激,因为我现在抓挠头,我将发布整个适配器类,以免担心不够,但通常它是我的onBindViewHolder我认为这是主要的罪魁祸首,其中确实包含许多大部分的人工代码,如前所述,一切都可以正常工作,但是在视图变化时上下滚动时出现奇怪的错误,我相信我正在做的一切我应该做的一切都应该显示正确的数据并不总是正确的大小或可见性,不胜感激

public class LiveMessageAdapter extends 
RecyclerView.Adapter<LiveMessageAdapter.MyViewHolder> {
    private static final int VIEW_TYPE_MESSAGE_SENT = 1;
    private static final int VIEW_TYPE_MESSAGE_RECEIVED = 2;
    private ArrayList<DatabaseMessage> messageList;
    private FrameLayout fade;
    private ImageView holderImage;
    private MessageListActivity.OnItemTouchListener onItemTouchListener;
    private Context context;
    private String userId;
    private Date dateCheck;
    private SparseBooleanArray selectedItems;

public class MyViewHolder extends RecyclerView.ViewHolder {
    public EmojiTextView message_text;
    public TextView time_stamp;
    public ImageView holderImage;
    public ConstraintLayout holder;
    public View sentReceived;
    public View fade;
    public ProgressBar progressBar;
    public ShapeOfView shapeOfView;
    public ConstraintLayout dateHolder;
    public TextView bigDateText;

    public MyViewHolder(View view) {
        super(view);
        message_text = view.findViewById(R.id.text_message_body);
        time_stamp = view.findViewById(R.id.text_message_time);
        fade = view.findViewById(R.id.fade);
        progressBar = view.findViewById(R.id.progress);
        holderImage = view.findViewById(R.id.image_view);
        shapeOfView = view.findViewById(R.id.image_view_holder);
        holder = view.findViewById(R.id.holder);
        sentReceived = view.findViewById(R.id.send_received);
        dateHolder = view.findViewById(R.id.date_holder);
        bigDateText = view.findViewById(R.id.big_date_text);
        Linkify.addLinks(message_text, Linkify.ALL);
        holder.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onItemTouchListener.onCardClick(v, getPosition());
            }
        });
        holder.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                onItemTouchListener.onCardLongClick(v, getPosition());
                return false;
            }
        });
    }
}

public LiveMessageAdapter(ArrayList<DatabaseMessage> messageList,
                          Context context,
                          MessageListActivity.OnItemTouchListener onItemTouchListener,
                          SparseBooleanArray selectedItems, String userId) {
    this.messageList = messageList;
    this.onItemTouchListener = onItemTouchListener;
    this.context = context;
    this.selectedItems = selectedItems;
    this.userId = userId;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View itemView;
    if (viewType == VIEW_TYPE_MESSAGE_RECEIVED) {
        itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.received_message_holder, parent, false);
        return new MyViewHolder(itemView);
    } else {
        itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.sent_message_holder, parent, false);
        return new MyViewHolder(itemView);
    }
}

@Override
public int getItemViewType(int position) {
    DatabaseMessage message = messageList.get(position);
    if (message.getSenderId().equals(userId)) {
        // If the current user is the sender of the message
        return VIEW_TYPE_MESSAGE_SENT;
    } else {
        // If some other user sent the message
        return VIEW_TYPE_MESSAGE_RECEIVED;
    }
}

public void toggleSelection(int pos) {
    if (selectedItems.get(pos, false)) {
        selectedItems.delete(pos);
        //view.setBackgroundColor(Color.WHITE);
    } else {
        selectedItems.put(pos, true);
        //view.setBackgroundColor(Color.BLUE);
    }
    notifyItemChanged(pos);
}

public void clearSelections() {
    selectedItems.clear();
    notifyDataSetChanged();
}

public int getSelectedItemCount() {
    return selectedItems.size();
}

public ArrayList<DatabaseMessage> getSelectedItems() {
    ArrayList<DatabaseMessage> items = new ArrayList<>(selectedItems.size());
    for (int i = 0; i < selectedItems.size(); i++) {
        items.add(messageList.get(selectedItems.keyAt(i)));
    }
    return items;
}

public void refreshMyList(ArrayList<DatabaseMessage> list) {
    this.messageList.clear();
    this.messageList.addAll(list);
    this.notifyDataSetChanged();
}

public ArrayList<DatabaseMessage> getList() {
    return messageList;
}

@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
    final DatabaseMessage userMessage = messageList.get(position);
    if (dateCheck == null){
        //first load show date
        dateCheck = userMessage.getTime_stamp();
        holder.dateHolder.setVisibility(View.VISIBLE);
        holder.bigDateText.setText(getTextDateHolder(dateCheck.getTime()));
    }else{
        //get time and date from message
        Calendar messageTime = Calendar.getInstance();
        messageTime.setTimeInMillis(userMessage.getTime_stamp().getTime());
        // get time and from date check
        Calendar dateCheckTime = Calendar.getInstance();
        dateCheckTime.setTimeInMillis(dateCheck.getTime());
        //check if they are the same
        if (dateCheckTime.get(Calendar.DATE) == messageTime.get(Calendar.DATE)
                && ((dateCheckTime.get(Calendar.MONTH) == messageTime.get(Calendar.MONTH)))
                && ((dateCheckTime.get(Calendar.YEAR) == messageTime.get(Calendar.YEAR)))) {
            //make sure this is gone if they are the same
            holder.dateHolder.setVisibility(View.GONE);
        }else{
            //set date holder visible and set the text
            holder.dateHolder.setVisibility(View.VISIBLE);
            holder.bigDateText.setText(getTextDateHolder(dateCheck.getTime()));
            //set date check to most recent checked time
            dateCheck = userMessage.getTime_stamp();
        }
        //check whether to show the message time
        if (dateCheckTime.get(Calendar.DATE) == messageTime.get(Calendar.DATE)
                && ((dateCheckTime.get(Calendar.MONTH) == messageTime.get(Calendar.MONTH)))
                && ((dateCheckTime.get(Calendar.YEAR) == messageTime.get(Calendar.YEAR)))
                && (dateCheckTime.get(Calendar.HOUR) == messageTime.get(Calendar.HOUR))
                && dateCheckTime.get(Calendar.MINUTE) == messageTime.get(Calendar.MINUTE)) {
            //make sure this is gone if they are the same
            holder.time_stamp.setVisibility(View.GONE);
        }else{
            //set date holder visible and set the text
            holder.time_stamp.setVisibility(View.VISIBLE);
            holder.time_stamp.setText(getSmsTodayYestFromMilli(userMessage.getTime_stamp().getTime()));
        }
    }


    holder.message_text.setText(userMessage.getMessage());

    if (userMessage.getData_type().equals(Constants.DATA_TYPE_IMAGE)) {
        holder.shapeOfView.setVisibility(View.VISIBLE);
        Glide.with(context)
                .load(userMessage.getData_url())
                .apply(new RequestOptions()
                        .dontAnimate().placeholder(R.drawable.placeholder).centerCrop())
                .listener(new RequestListener<Drawable>() {
                    @Override
                    public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
                        return false;
                    }

                    @Override
                    public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
                        holder.progressBar.setVisibility(View.INVISIBLE);
                        return false;
                    }
                })
                .into(holder.holderImage);

    } else {
        holder.shapeOfView.setVisibility(View.GONE);
    }
    if (userMessage.getMessage().length() < 1) {
        holder.message_text.setVisibility(View.GONE);
    } else if (userMessage.getMessage().length() >= 1 && userMessage.getMessage().length() < 10) {
        holder.message_text.setTextSize(22f);
    } else {
        holder.message_text.setTextSize(14f);
    }
    switch (userMessage.getSent_received()) {
        case 0:
            holder.sentReceived.setBackground(context.getResources().getDrawable(R.drawable.circle_white));
            break;
        case 1:
            holder.sentReceived.setBackground(context.getResources().getDrawable(R.drawable.circle_grey));
            break;
        case 2:

            holder.sentReceived.setBackground(context.getResources().getDrawable(R.drawable.circle_blue));
            break;

    }
    final EmojiInformation emojiInformation = EmojiUtils.emojiInformation(userMessage.getMessage());
    final int res;
    if (emojiInformation.emojis.size() > 0){
        if (emojiInformation.isOnlyEmojis && emojiInformation.emojis.size() == 1) {
            res = R.dimen.emoji_size_single_emoji;
        } else if (emojiInformation.isOnlyEmojis && emojiInformation.emojis.size() > 1) {
            res = R.dimen.emoji_size_only_emojis;
        } else {
            res = R.dimen.emoji_size_default;
        }
        holder.message_text.setEmojiSizeRes(res, false);
    }

    if (selectedItems.get(position, false)) {
        holder.fade.setVisibility(View.VISIBLE);
    } else {
        holder.fade.setVisibility(View.INVISIBLE);
    }
}

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

private String getSmsTodayYestFromMilli(long msgTimeMillis) {

    Calendar messageTime = Calendar.getInstance();
    messageTime.setTimeInMillis(msgTimeMillis);
    // get Currunt time
    Calendar now = Calendar.getInstance();

    final String strTimeFormate = "h:mm aa";
    final String strDateFormate = "dd/MM/yyyy h:mm aa";

    if (now.get(Calendar.DATE) == messageTime.get(Calendar.DATE)
            &&
            ((now.get(Calendar.MONTH) == messageTime.get(Calendar.MONTH)))
            &&
            ((now.get(Calendar.YEAR) == messageTime.get(Calendar.YEAR)))
            ) {

        return DateFormat.format(strTimeFormate, messageTime).toString();

    } else if (
            ((now.get(Calendar.DATE) - messageTime.get(Calendar.DATE)) == 1)
                    &&
                    ((now.get(Calendar.MONTH) == messageTime.get(Calendar.MONTH)))
                    &&
                    ((now.get(Calendar.YEAR) == messageTime.get(Calendar.YEAR)))
            ) {
        return "yesterday at " + DateFormat.format(strTimeFormate, messageTime);
    } else {
        return "date : " + DateFormat.format(strDateFormate, messageTime);
    }
}

private String getTextDateHolder(long msgTimeMillis) {

    Calendar messageTime = Calendar.getInstance();
    messageTime.setTimeInMillis(msgTimeMillis);
    // get Currunt time
    Calendar now = Calendar.getInstance();

    final String strDateFormate = "dd/MM/yyyy";

    if (now.get(Calendar.DATE) == messageTime.get(Calendar.DATE)
            && ((now.get(Calendar.MONTH) == messageTime.get(Calendar.MONTH)))
            && ((now.get(Calendar.YEAR) == messageTime.get(Calendar.YEAR)))
            ) {

        return "TODAY";

    } else if (
            ((now.get(Calendar.DATE) - messageTime.get(Calendar.DATE)) == 1)
                    && ((now.get(Calendar.MONTH) == messageTime.get(Calendar.MONTH)))
                    && ((now.get(Calendar.YEAR) == messageTime.get(Calendar.YEAR)))
            ) {
        return "YESTERDAY";
    } else {
        return "" + DateFormat.format(strDateFormate, messageTime);
    }
  }
}

首先加载几个屏幕截图

first load

上下滚动第二秒

enter image description here

1 个答案:

答案 0 :(得分:0)

这种RecyclerView问题,滚动时项目看似随机变化通常是由于将项目特征设置在错误的位置。

RecyclerView将重复使用为其创建的视图持有者(这是 recycle 部分),因此位置10的视图持有者(例如,可以重复使用) 0.如果未将属性绑定到绑定时,特征未更改为应具有的特征,则结果可能是意外的。换句话说,当视图持有者分配到位置0时,在位置10中可见的视图也将可见。