RecyclerView滚动时弄乱了

时间:2018-11-18 11:09:40

标签: android android-recyclerview recyclerview-layout

我以前从未问过任何问题,但希望您能理解我的意思。 我正在制作一个聊天应用程序,其中使用RecyclerView来显示消息。问题是,当我滚动RecyclerView时,某些项目从顶部消失,并且当我尝试添加一条消息时,整个项目都混乱了,它甚至没有滚动到底部,也没有添加到ListView

这是我的RecyclerView:

<android.support.v7.widget.RecyclerView
    android:id="@+id/conversation_recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    android:layout_above="@id/typingConversationLayout"
    android:layout_below="@id/topLayout_conversation_activity"
    android:layout_marginBottom="-5dp"
    android:paddingBottom="7dp" />

初始化和设置RecycerView:

linearLayoutManager = new LinearLayoutManager(this);
    adapter = new ConversationRecyclerViewAdapter();
    conversationRecyclerView.setAdapter(adapter);
    conversationRecyclerView.setLayoutManager(linearLayoutManager);
    linearLayoutManager.setStackFromEnd(true);
    conversationRecyclerView.setHasFixedSize(true);
    conversationRecyclerView.setNestedScrollingEnabled(false);

这是我的适配器类:

private class ConversationRecyclerViewAdapter
        extends RecyclerView.Adapter<ConversationRecyclerViewAdapter.ConversationViewHolder> {

    @NonNull
    @Override
    public ConversationViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int i) {

        Log.d(TAG, "onCreateViewHolder: Users Find started");

        View conversationsView = LayoutInflater.from(parent.getContext()).inflate(
                R.layout.layout_message_received, parent, false);

        return new ConversationViewHolder(conversationsView);
    }

    @Override
    public void onBindViewHolder(@NonNull final ConversationViewHolder holderConversation, int i) {
        Log.d(TAG, "onBindViewHolder: Users Find started at position is " + i);

        final int position = holderConversation.getAdapterPosition();

        if (mOwnUser_1.get(position)) {
            holderConversation.receivedMsgLayout.setVisibility(View.GONE);

            holderConversation.sentProfileImg.setImageResource(mUserProfileImg_2.get(position));
            holderConversation.sentMsg.setText(mUserText_3.get(position));

        } else {

            holderConversation.sentMsgLayout.setVisibility(View.GONE);

            holderConversation.receivedProfileImg.setImageResource(mUserProfileImg_2.get(position));
            holderConversation.receivedMsg.setText(mUserText_3.get(position));

        }

        Log.d(TAG, "onBindViewHolder: completed at " + position);

    }

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

    public class ConversationViewHolder extends RecyclerView.ViewHolder {

        RelativeLayout receivedMsgLayout, sentMsgLayout;
        EmojiTextView receivedMsg, sentMsg;
        CircleImageView receivedProfileImg, sentProfileImg;

        public ConversationViewHolder(@NonNull View v) {
            super(v);

            receivedMsgLayout = v.findViewById(R.id.received_message_layout);
            sentMsgLayout = v.findViewById(R.id.sent_message_layout);
            receivedMsg = v.findViewById(R.id.received_message_text);
            sentMsg = v.findViewById(R.id.sent_message_text);
            receivedProfileImg = v.findViewById(R.id.received_message_user__profile_image);
            sentProfileImg = v.findViewById(R.id.sent_message_user__profile_image);

        }
    }
}

在这里,我正在向ListView添加数据并显示到RecyclerView:

sendBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            String msg = editText.getText().toString().trim();

            if (TextUtils.isEmpty(msg)) {

                editText.setError("Please add a message");
                editText.requestFocus();

            } else {
                Log.d(TAG, "onClick: send Btn ADDED TEXT.. ");

                mOwnUser_1.add(user);
                mUserProfileImg_2.add(image);
                mUserText_3.add(message);

                editText.setText("");
                editText.requestFocus();

                adapter.notifyItemInserted(mOwnUser_1.size());
                conversationRecyclerView.scrollToPosition(mOwnUser_1.size() - 1);


            }

        }
    });

我不知道我在做什么错,但是它似乎并没有按照我的意愿工作。

更新代码:

三个列表视图:

private ArrayList<Boolean> mOwnUser_1 = new ArrayList<>();
private ArrayList<Integer> mUserProfileImg_2 = new ArrayList<>();
private ArrayList<String> mUserText_3 = new ArrayList<>();

以及向适配器添加数据的方式:

mOwnUser_1.add(true);
mUserProfileImg_2.add(R.drawable.boy);
mUserText_3.add(edittext.getText().toString().trim());
adapter.notifyItemInserted(mOwnUser_1.size());
conversationRecyclerView.scrollToPosition(mOwnUser_1.size() - 1);

我的整个会话活动课堂:

public class ConversationActivity extends AppCompatActivity {
private static final String TAG = "ConversationActivity";

private EditText editText;
private LinearLayout linearLayout;
private LinearLayoutManager linearLayoutManager;

private ImageView sendBtn;
private ImageView emojiImage;
private View rootView;
private Boolean popUpShown = false;
private Boolean micShown = false;
private ImageView micBtn;
private RelativeLayout micLayout;
private RecyclerView conversationRecyclerView;

// Array Lists for Find USERS
private ArrayList<Boolean> mOwnUser_1 = new ArrayList<>();
private ArrayList<Integer> mUserProfileImg_2 = new ArrayList<>();
private ArrayList<String> mUserText_3 = new ArrayList<>();

private ConversationRecyclerViewAdapter adapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    Log.d(TAG, "onCreate: started");
    super.onCreate(savedInstanceState);
    EmojiManager.install(new TwitterEmojiProvider());
    setContentView(R.layout.activity_conversation);

    editText = findViewById(R.id.conversationEditText);
    linearLayout = findViewById(R.id.optionsOther);
    emojiImage = findViewById(R.id.emojiIconOther);
    rootView = findViewById(R.id.root_view_conversation);
    micBtn = findViewById(R.id.microphoneBtn);
    micLayout = findViewById(R.id.microphoneLayout);
    conversationRecyclerView = findViewById(R.id.conversation_recyclerView);
    sendBtn = findViewById(R.id.sendBtnConversation);

    if (!(Build.VERSION.SDK_INT >= 21))
        findViewById(R.id.typingConversationLayout).setBackgroundResource(R.drawable.edit_text_conversation_background_below_api);

    sendBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            String msg = editText.getText().toString().trim();

            if (TextUtils.isEmpty(msg)) {

                editText.setError("Please add a message");
                editText.requestFocus();

            } else {
                Log.d(TAG, "onClick: send Btn ADDED TEXT.. ");

                addData(true, R.drawable.boy0, msg);
            }

        }
    });

    initConversationArrayList();

}

private void addData(Boolean user, int image, String message) {

    mOwnUser_1.add(user);
    mUserProfileImg_2.add(image);
    mUserText_3.add(message);

    editText.setText("");
    editText.requestFocus();

    adapter.notifyItemInserted(mOwnUser_1.size());
    conversationRecyclerView.scrollToPosition(mOwnUser_1.size() - 1);

}


private void initConversationArrayList() {
    Log.d(TAG, "initConversationArrayList: created");

    mOwnUser_1.add(true);
    mUserProfileImg_2.add(R.drawable.boy0);
    mUserText_3.add("Hello How are you?");


    Log.d(TAG, "initConversationArrayList: completed");

    initConversationRecyclerView();

}

private void initConversationRecyclerView() {
    Log.d(TAG, "initConversationRecyclerView: started");

    linearLayoutManager = new LinearLayoutManager(this);
    adapter = new ConversationRecyclerViewAdapter();
    conversationRecyclerView.setAdapter(adapter);
    conversationRecyclerView.setLayoutManager(linearLayoutManager);
    linearLayoutManager.setStackFromEnd(true);
    conversationRecyclerView.setHasFixedSize(true);
    conversationRecyclerView.setNestedScrollingEnabled(false);

    Log.d(TAG, "initConversationRecyclerView: completed");
}

2 个答案:

答案 0 :(得分:0)

当前,我还在聊天模块上,让我向您展示我如何做到这一点。我将逐步向您展示。

第1步:为recyclerview项制作两个单独的布局,一个布局用于从您这一侧发送的消息,另一个布局用于从另一侧接收的消息。

第2步:根据上述情况,使两个视图持有者根据您的方案填充不同的布局,如下所示:

public class ChatNewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Chat> chats;

public ChatNewAdapter(List<Chat> chats) {
    this.chats = chats;
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    if (viewType == 0) {
        View viewSend = (View) LayoutInflater.from(parent.getContext()).inflate(R.layout.item_message_send, parent, false);
        return new ViewHolderSend(viewSend);
    } else {
        View viewReceive = (View) LayoutInflater.from(parent.getContext()).inflate(R.layout.item_message_received, parent, false);
        return new ViewHolderReceive(viewReceive);
    }
}

@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
    switch (holder.getItemViewType()) {
        case 0:
            ViewHolderSend viewHolderSend = (ViewHolderSend) holder;
            viewHolderSend.messageSend.setText(chats.get(position).getMessage());
            break;

        case 1:
            ViewHolderReceive viewHolderReceive = (ViewHolderReceive) holder;
            viewHolderReceive.messageReceived.setText(chats.get(position).getMessage());
            break;
    }
}

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

@Override
public int getItemViewType(int position) {
    if (chats != null && !chats.get(position).fromAdmin) {
        return 0;
    } else
        return 1;
}

class ViewHolderSend extends RecyclerView.ViewHolder {
    TextView messageSend;

    public ViewHolderSend(View itemView) {
        super(itemView);
        messageSend = (TextView) itemView.findViewById(R.id.messageSend);
    }
}

class ViewHolderReceive extends RecyclerView.ViewHolder {
    TextView messageReceived;

    public ViewHolderReceive(View itemView) {
        super(itemView);
        messageReceived = (TextView) itemView.findViewById(R.id.messageReceived);
    }
}

public int addMessages(Chat chat) {
    chats.add(chat);
    notifyDataSetChanged();
    return chats.size();
}

第3步:现在在您的活动中:

public class Test extends AppCompatActivity {

RecyclerView chatList;
RecyclerView.LayoutManager mLayoutManager;
ChatNewAdapter adapter;
ImageView sendButton;
EditText messageEditText;
boolean keyboardUp = false;
boolean isRunning = false;
ArrayList<Chat> chats;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_chat);
    getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
    isRunning = true;
    setUpComponents();
}


public void setUpComponents() {
    chatList = (RecyclerView) findViewById(R.id.chat_list);
    chatList.setHasFixedSize(true);
    mLayoutManager = new LinearLayoutManager(this);
    chatList.setLayoutManager(mLayoutManager);
    messageEditText = (EditText) findViewById(R.id.messageText);
    getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
    sendButton = (ImageView) findViewById(R.id.send);

    adapter = new ChatNewAdapter(chats);
    chatList.setAdapter(adapter);
    chatList.scrollToPosition(chatList.getAdapter().getItemCount() - 1);

    messageEditText.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (keyboardShown(messageEditText.getRootView())) {
                Log.d("keyboard", "keyboard UP");

                if (keyboardUp == false) {
                    if (chats.size() > 0)
                        chatList.smoothScrollToPosition(chats.size() + 1);
                    keyboardUp = true;
                }

            } else {
                Log.d("keyboard", "keyboard Down");
                keyboardUp = false;
            }
        }
    });


    sendButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            final String message = messageEditText.getText().toString().trim();
            if (!message.equals("")) {
                Chat chat = new Chat();
                String name = message;
                chat.setMessage(name);
                messageEditText.setText("");
                adapter.addMessages(chat);
                chatList.scrollToPosition(chatList.getAdapter().getItemCount() - 1);

            } else {
                Log.d("sending message Error", "error fetching dates");
            }
        }
    });
}

private boolean keyboardShown(View rootView) {

    final int softKeyboardHeight = 100;
    Rect r = new Rect();
    rootView.getWindowVisibleDisplayFrame(r);
    DisplayMetrics dm = rootView.getResources().getDisplayMetrics();
    int heightDiff = rootView.getBottom() - r.bottom;
    return heightDiff > softKeyboardHeight * dm.density;
}

这是我的模型类,请忽略@PrimaryKey和@Required批注,仅因为我将Realm用于本地数据库。就您而言,您将不需要这些注释。

public class Chat extends RealmObject {

@PrimaryKey
@Required
public Long id;
public boolean fromAdmin;
@Required
public String message;
public int type;
public boolean isRead;
public boolean isSent;
public Date date;

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public boolean isFromAdmin() {
    return fromAdmin;
}

public void setFromAdmin(boolean fromAdmin) {
    this.fromAdmin = fromAdmin;
}

public String getMessage() {
    return message;
}

public void setMessage(String message) {
    this.message = message;
}

public int getType() {
    return type;
}

public void setType(int type) {
    this.type = type;
}

public boolean isRead() {
    return isRead;
}

public void setRead(boolean read) {
    isRead = read;
}

public boolean isSent() {
    return isSent;
}

public void setSent(boolean sent) {
    isSent = sent;
}

public Date getDate() {
    return date;
}

public void setDate(Date date) {
    this.date = date;
}

希望对您有所帮助,您可以进一步询问是否想了解与代码相关的其他信息。

答案 1 :(得分:0)

RecyclerView名称代表回收视图。将数据绑定到视图时,需要确保设置或重置适配器中接触的所有视图。当仅对部分而非全部项目有条件地设置数据时,通常会发生混乱。

尤其是:

if (mOwnUser_1.get(position)) {
    holderConversation.receivedMsgLayout.setVisibility(View.GONE);

    holderConversation.sentProfileImg.setImageResource(mUserProfileImg_2.get(position));
    holderConversation.sentMsg.setText(mUserText_3.get(position));

} else {

    holderConversation.sentMsgLayout.setVisibility(View.GONE);

    holderConversation.receivedProfileImg.setImageResource(mUserProfileImg_2.get(position));
    holderConversation.receivedMsg.setText(mUserText_3.get(position));

}

这两个分支都需要将其他布局重新设置为可见。

无论如何,通过这种两种布局的方法,您都可以通过在适配器中将它们作为单独的视图类型来获得更好的收益。参见How to create RecyclerView with multiple view type?