Content inside RecyclerView getting messed up - android

I'm encountering some really strange behaviors with RecyclerView and it's about anchoring and aligning views inside one row of RecyclerView. So here is how the result from row should look:
And here are two pictures showing final result:
This is not happening always. Sometimes views inside are messed up like on attached images above and sometimes are not. Anyway here is my xml file showing how row layout looks:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<RelativeLayout android:id="#+id/background"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<de.hdodenhof.circleimageview.CircleImageView
android:layout_margin="24dp"
android:id="#+id/iv_user_icon"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="#drawable/ic_zelena_bez_lopte"
app:civ_border="true"
app:civ_border_color="#color/colorAccent"
app:civ_border_width="1dp"
app:civ_shadow="true"
app:civ_shadow_color="#android:color/black"
app:civ_shadow_radius="10"/>
<LinearLayout
android:id="#+id/username_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/iv_user_icon"
android:layout_alignTop="#+id/iv_user_icon"
android:layout_marginLeft="20dp"
android:layout_marginStart="20dp"
android:layout_toEndOf="#+id/iv_user_icon"
android:layout_toRightOf="#+id/iv_user_icon"
android:gravity="center|start"
android:orientation="vertical">
<TextView
android:id="#+id/tv_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Mr.Bean"
android:textColor="#android:color/white"
android:textSize="12sp"
android:typeface="sans"/>
<TextView
android:id="#+id/tv_city_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:textColor="#color/colorAccent"
android:textSize="12sp"
android:typeface="sans"/>
</LinearLayout>
<ImageView
android:id="#+id/iv_option"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_alignBottom="#+id/iv_user_icon"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_alignTop="#+id/iv_user_icon"
android:layout_marginEnd="20dp"
android:layout_marginRight="20dp"
android:background="#null"
android:src="#drawable/ic_message"/>
<View
android:id="#+id/lst_item_divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignLeft="#+id/username_container"
android:layout_alignStart="#+id/username_container"
android:layout_below="#+id/username_container"
android:background="#color/main_text_color"/>
</RelativeLayout>
<ImageView
android:visibility="visible"
app:layout_anchor="#+id/iv_user_icon"
app:layout_anchorGravity="bottom|center|end|right"
android:src="#drawable/icon"
android:id="#+id/iv_star"
android:layout_width="30dp"
android:layout_height="30dp"/>
</android.support.design.widget.CoordinatorLayout>
I'm doing some hiding views inside adapter when i need to, and maybe that's an issue, i really don't know. I have tried without hiding views when checking some conditions inside adapter, but same results. Just to explain, i'm hiding inbox icon because if my username is showed in list i would like to hide it because i wouldn't want to send myself message and also this badge icon will be shown to one user only.
Here is code from adapter:
#Override
public void onBindViewHolder(final TeamMembersListAdapter.HeaderViewHolder holder, int position) {
final User user = teamUsers.get(position);
Glide.with(mContext)
.load(Uri.parse(user.getImage()))
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.placeholder(R.drawable.ic_zelena_bez_lopte)
.error(R.drawable.ic_zelena_bez_lopte)
.dontAnimate()
.into(holder.profileImage);
String selfUserId = AppController.getInstance().getDatabase().getUserDetails().get("user_id");
if (user.getCreatorId() == Integer.parseInt(user.getId())) {
holder.ivBadge.setVisibility(View.VISIBLE);
} else {
holder.ivBadge.setVisibility(View.INVISIBLE);
}
if (selfUserId.equals(user.getId())) {
holder.ivSendMessage.setVisibility(View.INVISIBLE);
} else {
holder.ivSendMessage.setVisibility(View.VISIBLE);
}
holder.tvUsername.setText(user.getName());
holder.tvCityName.setText(user.getCity());
holder.bgContainer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mOnItemClickListener.onItemClickListener(holder.getAdapterPosition());
}
});
}

Shouldn't all views be together inside the RelativeLayout?
I don't get why You even need the CoordinatorLayout, maybe try to get rid off Coordinator and wrap all inside Relative.
I would suggest also to try the ConstraintLayout - it should be super easy to done this in such layout.
Here, check this out
https://developer.android.com/training/constraint-layout/index.html#add-constraintlayout-to-your-project

Related

How can i detect if a Card or a RecyclerView's item is selected?

i'm new to Android and i'm working on a University project, an app to take notes. I can add and delete note, but i would like to implement a classic way to delete an item: long press on it and delete it with dialogs or whatever.
This is what i have: Main Activity
I tried to click for a few seconds on the cards/notes (they are in a recycle view nested in a coordinator layout) and i saw that a background visual effect is displayed, so i think that something is already implemented.
Let me know if you need XML layout implementation or something else to answer. Thanks! :)
EDIT
requested code
CardView cardView = findViewById(R.id.cardId);
cardView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
Toast.makeText(MainActivity.this, "long click!", Toast.LENGTH_SHORT).show();
return true;
}
});
XML Declaration of the cardview
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/touch_layout"
android:background="?attr/selectableItemBackground">
<androidx.cardview.widget.CardView
android:id="#+id/cardId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="#style/cardStyle"
android:elevation="4dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginBottom="4dp"
android:layout_marginTop="4dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp">
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
tools:text="title"
android:textStyle="bold"
android:textSize="20sp"
android:layout_toStartOf="#id/showText"/>
<androidx.appcompat.widget.AppCompatImageButton
android:id="#+id/showText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:src="#drawable/ic_leftarrow" />
<TextView
android:id="#+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/text"
android:layout_alignParentEnd="true"
android:textSize="12sp"
android:layout_marginTop="4dp"
tools:text="#string/date" />
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_marginTop="10dp"
android:layout_below="#+id/title"
tools:text="message..." />
</RelativeLayout>
</androidx.cardview.widget.CardView>
</RelativeLayout>
You can use long click listener easy on recylerview
itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
Log.v("LongClick: "+"LongClick");
return true;// returning true instead of false, works for me
}
});
What you see in the background is the nativen effect applied on some ItemViews by Android. For registering clicks, follow these steps:
Create the layout in the XML and assign an ID to it.
<TextView
android:id="#+id/timestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp"
android:layout_marginRight="16dp"
android:layout_alignParentEnd="true"/>
Declare and define the view (TextView in this case) by using the assigned ID:
TextView messageText;
messageText = itemView.findViewById(R.id.timestamp);
Attach Listener to register clicks:
messageText.setOnLongClickListener(new View.OnClickListener() {
#Override
public void onLongClick(View view){
// Do what you want here.
}
});

Change TextView color in Clicked and unClicked State using style.xml

Suppose I have a cardView Layout which have a TextView and ImageView. I showed them in RecyclerView. If I click on the view the textColor and the drawable color will become red. and then if I click another view, that clicked view will be red and prevoius will convert to black. I did the same thing in bottomNavigationView using custom color.
Here is the layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/item_layout_card_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="10dp"
app:cardCornerRadius="4dp"
app:cardElevation="2dp"
app:cardMaxElevation="3dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/item_image_view"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="10dp"
android:scaleType="centerCrop"
android:src="#mipmap/ic_launcher" />
<TextView
android:id="#+id/item_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/item_image_view"
android:layout_centerHorizontal="true"
android:layout_marginBottom="5dp"
android:gravity="center"
android:text="Item"
android:textColor="#000000"
android:textSize="12sp" />
</RelativeLayout>
</android.support.v7.widget.CardView>
You want to change the color of the recycler view row
In your adapter define variable like
var coloredIndex = -1
In your onBindViewHolder() function
h.var.setOnClickListener {
coloredIndex = curPos
}
changeSelectedItemColor(h, curPos)
Define this below function to change the color.
private fun changeSelectedItemColor(h: YourViewHolder, curPos: Int) {
if (coloredIndex == curPos) {
h.var.setBackgroundColor(ContextCompat.getColor
(context, R.color.red))
} else {
h.var.setBackgroundColor(ContextCompat.getColor
(context, R.color.black))
}
notifyDataSetChanged()
}
This is a example. You didn't add your recycler view adapter code in your question. Please add it for further clarification.

Multiple Empty View for one ListView

I have a ListView, with an Empty View that shows a progressbar to indicate that the app is still loading. I want to make a second empty view to tell the user if there is some error during the process.
I have tried with 2 relative layouts, but when I need to set the "error view", it just ignore it and shows only the "loading view".
So I have tried with a single layout, with my progressbar and the others things to make the error screen, with VISIBILITY:GONE. But, when it's time to put VISIBILITY to VISIBLE, I receive a NullPointerException.
I don't really know what I'm supposed to do to make it works... Thank you!
EDIT
this is my Layout right now (the VISIBILITY attempt) UNDER the ListView
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent" android:id="#+id/post_list_loading">
<ProgressBar
style="?android:attr/progressBarStyle"
android:layout_width="125dp"
android:layout_height="125dp"
android:layout_centerInParent="true"
android:id="#+id/post_list_loading_progressbar"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:visibility="visible" />
<ImageView
android:layout_width="125dp"
android:layout_height="125dp"
android:layout_centerInParent="true"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:src="#drawable/post_list_error_image"
android:visibility="gone"
android:id="#+id/post_list_error_image"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/post_list_error_image"
android:text="Error Text"
android:maxLines="2"
android:ellipsize="end"
android:layout_marginLeft="50dp"
android:layout_centerHorizontal="true"
android:textSize="21dp"
android:id="#+id/post_list_error_text"
android:layout_marginTop="5dp"
android:visibility="gone"
/>
<Button
android:id="#+id/post_list_error_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/post_list_error_text"
android:text="Ricarica"
android:layout_centerHorizontal="true"
android:layout_marginLeft="50dp"
app:backgroundTint="#color/colorPrimary"
android:textColor="#color/colorWhite"
android:visibility="gone"
/>
</RelativeLayout>
The first method I have tried was about putting everything after the progressbar in another RelativeLayout.
So my idea was to make a function to switch between the two views, playing with the Visibility settings.
public void emptyViewManager(Boolean isError, String errorMessage)
{
// [...]
if (isError == true)
{
// Error View
emptyView_progress.setVisibility(View.GONE);
emptyView_errorImage.setVisibility(View.VISIBLE);
emptyView_errorText.setVisibility(View.VISIBLE);
emptyView_errorButton.setVisibility(View.VISIBLE);
emptyView_errorText.setText(errorMessage);
}
else
{
// Loading View
emptyView_progress.setVisibility(View.VISIBLE);
emptyView_errorImage.setVisibility(View.GONE);
emptyView_errorText.setVisibility(View.GONE);
emptyView_errorButton.setVisibility(View.GONE);
}
}
But this didn't work because I have a NullPointerException when the App reach the setVisibility function.

Adapt child's width to parent's width

I'm facing an issue with an xml layout.
This is the full xml:
<FrameLayout
android:id="#+id/root"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<ImageView
android:id="#+id/image"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:adjustViewBounds="true"
tools:src="#drawable/segment_cultura"/>
<LinearLayout
android:id="#+id/message_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="#color/black_divider"
android:padding="4dp">
<TextView
android:id="#+id/message"
style="#style/TextAppearance.AppCompat.Caption"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:maxLines="2"
android:textColor="#color/white_secondary_text"
/>
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="end"
android:src="#drawable/ic_message"/>
</LinearLayout>
<ImageView
android:id="#+id/cancel"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="top|end"
android:layout_margin="4dp"
android:src="#drawable/ic_close"/>
</FrameLayout>
The goal: Use this as an item in a fixed height horizontal RecyclerView, using ONLY the image to determine the size of the item. Other views, such message_container or cancel will need to adapt to this size.
The problem: message_container needs to fill the width of the item, but it shouldn't modify the item width when there is a long text in message. It should go to the 2nd line and then get ellipsized. What happens instead is message never goes to the second line and makes the parents (message_container and root) enlarge to fit its text.
I'm looking for a solution that only involves xml, if I can't find it a custom view is preferred to some logic in the adapter.
Thank you for your time.
I solved this by using:
image.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (root != null && image.getWidth() != 0)
root.getLayoutParams().width = image.getWidth();
});

FrameLayout content order

I'm learning Android and I was trying out FrameLayout containing ImageViews, I tried to do a little app that switchs between two images when you click on them the code is the following:
My xml looks like this:
>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Hola" >
<ImageView
android:id="#+id/segunda"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="metodosegunda"
android:scaleType="fitCenter"
android:src="#drawable/img1" />
<ImageView
android:id="#+id/primera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="metodoprimera"
android:scaleType="fitCenter"
android:src="#drawable/img2" />
</FrameLayout>
And my main program:
public class Hola extends Activity {
ImageView primera;
ImageView segunda;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.teta_layout);
primera = (ImageView) findViewById(R.id.primera);
segunda = (ImageView) findViewById(R.id.segunda);
}
public void metodoprimera (View view){
primera.setVisibility(View.GONE);
segunda.setVisibility(View.VISIBLE);
}
public void metodosegunda (View view){
segunda.setVisibility(View.GONE);
primera.setVisibility(View.VISIBLE);
}
}
This program should show an image and as soon as you click on it it should hide that image and show the other and so on.
The thing is that this won't work , but as soon as I switch the imageview order in the xml, it works, and i don't really understand why it should not work this way.
Thank you guys in advance
Try adding:
android:visibility="gone"
to the XML for one of the ImageView's.
I'll try to go more explicit with the explanation, here is the thing:
If I have the XML like this it will show the images (depending on visibility) but the oClick thing will not work:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Hola" >
<ImageView
android:id="#+id/segunda"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="metodosegunda"
android:scaleType="fitCenter"
android:src="#drawable/img1"
android:visibility="gone" />
<ImageView
android:id="#+id/primera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="metodoprimera"
android:scaleType="fitCenter"
android:src="#drawable/img2"
android:visibility="visible" />
</FrameLayout>
If I swap the ImageView's order in the XML It will work perfectly:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Hola" >
<ImageView
android:id="#+id/primera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="metodoprimera"
android:scaleType="fitCenter"
android:src="#drawable/img2"
android:visibility="visible" />
<ImageView
android:id="#+id/segunda"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="metodosegunda"
android:scaleType="fitCenter"
android:src="#drawable/img1"
android:visibility="gone" />
</FrameLayout>
It's not about the visibility of each Imageview since it does not matter what value I put on them It won't work the first way but i will work the second way.
Seems like a weird issue since the oder of the imageviews should not matter if you set them visible or gone ...

Categories

Resources