Unable to create an adapter with custom cards - android

I'm using the cardslib library for having cards in my Android app. It has pre-defined card layouts or we have an option to customize the layout.
While creating the adapter for recycler view, only the list of card objects with pre-defined card layouts are accepted. I get an error when I try to pass a list of custom cards to the constructor.
CardArrayRecyclerViewAdapter cardArrayRecyclerViewAdapter = new CardArrayRecyclerViewAdapter(getApplicationContext(), customCards);
The above code shows an error. customCards is the list of custom card objects. How do I make it work ?

In your CardArrayRecyclerViewAdapter change List<Card> to List<CustomCard> in the constructor

you can write Custom card adapter bellow
card adapter call just like
List<CustomCard> cardlist = new ArrayList<>();
recyclerView.setHasFixedSize(true);
// recyclerView
recyclerView.setLayoutManager(new LinearLayoutManager(this));
// create an Object for Adapter
CardDataAdapter mAdapter = new CardDataAdapter(cardlist);
// set the adapter object to the Recyclerview
recyclerView.setAdapter(mAdapter);
custom Adapter
class CardDataAdapter extends RecyclerView.Adapter<CardDataAdapter.ViewHolder> {
private List<CustomCard> dataSet;
public CardDataAdapter(List<CustomCard> list) {
dataSet = list;
}
#Override
public CardDataAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
// create a new view
View itemLayoutView = LayoutInflater.from(viewGroup.getContext()).inflate(
R.layout.row_custom_card, null);
itemLayoutView.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT));
// create ViewHolder
CardDataAdapter.ViewHolder viewHolder = new CardDataAdapter.ViewHolder(itemLayoutView);
return viewHolder;
}
#Override
public void onBindViewHolder(CardDataAdapter.ViewHolder viewHolder, int i) {
CustomCard fp = dataSet.get(i);
viewHolder.tv_title.setText(fp.getName());
viewHolder.feed = fp;
}
#Override
public int getItemCount() {
return dataSet.size();
}
// inner class to hold a reference to each item of RecyclerView
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView tv_title;
public NotificationModel feed;
public ViewHolder(View itemLayoutView) {
super(itemLayoutView);
tv_title = (TextView) itemLayoutView .findViewById(R.id.tv_title);
itemLayoutView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Write here
}
});
}
}
}
note : CustomCard is model & row_custom_card layout xml where name Textview resde

The second argument to the CardArrayRecyclerViewAdapter constructor must be of type List<Card>. I know it seems like List<CustomCard> should work here, but it will not.
It's impossible to say what the best way to solve this problem is without seeing more code, but you could do this:
List<Card> cards = new ArrayList<>();
cards.addAll(customCards);
// now call constructor with `cards` instead of `customCards`
You can read more about why List<CustomCard> is not accepted for the List<Card> argument here Is List<Dog> a subclass of List<Animal>? Why aren't Java's generics implicitly polymorphic?

Related

How to create a RecyclerView of Buttons

I am creating an AlertDialog custom class, called ActionDialog, which will contains a RecyclerView containing Buttons. I have a List of Button that I populate in the custom class ActionDialog (for now i just populate with useless Button just to try to use it, except one which I create in another class).
The problem is that when i create the AlertDialog, all buttons are showing empty, they are showed but with no text/no clicklistener (as you can see in the image below).
(I have added a custom ActionListener to a Button in another class and then give it as parameter in ActionDialog class. Will it lose the ActionListener?)
Here is the result.
I will leave here my ActionDialog class code, and the adapter class.
This is ActionDialog class:
public class ActionDialog extends AlertDialog{
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private Button actionButtons;
private List<Button> buttons;
private Activity context;
public ActionDialog(#NonNull Activity context, Button actionButtons) {
super(context);
this.context = context;
this.actionButtons = actionButtons;
buttons = new ArrayList<>();
initButton();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//requestWindowFeature(Window.FEATURE_NO_TITLE);
}
private void initButton(){
initZoneButton();
//TODO init all buttons
Button b1 = new Button(context);
b1.setText("ExampleButton1");
Button b2 = new Button(context);
b2.setText("ExampleButton2");
b1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String a;
}
});
buttons.add(b1);
buttons.add(b2);
}
private void initZoneButton(){
buttons.add(actionButtons); //this button is created in another class and give as parameter in this class
}
public void createDialog(){
Builder mBuilder = new Builder(context);
View view = context.getLayoutInflater().inflate(R.layout.dialog_actionbuttons_layout, null);
mRecyclerView = view.findViewById(R.id.dialog_actionbuttons_rv);
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(context);
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new ActionButtonsAdapter(buttons);
mRecyclerView.setAdapter(mAdapter);
mBuilder.setView(view);
mBuilder.create().show();
}
}
Here is the RecyclerView adapter class:
public class ActionButtonsAdapter extends RecyclerView.Adapter<ActionButtonsAdapter.ViewHolder>{
private List<Button> dataButtons;
static class ViewHolder extends RecyclerView.ViewHolder {
Button actionButton;
ViewHolder(View v) {
super(v);
actionButton = v.findViewById(R.id.action_button_rv);
}
}
public ActionButtonsAdapter(List<Button> dataButtons){
this.dataButtons = dataButtons;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.actionButton = dataButtons.get(position);
//i think the problem is here, maybe
}
#Override
public ActionButtonsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_actionbutton_layout, parent, false);
return new ViewHolder(v);
}
#Override
public int getItemCount() {
return dataButtons.size();
}
}
I think in the onBindViewHolder method you should do what ever you want to do with your button.
Also there is no need for the list of buttons here. Make a list the data you need to be held in the Buttons RecyclerView.
I have a RecyclerView that will display Genres for restaurants lets say, So I will create a List of strings to hold these genres names (chickens, meats, etc,..)
Setting its text
holder.actionButton.setText(// Make use of position here);
Or Click Listeners.
Update
You can check google samples for recyclerview here
#Override
public void onBindViewHolder(ViewHolder viewHolder, final int position) {
Log.d(TAG, "Element " + position + " set.");
// Get element from your dataset at this position and replace the contents of the view
// with that element
viewHolder.getTextView().setText(mDataSet[position]);
}
wheres mDataset is Array of Strings.

Why my realm recycle view not showing any data ?

I have implemented RecyclerView show some realm table data. I've created adapter by extending from RealmRecyclerViewAdapter. Even thought I have 3 rows in table (Which I checked by result debugging) nothing showing up in the list. I'm using 'io.realm:android-adapters:2.1.0' adapter and Realm 3.7.2
Here's my code.
Adapter class.
public class UserListAdapter extends RealmRecyclerViewAdapter<User,UserListAdapter.ViewHolder> {
public UserListAdapter(#Nullable OrderedRealmCollection<User> data, boolean autoUpdate) {
super(data, autoUpdate);
setHasStableIds(true);
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.user_list_layout, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
User user = getItem(position);
holder.home.setText(user.getUid());
holder.name.setText(user.getName());
holder.home.setText(user.getHouse().getName());
if(user.isStatus()) {
holder.status.setText("Active");
}else{
holder.status.setText("Inactive");
}
}
#Override
public long getItemId(int index) {
return getItem(index).getUid();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
#BindView(R.id.column_id)
TextView id;
#BindView(R.id.column_name)
TextView name;
#BindView(R.id.column_house)
TextView home;
#BindView(R.id.status_button)
Button status;
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
itemView.setOnClickListener(this);
status.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if(v.getId() == R.id.status){
//TODO: create interface and add method tho trigger when status click
}else{
//TODO: create interface and add method tho trigger when item click
}
}
}
}
code fragment for setting adapter
try(Realm realm = Realm.getDefaultInstance()){
RealmResults<User> users = realm.where(User.class).findAll();
listAdapter = new UserListAdapter(users,true);
recyclerView.setAdapter(listAdapter);
recyclerView.addItemDecoration(new RecyclerViewDividerVertical(2));
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
}
I could have conver RealmResults<User> in to ArrayList<User> and implement normal RecyclerView Adapter and get it done. But As I've understand RealmRecyclerViewAdapter will result auto update result data in case of data change. But i'm not 100% clear on that too. Can any one explain how that works ? Thanks.
try(Realm realm = Realm.getDefaultInstance()){
RealmResults<User> users = realm.where(User.class).findAll();
listAdapter = new UserListAdapter(users,true);
recyclerView.setAdapter(listAdapter);
recyclerView.addItemDecoration(new RecyclerViewDividerVertical(2));
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
} // <--- auto-close!
If you close the Realm instance then the results bound to it become invalidated, and RealmRecyclerViewAdapter checks against isValid() which will return false because you've closed the Realm, so it will be shown with 0 element count.
Refer to proper lifecycle management for UI thread Realm instance (onCreate() open, onDestroy() close) in the documentation.
Looks like your data is invalid and getItemCount() method which is implemented in RealmRecyclerViewAdapter returns 0.

Add, remove and set CardView parameters programmatically

I am developing an application using the RecyclerView & CardView widgets to display the contacts added by the user.
The application allows the user to add a new card, set the appropriate information (name, phone number & image) to be displayed within the card while the card is being added to the list
The number set by the user can be dialed to initiate a phone
call when the card is clicked
I have created the UI, but I don't know how to go about the aforementioned operations using RecyclerView. How to solve this?
In order to bind the contacts to the CardView, you need to create an ArrayList<> to store the contacts in order to bind them. First, create a new class called Contact.java and add the following code:
public class Contact {
public String name;
public int number;
public Contact(String name, int number) {
this.name = name;
this.number = number;
}
}
This class will make sure that each instance within our ArrayList<> has the required values for the name of the contact and phone number. Now, we need to create an adapter class to manage the click events within our CardView and to bind the values from our ArrayList<> to the Views within the CardView. Create a new class called ContactsAdapter.java and add the following code:
public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.ContactsViewHolder> {
public List<Contact> list;
public ContactsAdapter(List<ContactsAdapter> list) {
this.list = list;
}
public static class ContactsViewHolder extends RecyclerView.ViewHolder {
// Update:
RelativeLayout item;
ImageView photo;
TextView name;
TextView number;
public ContactsViewHolder(View view) {
super(view);
// Update:
item = (RelativeLayout) view.findViewById(R.id.id_to_rel_layout); // If not, then add one by using android.id="#+id/whatever"
photo = (ImageView) view.findViewById(R.id.contact_photo);
name = (TextView) view.findViewById(R.id.contact_name);
number = (TextView) view.findViewById(R.id.contact_number);
}
}
#Override
public ContactsViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.contacts_layout, viewGroup, false);
ContactsViewHolder viewHolder = new ContactsViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(ContactsViewHolder viewHolder, final int position) {
// Update:
item.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Do onclick stuff here such as dialing someone
}
});
viewHolder.photo.setImageURI(your_uri);
viewHolder.name.setText(list.get(position).name);
viewHolder.number.setText(list.get(position).number);
}
#Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
#Override
public int getItemCount() {
return list.size();
}
}
Now we have to attach the adapter to our RecyclerView. In the activity that contains the appropriate RecyclerView, add the following code:
private List<Contact> list = new ArrayList<>;
public void loadContacts() {
list.add(new Contacts(photoUri, name, number));
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.your_recyclerview);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
ContactsAdapter adapter = new ContactsAdapter(list);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(adapter);
}
You have successfully binded your contacts with your CardView. Tell me how you go.

RecyclerView architecture - onBindViewHolder nested data

i want to show list as per image for that i am using recycler view and showing row its easy .but inside each row i want to showing many rows
say
i have 10 rows and each row has different row inside
so 1 row have 3 rows where as 2nd have 2 as on
so what is best way to do this
is it possible we can have one more listview inside that row ?
or inside onBindViewHolder i have to manually loop
and inflate layout
Edit :-
when i am trying this is always shuffles
#Override
public void onBindViewHolder(final RecyclerViewHolder holder, int position) {
for (int i = 0; i < position; i++) {
View c = ((Activity) mContext).getLayoutInflater().inflate(R.layout.row2, null);
// ((TextView) c.findViewById(R.id.mis)).setText(data.get(position) + "");
holder.inner.addView(c);
}
holder.n.setText(position+"");
holder.itemView.setTag(position);
}
image as follows
Yes you can use recyclerview inside recycler view just need to maintain separate adapter for that.
Or in this case you can also use expandable list view which will be much easier to use in this case.
If in your case, you don't have many rows, you can apply this:
Use NestedScrollview and add 2 RecyclerViews inside of it.
If you have specific number of rows like 2-3, it will be easy to implement.
Add layout_behavior to your RecyclerViews like below:
<android.support.v7.widget.RecyclerView
android:id="#+id/myRecyclerView"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
And wrap content for layout height is important.
android:layout_height="wrap_content"
And last, you should add this, so scroll works only for NestedScrollView
myRecyclerView.setNestedScrollingEnabled(false);
If you have many items use Single RecyclerView with multiple types of viewholders.
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final int TYPE_MAIN = 0;
private final int TYPE_SUB = 1;
private ArrayList<Object> dataSet;
class ViewHolderMain extends RecyclerView.ViewHolder {
...
}
class ViewHolderSub extends RecyclerView.ViewHolder {
...
}
#Override
public int getItemViewType(int position) {
if(dataSet.get(position) instance of MainRowObject){
return TYPE_MAIN;
}else{
return TYPE_SUB;
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case TYPE_MAIN: return new ViewHolderMain(...);
case TYPE_SUB: return new ViewHolderSub(...);
...
}
}
}
With the library SectionedRecyclerViewAdapter you can group your items in sections:
class MySection extends StatelessSection {
List<String> list;
public MySection(List<String> list) {
// call constructor with layout resource for this Section items
super(R.layout.section_item);
this.list = list;
}
#Override
public int getContentItemsTotal() {
return list.size(); // number of items of this section
}
#Override
public RecyclerView.ViewHolder getItemViewHolder(View view) {
// return a custom instance of ViewHolder for the items of this section
return new MyItemViewHolder(view);
}
#Override
public void onBindItemViewHolder(RecyclerView.ViewHolder holder, int position) {
MyItemViewHolder itemHolder = (MyItemViewHolder) holder;
// bind your view here
itemHolder.tvItem.setText(list.get(position));
}
}
Then you set up the RecyclerView with your sections:
// Create an instance of SectionedRecyclerViewAdapter
SectionedRecyclerViewAdapter sectionAdapter = new SectionedRecyclerViewAdapter();
// Create your sections with the list of data per row
MySection row1Section = new MySection(data1List);
MySection row2Section = new MySection(data2List);
// Add your Sections to the adapter
sectionAdapter.addSection(row1Section);
sectionAdapter.addSection(row2Section);
// Set up your RecyclerView with the SectionedRecyclerViewAdapter
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(sectionAdapter);

How should I initialize an array inside RecyclerView Adapter which has the size of a list while the list will not available on Adapter construction?

I have a RecyclerView that will contain list of item retrieved from the internet. So at first, the list will be empty. After the data retrieved from the internet, it will update the list and call notifyDataSetChanged().
I can adapt the data into the RecyclerView just fine. But, I have an ImageButton for each of item which has different Image if it's clicked. If I initialize the flags array inside onBindViewHolder, each time I scrolled the RecyclerView, the flag array will be reinitialize to false. If I initialize it in the Adapter constructor, it will be 0 index since the list will be empty at first. Where should I put array initializing in adapter if the data will come at some amount of time later?
Below is my code, but the flag array (isTrue) is always reinitialize each time I scrolled my RecyclerView.
public class SomethingAdapter extends RecyclerView.Adapter<SomethingAdapter.ViewHolder> {
private ArrayList<String> someList;
private boolean[] isTrue;
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView someText;
public ImageButton someButton;
public ViewHolder(View v) {
super(v);
someText = (TextView) v.findViewById(R.id.text);
someButton = (ImageButton) v.findViewById(R.id.button);
}
}
public SomethingAdapter(ArrayList<String> someList) {
this.someList = someList;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.some_layout, parent, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(final ViewHolder viewHolder, final int position) {
//TODO: This thing will make isTrue always reinitialize if scrolled
this.isTrue = new boolean[someList.getResults().size()];
viewHolder.someText.setText(someList.get(position));
if (isTrue[position]) {
viewHolder.someButton.setImageResource(R.drawable.button_true);
} else {
viewHolder.someButton.setImageResource(R.drawable.button_false);
}
viewHolder.someButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (isTrue[position]) {
//Connect to the internet and if response is positive {
//isTrue[position] = false;
//viewHolder.someButton.setImageResource(R.drawable.button_false);
//}
} else {
//Connect to the internet and if response is positive {
//isTrue[position] = true;
//viewHolder.someButton.setImageResource(R.drawable.button_true);
//}
}
}
});
}
#Override
public int getItemCount() {
return someList.size();
}
Initialize it when you add items to someList.
Also, don't add click listener in your onBind, create it in onCreateViewHolder. You cannot use position in the click callback, instead you should be using ViewHolder#getAdapterPosition.
See docs for details:
https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#onBindViewHolder(VH, int)

Categories

Resources