代码之家  ›  专栏  ›  技术社区  ›  martinseal1987

RecyclerView适配器位置更改视图大小和可见性时出现问题

  •  0
  • martinseal1987  · 技术社区  · 7 年前

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

    好的,我随机地说,很明显是我改变了这些视图的大小和/或可见性,所以让我们举一个简单的例子,如果我改变了位置0的可见性,使其消失,因为我的对象没有文本在里面,当适配器被称为位置0时,确实会消失,但是如果我向下滚动,视图变为可见,就会发生类似的事情在我的文本视图中,如果少于10个字符,应该是x大小,否则应该是y大小,第一次加载时大小是正确的,但是向下滚动和向后滚动大小会改变,我知道在幕后视图是加载和回收的(因此命名为回收视图),但是我认为传入onbindViewHolder(final myViewHolder holder,final int position)的位置总是正确的,因为它来自主列表,如果有人能在这里帮我,我会很感激,因为现在我在挠头,我在因为担心没有包含足够的适配器类,所以要发布我的整个适配器类,但通常我认为它的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 回复  |  直到 7 年前
        1
  •  1
  •   Cheticamp    7 年前

    这种 RecyclerView 当滚动时项目看起来是随机变化的问题通常是由于在错误的地方设置了项目特性。

    一个 回收服务 将重用为其创建的视图保持器(这是 回收 部分),因此位置10的视图保持架可以在位置0处重用。如果特征没有改变为视图持有者 跳跃 结果可能出乎意料。换言之,当视图保持架被分配到位置0时,在位置10中可见的视图也将可见。

    推荐文章