[英]Android - How to make adapters layout stay in position
I created a simple chat app using firebase
but got a little trouble in laying bubble elements for the left
and right
positions. 我创建使用一个简单的聊天应用firebase
,但奠定了泡沫元素有一个小麻烦left
和right
的位置。 Left bubble for the other person, right bubble for me. 给别人留下泡沫,给我泡泡吧。
This is my Adapter : 这是我的适配器 :
public class MessageAdapterCustom extends RecyclerView.Adapter<MessageAdapterCustom.MessageViewHolder> {
private List<Messages> mMessageList;
private Context context;
private String mBubblePosition;
public MessageAdapterCustom(Context context, List<Messages> mMessageList, String mBubblePosition) {
this.context = context;
this.mMessageList = mMessageList;
this.mBubblePosition = mBubblePosition;
}
@Override
public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from( parent.getContext() )
.inflate( R.layout.message_single_layout_custom, parent, false );
return new MessageViewHolder( v );
}
public class MessageViewHolder extends RecyclerView.ViewHolder {
public TextView messageText;
public CircleImageView profileImage;
public MessageViewHolder(View view) {
super( view );
if(mBubblePosition.equals( "kiri" )) {
RelativeLayout right = (RelativeLayout) view.findViewById( R.id.sendingMessageLayout );
right.setVisibility( View.GONE );
messageText = (TextView) view.findViewById( R.id.message_text_layout_kiri );
profileImage = (CircleImageView) view.findViewById( R.id.message_profile_layout_kiri );
} else {
LinearLayout left = (LinearLayout) view.findViewById(R.id.recievemessageLayout);
left.setVisibility(View.GONE);
messageText = (TextView) view.findViewById( R.id.message_text_layout_kanan );
profileImage = (CircleImageView) view.findViewById( R.id.message_profile_layout_kanan );
}
}
}
@Override
public void onBindViewHolder(final MessageViewHolder holder, int position) {
final Messages msg = mMessageList.get( position );
holder.messageText.setText( msg.getMessage() );
Picasso.with( context )
.load( msg.getProfile_pic() )
.networkPolicy( NetworkPolicy.OFFLINE )
.into( holder.profileImage );
/*Picasso.with( context )
.load( msg.getProfile_pic() )
.networkPolicy( NetworkPolicy.OFFLINE )
.placeholder( R.drawable.no_profile )
.into( holder.profileImage, new Callback() {
@Override
public void onSuccess() {
}
@Override
public void onError() {
Picasso.with( context )
.load( msg.getProfile_pic() )
.networkPolicy( NetworkPolicy.OFFLINE )
.into( holder.profileImage );
}
} );*/
}
@Override
public int getItemCount() {
return mMessageList.size();
}
}
My ChatActivity : 我的聊天活动:
public class ChatsActivity extends BaseActivity {
private Toolbar mToolbar;
private String mChatUser, mChatUserProfileImage;
private DatabaseReference mRootRef, mMessageDatabase;
private FirebaseAuth mAuth;
private TextView mTitleView, mLastSeenView;
private CircleImageView mProfileImage, mChatProfilePic;
private String online, image, mCurrentUserID;
private ImageButton mChatAddBtn, mChatSendBtn;
private EditText mChatMessageText;
private RecyclerView mMessagesList;
private final List<Messages> messagesList = new ArrayList<>();
private LinearLayoutManager mLinearLayout;
private MessageAdapter mAdapter;
private MessageAdapterCustom mAdapterCustom;
String URL_PROFILE;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_chats );
mRootRef = FirebaseDatabase.getInstance().getReference();
/*mRootRef.keepSynced( true );*/
mAuth = FirebaseAuth.getInstance();
mCurrentUserID = mAuth.getCurrentUser().getUid();
mChatUser = getIntent().getStringExtra( "user_id" );
mChatUserProfileImage = getIntent().getStringExtra( "thumb_image" );
/*getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE );*/
mToolbar = (Toolbar) findViewById( R.id.toolbar );
setSupportActionBar( mToolbar );
mChatAddBtn = (ImageButton) findViewById( R.id.chat_add_btn );
mChatSendBtn = (ImageButton) findViewById( R.id.chat_send_btn );
mChatMessageText = (EditText) findViewById( R.id.chat_message );
mChatMessageText.requestFocus();
mMessagesList = (RecyclerView) findViewById( R.id.chat_messages_list );
mLinearLayout = new LinearLayoutManager( this );
mMessagesList.setHasFixedSize( true );
mMessagesList.setLayoutManager( mLinearLayout );
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled( true );
actionBar.setDisplayShowCustomEnabled( true );
final String userName = getIntent().getStringExtra( "user_name" );
final String thumbProfilePic = getIntent().getStringExtra( "thumb_image" );
chatUserPic( mChatUser );
LayoutInflater layoutInflater = (LayoutInflater) this.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
View action_bar_view = layoutInflater.inflate( R.layout.chat_custom_bar, null );
actionBar.setCustomView( action_bar_view );
mTitleView = (TextView) findViewById( R.id.custom_bar_title );
mLastSeenView = (TextView) findViewById( R.id.custom_bar_seen );
mProfileImage = (CircleImageView) findViewById( R.id.custom_bar_image );
mChatProfilePic = (CircleImageView) findViewById( R.id.message_profile_layout );
mTitleView.setText( userName );
mRootRef.child( "Users" ).child( mCurrentUserID ).child( "online" ).setValue( "Online" );
loadMessages();
mRootRef.child( "Users" ).child( mChatUser ).addValueEventListener( new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
mTitleView.setText( userName );
online = dataSnapshot.child( "online" ).getValue().toString();
image = dataSnapshot.child( "image" ).getValue().toString();
if (online.equals( "Online" )) {
mLastSeenView.setText( online );
} else {
GetTimeAgo getTimeAgo = new GetTimeAgo();
long lastTime = Long.parseLong( online );
String lastSeenTime = getTimeAgo.timeAgo( lastTime, getApplicationContext() );
mLastSeenView.setText( lastSeenTime );
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
} );
mChatMessageText.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View view) {
if(mAdapterCustom != null) {
mMessagesList.scrollToPosition( mAdapterCustom.getItemCount() - 1 );
}
}
} );
mChatMessageText.setOnFocusChangeListener( new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean hasFocus) {
if (hasFocus) {
if(mAdapterCustom != null) {
mMessagesList.scrollToPosition( mAdapterCustom.getItemCount() - 1 );
}
} else {
if(mAdapterCustom != null) {
mMessagesList.scrollToPosition( mAdapterCustom.getItemCount() - 1 );
}
}
}
} );
mRootRef.child( "Chat" ).child( mCurrentUserID ).addValueEventListener( new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (!dataSnapshot.hasChild( mChatUser )) {
Map chatAddMap = new HashMap();
chatAddMap.put( "seen", false );
chatAddMap.put( "timestamp", ServerValue.TIMESTAMP );
Map chatUserMap = new HashMap();
chatUserMap.put( "Chat" + "/" + mCurrentUserID + "/" + mChatUser, chatAddMap );
chatUserMap.put( "Chat" + "/" + mChatUser + "/" + mCurrentUserID, chatAddMap );
mRootRef.updateChildren( chatUserMap, new DatabaseReference.CompletionListener() {
@Override
public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
if (databaseError != null) {
Log.e( "CHAT_LOG", databaseError.getMessage().toString() );
} else {
mMessagesList.scrollToPosition( mAdapterCustom.getItemCount() - 1 );
}
}
} );
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
} );
mChatSendBtn.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View view) {
final String message = mChatMessageText.getText().toString();
if (TextUtils.isEmpty( message )) {
onError( "Message cannot be empty!" );
} else {
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
Query query = reference.child( "Users" ).child( mCurrentUserID );
query.addListenerForSingleValueEvent( new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
final String URL_PROFILE = dataSnapshot.child( "thumb_image" ).getValue().toString();
sendMessage( message, URL_PROFILE );
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
} );
}
}
} );
}
private void chatUserPic(String id) {
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
Query query = reference.child( "Users" ).child( id );
query.addListenerForSingleValueEvent( new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
final String URL_PROFILE = dataSnapshot.child( "thumb_image" ).getValue().toString();
Picasso.with( getApplication() )
.load( URL_PROFILE )
.networkPolicy( NetworkPolicy.OFFLINE )
.placeholder( R.drawable.no_profile )
.into( mProfileImage, new Callback() {
@Override
public void onSuccess() {
}
@Override
public void onError() {
Picasso.with( getApplication() )
.load( URL_PROFILE )
.placeholder( R.drawable.no_profile )
.into( mProfileImage );
}
} );
} else {
String URL_PROFILE = "no_profile";
Log.i( "PAUL", URL_PROFILE );
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
} );
}
private void loadMessages() {
mRootRef.child( "Messages" ).child( mCurrentUserID ).child( mChatUser ).addChildEventListener( new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Messages message = dataSnapshot.getValue( Messages.class );
String currentUserID = message.current_user_id.toString();
/*mAdapter = new MessageAdapter( getApplicationContext(), messagesList );*/
if (currentUserID.equals( mCurrentUserID )) {
mAdapterCustom = new MessageAdapterCustom( getApplicationContext(), messagesList, "kanan" );
mMessagesList.setAdapter( mAdapterCustom );
messagesList.add( message );
mAdapterCustom.notifyDataSetChanged();
Log.i( "CHAT_ACTIVITY", "RIGHT" );
} else {
mAdapterCustom = new MessageAdapterCustom( getApplicationContext(), messagesList, "kiri" );
mMessagesList.setAdapter( mAdapterCustom );
messagesList.add( message );
mAdapterCustom.notifyDataSetChanged();
Log.i( "CHAT_ACTIVITY", "LEFT" );
}
/*mMessagesList.scrollToPosition( mAdapterCustom.getItemCount() - 1 );*/
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
} );
}
private void sendMessage(String message, String profile_pic) {
String current_user_ref = "Messages" + "/" + mCurrentUserID + "/" + mChatUser;
String chat_user_ref = "Messages" + "/" + mChatUser + "/" + mCurrentUserID;
DatabaseReference user_message_push = mRootRef.child( "Messages" )
.child( mCurrentUserID ).child( mChatUser ).push();
String push_id = user_message_push.getKey();
Map messageMap = new HashMap();
messageMap.put( "message", message );
messageMap.put( "seen", false );
messageMap.put( "type", "text" );
messageMap.put( "time", ServerValue.TIMESTAMP );
messageMap.put( "profile_pic", profile_pic );
messageMap.put( "current_user_id", mCurrentUserID );
Map messageUserMap = new HashMap();
messageUserMap.put( current_user_ref + "/" + push_id, messageMap );
messageUserMap.put( chat_user_ref + "/" + push_id, messageMap );
mRootRef.updateChildren( messageUserMap, new DatabaseReference.CompletionListener() {
@Override
public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
if (databaseError != null) {
mChatMessageText.setText( "" );
Log.e( "SEND_MESSAGE_CHAT", databaseError.getMessage().toString() );
} else {
mChatMessageText.setText( "" );
mMessagesList.scrollToPosition( mAdapterCustom.getItemCount() - 1 );
}
}
} );
}
@Override
protected void onStart() {
super.onStart();
mRootRef.child( "Users" ).child( mCurrentUserID ).child( "online" ).setValue( "Online" );
mMessagesList.getLayoutManager().scrollToPosition( mLinearLayout.findLastVisibleItemPosition() + 1000 );
}
}
You see the line : 你看到了这条线:
if (currentUserID.equals( mCurrentUserID )) {
mAdapterCustom = new MessageAdapterCustom( getApplicationContext(), messagesList, "kanan" );
mMessagesList.setAdapter( mAdapterCustom );
messagesList.add( message );
mAdapterCustom.notifyDataSetChanged();
Log.i( "CHAT_ACTIVITY", "RIGHT" );
} else {
mAdapterCustom = new MessageAdapterCustom( getApplicationContext(), messagesList, "kiri" );
mMessagesList.setAdapter( mAdapterCustom );
messagesList.add( message );
mAdapterCustom.notifyDataSetChanged();
Log.i( "CHAT_ACTIVITY", "LEFT" );
}
When I try to use two devices, first if I myself try to send a message, Log shows RIGHT
which means the position of the balloon on the right . 当我尝试使用两个设备时,首先如果我自己尝试发送消息,则Log显示RIGHT
,这意味着气球的位置在右侧 。
But when I reply with different devices (the other person) then the adapter will move the two bubbles to the left . 但是当我用不同的设备(另一个人)回复时,适配器会将两个气泡向左移动 。 It seems because it follows the last adapter command. 看起来因为它遵循最后一个适配器命令。
How do I keep my adapter in position every time a message arrives
, instead of changing all the structure of my view elements as shown. 如何在每次message arrives
保持适配器的位置 ,而不是如图所示更改视图元素的所有结构。
-- Update -- My Layout : - 更新 - 我的布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/stackoverflow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
<LinearLayout
android:id="@+id/recievemessageLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/message_profile_layout_kiri"
android:layout_width="55dp"
android:layout_height="55dp"
android:src="@drawable/no_profile" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/message_text_layout_kiri"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="5dp"
android:background="@drawable/message_text_background"
android:paddingBottom="5dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="5dp"
android:text="@string/message_here"
android:textColor="@android:color/white" />
<ImageView
android:id="@+id/message_buble_kiri"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginStart="10dp"
android:layout_marginTop="-10dp"
android:src="@drawable/buble_left" />
</LinearLayout>
</LinearLayout>
<RelativeLayout
android:id="@+id/sendingMessageLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/recievemessageLayout"
android:layout_marginTop="5dp"
android:orientation="horizontal">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/message_profile_layout_kanan"
android:layout_width="55dp"
android:layout_height="55dp"
android:layout_alignParentEnd="true"
android:src="@drawable/no_profile" />
<TextView
android:id="@+id/message_text_layout_kanan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginEnd="10dp"
android:layout_marginTop="5dp"
android:layout_toStartOf="@+id/message_profile_layout_kanan"
android:background="@drawable/message_text_background"
android:paddingBottom="5dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="5dp"
android:text="@string/message_here"
android:textColor="@android:color/white" />
<ImageView
android:id="@+id/message_buble_kanan"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignEnd="@+id/message_text_layout_kanan"
android:layout_below="@+id/message_text_layout_kanan"
android:layout_marginTop="-10dp"
android:src="@drawable/buble_right" />
</RelativeLayout>
</RelativeLayout>
You are currently creating two different adapters with all messages aligned the same direction. 您当前正在创建两个不同的适配器,所有消息都指向相同的方向。 Instead, you should create one adapter decides how to align each message one at a time. 相反,您应该创建一个适配器来决定如何一次对齐一条消息。
RecyclerView with multiple View Type? RecyclerView具有多种视图类型?
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
class ViewHolder0 extends RecyclerView.ViewHolder {
...
public ViewHolder0(View itemView){
...
}
}
class ViewHolder2 extends RecyclerView.ViewHolder {
...
public ViewHolder2(View itemView){
...
}
@Override
public int getItemViewType(int position) {
// Just as an example, return 0 or 2 depending on position
// Note that unlike in ListView adapters, types don't have to be contiguous
return position % 2 * 2;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case 0: return new ViewHolder0(...);
case 2: return new ViewHolder2(...);
...
}
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
switch (holder.getItemViewType()) {
case 0:
ViewHolder0 viewHolder0 = (ViewHolder0)holder;
...
break;
case 2:
ViewHolder2 viewHolder2 = (ViewHolder2)holder;
...
break;
}
}
}
Items in your list of messages will primarily be of two types: sent and received. 邮件列表中的项目主要有两种类型:已发送和已接收。 Could you make your data model such that they define their types and in onCreateViewHolder()
you have a different viewholder for each type. 您可以将数据模型设置为定义其类型吗?在onCreateViewHolder()
您为每种类型设置了不同的视图。 In onBindViewHolder()
you need to bind your views again on the basis of the type of item. 在onBindViewHolder()
您需要根据项目类型再次绑定视图。
I have modified Naveen's example a bit to get : 我已经修改了Naveen的例子:
interface MsgType {
int TYPE_SENT = 1;
int TYPE_RECEIVED = 2;
}
class Msg implements MsgType
{
String text ;
int type;
public Msg(String text, int type) {
// set
}
public String getText() {
return text;
}
public int getType() {
return type;
}
}
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
List<Msg> msgs;
class SentMsgVH extends RecyclerView.ViewHolder {
...
public SentMsgVH(View itemView){
...
}
}
class ReceivedMsgVh extends RecyclerView.ViewHolder {
...
public ReceivedMsgVh(View itemView){
...
}
@Override
public int getItemViewType(int position) {
return msgs.get(position).getType();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v;
switch (viewType) {
case TYPE_SENT:
v = ... ; // inflate view
return new SentMsgVH(v);
case TYPE_RECEIVED:
v = ...; // inflate view
return new ReceivedMsgVh(v);
}
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
switch (getItemViewType(position)) {
case TYPE_SENT:
ViewHolder0 viewHolder0 = (SentMsgVH)holder;
...
break;
case TYPE_RECEIVED:
ViewHolder2 viewHolder2 = (ReceivedMsgVh)holder;
...
break;
}
}
}
In your respective viewholders you should inflate the proper layout as per your needs. 在各自的视图中,您应根据需要扩展正确的布局。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.