I'm setting a RecyclerView behaving like a list, I want a button in the bottom of the list that when clicked adds more views, I'm thinking the easier way to do it is to make the position 0 as the first one in the bottom, and increasing the position to the top, so I can add views when the the view in position 0 is clicked.
If there is a better aproach for this problem do share.
Here is my adapter:
public class AddEventsAdapter extends RecyclerView.Adapter<AddEventsAdapter.ViewHolder> {
public List<String> items = new ArrayList<>();
public void addItem(String name) {
notifyItemInserted(items.size() - 1);
items.add(name);
}
public void removeItem(int position) {
items.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, items.size());
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.add_event_item, parent, false);
return new ViewHolder(view);
}
#Override
public int getItemCount() {
return items.size();
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.setData(position);
holder.eventName.setText(i + "");
if(position == 0)
{
holder.theLayout.setBackgroundColor(Color.parseColor("#7F9099"));
holder.eventName.setText("Add");
}
}
static int i;
class ViewHolder extends RecyclerView.ViewHolder{
public TextView eventName;
public RelativeLayout theLayout;
public ViewHolder(final View itemView) {
super(itemView);
eventName = (TextView)itemView.findViewById(R.id.eventName);
theLayout = (RelativeLayout)itemView.findViewById(R.id.backgroundevent);
theLayout.setId(++i);
}
public void setData(final int position) {
theLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (position == items.size() - 1) {
addItem("");
} else {
removeItem(position);
}
}
});
}
}
}
You may notice some errors in that, I've been over it for the last 10 hours and I'm having a logic breakdown
It's solved by addind this line to the LayoutManager .setReverseLayout(true);
you can add a footer view at the end of the list and inside that you can add your button. This is the link to create a footer in recycler view https://github.com/u3breeze/android-RecyclerView-WithHeaderAndFooter. You can add the views in the normal way
Related
I try to update the list item weight code work fine
#NonNull
#Override
public viewlistx onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View xd = getLayoutInflater().inflate(R.layout.lay_yesno_list,parent,false);
return new viewlistx(xd);
}
#Override
public void onBindViewHolder(#NonNull viewlistx holder, final int position) {
btyesi = holder.btyes;
holder.btyes.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.w("click","pos: " + position);
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) btyesi.getLayoutParams();
params.weight = 2.0f;
btyesi.setLayoutParams(params);
}
});
}
#Override
public int getItemCount() {
return 4;
}
public class viewlistx extends RecyclerView.ViewHolder{
private final TextView btyes;
public viewlistx(#NonNull View itemView) {
super(itemView);
btyes = itemView.findViewById(R.id.yesbtx);
}
}
}
but the problem is when I click an item it changes the next item weight
for example pos, 0 click pos 1 item value change or pos 1 clicked pos 2 item value change
What's I'm doing wrong?
found way to fix that for use value animation on list must change
holder
to
final holder
and its work fine
I am working on app that using RecyclerView. I have a Button in each card that when clicked, will count the number of clicks and display it in a TextView in that particular card. The app crashes (Logic Error ) when I run it. What am I doing wrong ?
( I want to setcheck the check box true when counter = counter in Model )
public class MorAdapter extends RecyclerView.Adapter<MorAdapter.HViewholder> {
private ArrayList<ZekeritemModel> model=new ArrayList<>();
public MorAdapter(ArrayList<ZekeritemModel> models,Context context) {
this.model = models;
}
#Override
public HViewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View v = layoutInflater.inflate(R.layout.mor_items, parent, false);
return new HViewholder(v);
}
#Override
public void onBindViewHolder(#NonNull MorAdapter.HViewholder holder, int position) {
holder.plusbtn.setOnClickListener(new View.OnClickListener() {
int count =0;
#Override
public void onClick(View v) {
count++;
holder.plustext.setText(Integer.toString(count));
if (count==model.get(position).getCounter()){
holder.checkBox.setChecked(true);}
}
});
}
#Override
public int getItemCount() {
return model.size();
}
class HViewholder extends RecyclerView.ViewHolder {
TextView plustext;
CircleButton plusbtn;
CheckBox checkBox;
HViewholder(View itemView) {
super(itemView);
plusbtn=itemView.findViewById(R.id.pluss);
plustext=itemView.findViewById(R.id.plustext);
checkBox=itemView.findViewById(R.id.checkk);
}
}
}
add currentCount property to your model ZekeritemModel
so your model became
public class ZekeritemModel {
.... your code
....
int currentCount = 0;
// add your getter and setter ..
}
change your onBind to
#Override
public void onBindViewHolder(#NonNull MorAdapter.HViewholder holder, int position) {
// get current item
final ZekeritemModel item = model.get(position);
int count = item.getCurrentCount();
// set value of counter inside textview
holder.plustext.setText(Integer.toString(count));
holder.plusbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
count++;
item.setCurrentCount(count);
holder.plustext.setText(Integer.toString(count));
if (count==model.get(position).getCounter()){
holder.checkBox.setChecked(true);}
}
});
}
NOTE may code some typo or miss some taps, spaces, parenthesis (as i Have no IDE now).
Because you declared "counter" as global , you must to add counter to your model
I have a dataset I use to create a recycler view and the elements in it have a "solved" Boolean value. When the recyclerview is initialized everything displays correctly. When I scroll through slowly for the most part the corresponding image is displayed correctly but a few of the images blink in and out of view. If I scroll very fast then everything essentially gets messed up.
private class RegularCrimeHolder extends CrimeHolder implements View.OnClickListener{
private Crime mCrime;
private TextView mTitleTextView;
private TextView mDateTextView;
public RegularCrimeHolder(LayoutInflater inflater, ViewGroup parent) {
super(inflater.inflate(R.layout.list_item_crime, parent, false));
mTitleTextView = this.itemView.findViewById(R.id.crime_title);
mDateTextView = this.itemView.findViewById(R.id.crime_date);
mSolved = this.itemView.findViewById(R.id.solved);
itemView.setOnClickListener(this);
}
//Optional
public void bind(Crime crime){
mCrime = crime;
mTitleTextView.setText(mCrime.getTitle());
mDateTextView.setText(mCrime.getDate().toString());
mSolved.setVisibility(crime.isSolved()? View.VISIBLE : View.GONE);
}
#Override
public void onClick(View view) {
//Toast toast = Toast.makeText(getActivity(), mCrime.getTitle() + " clicked!", Toast.LENGTH_SHORT);
//toast.show();
Intent intent = CrimeViewPagerActivity.newIntent(mCrime.getID(), getContext(), CrimeLab.GetIndex(mCrime));
startActivityForResult(intent, REQUEST_CRIME);
}
}
private class CrimeAdapter extends RecyclerView.Adapter<CrimeHolder>{
private List<Crime> mCrimes;
public CrimeAdapter(List<Crime> crimes){
mCrimes = crimes;
this.setHasStableIds(true);
}
#Override
public long getItemId(int position){
return position;
}
#Override
public CrimeHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
if(viewType == 0)
return new RegularCrimeHolder(layoutInflater, viewGroup);
else
return new BadCrimeHolder(layoutInflater, viewGroup);
}
#Override
public int getItemViewType(int position) {
if(mCrimes.get(position).RequiresPolice())
return 1;
else
return 0;
}
#Override
public void onBindViewHolder(#NonNull CrimeHolder crimeHolder, int i) {
Crime crime = mCrimes.get(i);
crimeHolder.bind(crime);
}
#Override
public int getItemCount() {
return mCrimes.size();
}
}
Don't worry! Cool! In your adapter, just do the below things
Kotlin
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItemViewType(position: Int): Int {
return position
}
Java
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}
Your sample code lacks detail. Post the full adapter viewholder and item layout code.
But if I had to guess here, your layout is messed up and your onViewRecycled isn't cleaning up correctly.
For example, say a viewholder was just used and the visibility was set to visible. Now when this viewholder is recycled and re bound, what you'll see is a flicker. Because the view in question is visible from that last bind and it needs to hide itself in this bind.
What you want to do is inside your onViewRecycled, you want to set the visibility set to gone so that when viewholders are reused, there are no flickers.
I'm trying to use a different String, for each item in the RecyclerView, but my program always takes the first String I've put in the ArrayList, no matter which item I click on:
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, final int viewType) {
final View v = LayoutInflater.from(mContext).inflate(R.layout.cardview, null);
final ContentMain contentMain = mData.get(viewType);
v.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Toast.makeText(v.getContext(), contentMain.getMyContent(),
Toast.LENGTH_LONG).show();
}
}
ViewHolder vHolder = new ViewHolder(v);
return vHolder;
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final ContentMain contentMain = mData.get(position);
holder.myContent= mData.get(position).getMyContent();
}
You shouldn't bind the onClickListener in onCreateViewHolder. Purpose of onCreateViewHolder is to construct the ViewHolder and not binding information to it.
Following code in onCreateViewHolder:
final ContentMain contentMain = mData.get(viewType);
Will always return first element because your viewType is 0. It doesn't describe the position.
Move this code in onBindViewHolder as follows:
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final ContentMain contentMain = mData.get(position);
holder.myContent= mData.get(position).getMyContent();
holder.itemView.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Toast.makeText(v.getContext(), contentMain.getMyContent(),Toast.LENGTH_LONG).show();
}
});
}
Get you data inside onClick().
You are getting data using position while creating ViewHolder. It will give wrong position since recyclerview must be calculating layout measurements -
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int position) {
final View v = LayoutInflater.from(mContext).inflate(R.layout.cardview, parent, false); //Avoid inflate layout with null parent
v.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
final ContentMain contentMain = mData.get(getAdapterPosition());
Toast.makeText(v.getContext(), contentMain.getMyContent(), Toast.LENGTH_LONG).show();
}
}
ViewHolder vHolder = new ViewHolder(v);
return vHolder;
}
EDIT:
Probably you should define click listeners inside ViewHolder -
public static ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View v) {
v.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Do you stuffs here...
}
}
}
}
I have a RecyclerView, when I click in the first view it adds another view like in the image, what I want is to set the "add" view which ID is "1" to be fixed in the last position of the recycler instead in the first.
My adapter:
public class AddEventsAdapter extends RecyclerView.Adapter<AddEventsAdapter.ViewHolder> {
private List<String> items = new ArrayList<>();
public void addItem(String name) {
items.add(name);
notifyItemInserted(items.size() - 1);
}
public void removeItem(int position) {
items.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, items.size());
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.add_event_item, parent, false);
return new ViewHolder(view);
}
#Override
public int getItemCount() {
return items.size();
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.setEventNameName(i + "");
if(position == 0)
{
holder.theLayout.setBackgroundColor(Color.parseColor("#7F9099"));
holder.eventName.setText("Add");
}
}
static int i;
class ViewHolder extends RecyclerView.ViewHolder{
public TextView eventName;
public RelativeLayout theLayout;
public ViewHolder(final View itemView) {
super(itemView);
eventName = (TextView)itemView.findViewById(R.id.eventName);
theLayout = (RelativeLayout)itemView.findViewById(R.id.backgroundevent);
theLayout.setId(++i);
theLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (getAdapterPosition()>0){
removeItem(getAdapterPosition());
}else {
addItem("");
}
}
});
}
public void setEventNameName(String TheEventName){
eventName.setText(TheEventName);
}
}
}
In the activity:
final AddEventsAdapter AddContainer = new AddEventsAdapter();
AddEventsRecycler.setLayoutManager(new LinearLayoutManager(this));
AddEventsRecycler.setAdapter(AddContainer);
AddEventsRecycler.setItemViewCacheSize(666);
RecyclerView.ItemAnimator itemAnimator = new DefaultItemAnimator();
itemAnimator.setAddDuration(1000);
itemAnimator.setRemoveDuration(1000);
AddEventsRecycler.setItemAnimator(itemAnimator);
AddContainer.addItem("");
I solved it by creating a custom adapter that allows a footer and a header, here is the project in GitHub: https://github.com/u3breeze/android-RecyclerView-WithHeaderAndFooter
Did you try something like:
public void addItem(String name) {
if (items.size() != 0) {
removeItem(items.size() - 1);
items.add(name);
items.add("Add");
} else
items.add("Add");
notifyItemInserted(items.size() - 1);
}
then id of Add item is items.size() -1
edit:
Change if in your Holder class with following code:
if(position == items.size() - 1)
{
holder.theLayout.setBackgroundColor(Color.parseColor("#7F9099"));
holder.eventName.setText("Add");
}