I have set the negative margin for items like this:-
public class ItemDecorator extends RecyclerView.ItemDecoration {
private final int mSpace;
public ItemDecorator(int space) {
this.mSpace = space;
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
if (position != 0)
outRect.top = mSpace;
}
}
This causes top item to stack lowest and next item after the top item overlaps it. I want top item to overlap its next item and so on.
Related
I have a validate button inside each item of a recyclerView in order to change the color to green of the current item. When a new item is added in the recyclerview , I want to set the default background (no background color).
I've tried inside the BindView(position) function so by default when a new item is added in the itemsList, the color of the current element (item 0) is green whether I clicked on validate or not and that's not what I want.
I've also tried in the onBindViewHolder function but it doesnt work.
How can I change the color of this item in this recyclerview and this color remains the same whithout considering the index changing in the List if a new item is added?
I want that each new item of this recyclerview to be in the default color (background color white or no background color) and the item +n to be in the color of the corresponding status (validated = green , reschedulded = grey)
Once the validated button has been clicked I want the item to remains in read only mode.
Here is the code :
The adapter:
private Context context;
private List<RideObject> itemList;
public TestListeAdapter(List<RideObject> itemList, Context context) {
this.itemList = itemList;
this.context = context;
}
#NotNull
#Override
public TestListeAdapter.TestListeViewHolders onCreateViewHolder(ViewGroup parent, int viewType) {
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_testliste, null, false);
RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutView.setLayoutParams(lp);
return new TestListeAdapter.TestListeViewHolders(layoutView);
}
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
public void onBindViewHolder(#NotNull TestListeAdapter.TestListeViewHolders holder, final int position) {
holder.bindView(position);
if (holder.validated){
holder.mCard.setCardBackgroundColor(ContextCompat.getColor(context.getApplicationContext(), R.color.teal_700));
}
the viewholder Class :
class TestListeViewHolders extends RecyclerView.ViewHolder {
//MyClickListener listener;
TextView rideId;
ImageView mCheck;
ImageView mreschedulded;
CardView mCard;
TestListeViewHolders(View itemView) {
super(itemView);
mCheck = itemView.findViewById(R.id.validate);
mreschedulded= itemView.findViewById(R.id.reschedulded);
mCard = itemView.findViewById(R.id.card_view);
}
private void bindView(int pos) {
RideObject item = itemList.get(pos);
mCheck.setOnClickListener(view -> {
item.setRDVHour(timePicker.getHour());
item.setRDVMinute(timePicker.getMinute());
validated = true;
item.setValider(true);
item.confirmDriver();
//if (itemList.size() == 1){
//mCard.setCardBackgroundColor(ContextCompat.getColor(context.getApplicationContext(), R.color.teal_700));
//itemView.setBackgroundColor(ContextCompat.getColor(context.getApplicationContext(),R.color.teal_700));
});
mreschedulded.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
timePicker.setEnabled(true);
itemView.setBackgroundColor(ContextCompat.getColor(context.getApplicationContext(),R.color.grey));
}
});
}
}
In the MainActivity:
resultsTestList.add(0, mCurrentRide);
mTestListAdapter.notifyDataSetChanged()
Ive tried the code in the answer but it doesnt work . Currently, the setbackgroundcolor applies just to the first element of the list. I would want that if the first element (item0) goes to second element (item1) the item keep his color background which is not the case with the given answer code
When binding RecyclerView items, you have to think of it as that you need to change the ViewHolder completely disregarding the previous state.
The view holder should not hold key information like validated.
Whether the view holder stays in the validated state or not should depend on the item it is being bind to.
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
public void onBindViewHolder(#NotNull TestListeAdapter.TestListeViewHolders holder, final int position) {
holder.bindView(position);
}
...
private void bindView(int pos) {
RideObject item = itemList.get(pos);
if (item.validated) {
mCard.setCardBackgroundColor(...R.color.teal_700));
else {
mCard.setCardBackgroundColor(...R.color.grey));
mCheck.setOnClickListener(view -> {
item.setRDVHour(timePicker.getHour());
item.setRDVMinute(timePicker.getMinute());
item.validated = true;
item.setValider(true);
item.confirmDriver();
});
mReschedulded.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
timePicker.setEnabled(true);
itemView.setBackgroundColor(ContextCompat.getColor(context.getApplicationContext(),R.color.grey));
}
});
}
}
I have made a three infinity RecyclerView (100, 60, 60 item count):
public int getItemCount() {
return Integer.MAX_VALUE;
}
Now I want to get item value from this Views. And for 100 item count RecyclerView its easy, but I dont understand how to make this for 60 item count RecyclerView. I made a method in Adapter, like this:
public String get(int position) {
return hours.get(position).hour;
}
Here is for 100:
hours.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == recyclerView.SCROLL_STATE_IDLE) {
View centerView = snapHelper.findSnapView(linearLayoutManager);
int pos = linearLayoutManager.getPosition(centerView);
String val = recyclerAdapter.get(pos % 100);
Log.e("Snapped Item Position:","" + val);
}
}
});
Maybe there is better way to get item values from infinity RecyclerView?
Here u can check the project on GitHub: InfinityRecycler
I have ImageView inside of an item in a RecyclerView. Every time I click on an item, I want the image to become visible and the previous clicked item's image becomes invisible.
public static class MyHolder extends RecyclerView.ViewHolder {
private ImageView image_view;
private TextView text_view_name;
private TextView text_view_abilities;
private ImageView heart_image_view;
public MyHolder(#NonNull final View itemView, final OnItemClickListener listener) {
super(itemView);
image_view = itemView.findViewById(R.id.image_view);
text_view_name = itemView.findViewById(R.id.text_view_name);
text_view_abilities = itemView.findViewById(R.id.text_view_abilities);
heart_image_view = itemView.findViewById(R.id.heart_image_view);
heart_image_view.setImageResource(R.drawable.heart);
heart_image_view.setVisibility(View.GONE);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onItemClick(position);
heart_image_view.setVisibility(View.VISIBLE);
}
}
});
}
}
#NonNull
#Override
public MyHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.single_item_layout, viewGroup, false);
MyHolder holder = new MyHolder(v, mlistener);
return holder;
}
#Override
public void onBindViewHolder(#NonNull MyHolder myHolder, int position) {
Item item = myList.get(position);
myHolder.text_view_name.setText(item.getTitle());
stringArray = item.getAbilitiesObj();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < stringArray.size(); i++) {
try {
builder.append(stringArray.get(i));
builder.append(", ");
} catch (NumberFormatException ex) {
ex.printStackTrace();
}
myHolder.text_view_abilities.setText(builder);
}
if (myHolder.image_view != null) {
String photoUrl = item.getImageUrl();
Picasso.with(mContext).load(photoUrl).into(myHolder.image_view);
}
}
In MyHolder class where item.setOnClick, I set the clicked item image visible but then every time I click on another item, the image of the new item becomes visible and the image of the previous item does not get invisible.
You need to have another array of integers in your adapter to keep track of the items which is clicked. At first, initialize the array of integers with all ones.
// Define an array like the following in your adapter
private int[] selectedItems = new int[yourDataList.size()]; // Initialize the array to have the same size as your data list.
Then initialize the array with all ones. Try having a function like this in your adapter.
private void initializeSeledtedItems() {
for(int item : selectedItems) item = 1;
}
Now in your onBindViewHolder, set the visibility of the ImageView in your RecyclerView items based on the value found in the selectedItems array.
if(selectedItems[position] == 1) heart_image_view.setVisibility(View.VISIBLE);
else heart_image_view.setVisibility(View.GONE);
In the onClickListener modify the selectedItems array as such that, only the item selected has the value one and all the others have zeros. Then call notifyDataSetChanged to take your changes into effect.
private void setSelectedItem(int position) {
for(int i = 0; i < selectedItems.length(); i++) {
if(i == position) selectedItems[i] = 1;
else selectedItems[i] = 0;
}
}
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
setSelectedItem(position);
notifyDataSetChanged();
}
}
}
});
Hope that helps!
My code is for setting Visibility on recycler view's item , when you click on recycler views item it set VISIBLE on that particular item and INVISIBLE on other items.
this code works for me for setting visibility on clicked item and hiding previous icon.
initialize
int selecteditem =0;
onBindViewHolder
if(selecteditem==position){
holder.icSelect.setVisibility(View.VISIBLE);
}
else{
holder.icSelect.setVisibility(View.INVISIBLE);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
selecteditem=position;
holder.icselect.setVisibility(View.VISIBLE);
notifyDataSetChanged();
}
});
i uploaded image for basic idea .
enter image description here
I have a RecyclerView which uses a simple line separator Decoration.
The decoration is fine except when a NEW item is added to the bottom of the recycler and scrolled into view, the decoration is initially drawn in it's final location and then the view underneath scrolls into place, but the decoration doesn't scroll.
The desired behavior would be for the decoration to be drawn in it's starting location and then scroll into position along with the new item.
Here's the relevant portions of the Decoration:
class NormalDecoration extends RecyclerView.ItemDecoration {
private int spacing;
private Drawable drawable;
NormalDecoration(Context context) {
spacing = context.getResources().getDimensionPixelOffset(R.dimen.chat_separator_height);
drawable = ContextCompat.getDrawable(context, R.drawable.chat_divider);
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (applySpacing(view, parent)) {
outRect.top += spacing;
}
}
boolean applySpacing(View view, RecyclerView parent) {
int position = parent.getChildAdapterPosition(view);
return position != -1 && position < mItems.size();
}
#Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
int dividerLeft = parent.getPaddingLeft();
int dividerRight = parent.getWidth() - parent.getPaddingRight();
for(int index = parent.getChildCount() - 1 ; index >= 0 ; --index) {
View view = parent.getChildAt(index);
if(applySpacing(view, parent)) {
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
int dividerTop = view.getBottom() + params.bottomMargin;
int dividerBottom = dividerTop + spacing;
drawable.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom);
drawable.draw(c);
}
}
}
}
My Adapter contains the following helper:
class Adapter {
public void add(final int index, final IChatMessageItem item) {
mItems.add(index, item);
notifyItemInserted(index);
}
}
And here's how I add the item to the recycler that results in unacceptable scrolling behavior:
...
adapter.add(index, item);
layout.scrollToPosition(index);
...
You need to use view.getTranslationX(), getTranslationY(), and getAlpha() respectively to animate the decoration along with the view moving.
If you just draw a divider, you might want to use the official support decoration which also does the above mentioned.
I also wrote an article about this in detail here.
I need recyclerview to scroll it's last item to the middle of itself. I mean that i need las element of recyclerview with LinearLayoutManager not to stop at the bottom of recyclerview but scroll to the middle of it.
Is it a simple way to achieve this?
You can use a RecyclerView.ItemDecoration to put an extra bottom-margin on the last item. It'll end up looking something like this:
public class TopMarginDecoration
extends RecyclerView.ItemDecoration {
#Override
public void getItemOffsets(outRect, view, parent, state) {
int position = parent.getChildAdapterPosition(view);
if (position + 1 == parent.getAdapter().getItemCount()) {
// get height of recyclerview
// get height of child view
// calculate required space to center the child view
outRect.bottom += calculatedSpace;
}
}
}
You can use RecyclerView.addItemDecoration(…) in your Activity or Fragment to tie this together.
final LinearLayoutManager llm = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false);
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (recyclerView.getAdapter().getItemCount() == (llm.findLastCompletelyVisibleItemPosition() + 1)) {
Toast.makeText(MainActivity.this, "Sholled", Toast.LENGTH_SHORT).show();
}
}
});