I have this working perfectly with a ListView, but decided to update my code to use RecyclerView.
I see there is no default implementation, and the responses to similar questions are quite old.
Is using a sort of cursor the best way to go, or is there a better option?
These are my code snippets for a working RecyclerView with hard-coded values:
MainActivity
recyclerView = (RecyclerView)findViewById(R.id.recycler_view);
mLayoutmanager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(mLayoutmanager);
mAdapter = new recyclerViewDataAdapter();
recyclerView.setAdapter(mAdapter);
recyclerViewDataAdapter
public class recyclerViewDataAdapter extends RecyclerView.Adapter {
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//lets populate our recyler view with the item created;
//get the view from the layout inflator
// third parameter is set to false to prevent viewgroup to attach to root
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item,parent,false);
// as this method need to return the viewHolder type
// need to convert our view to the view holder
RecyclerView.ViewHolder viewHolder = new RecyclerView.ViewHolder(view) {
#Override
public String toString() {
return super.toString();
}
};
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
}
#Override
public int getItemCount() {
return 3000;
}
}
activity_main
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
recycler_item
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="vertical">
<TextView
android:id="#+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hii "
android:textSize="30sp" />
</LinearLayout>
Here is my DatabaseAdapter which worked perfectly with a ListView:
public class DatabaseHelper extends SQLiteAssetHelper {
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "database9.db";
private static final String BOOKS = "books";
private static final String AUTHORS = "authors";
public DatabaseHelper (Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
// setForcedUpgrade();
}
// Getting all books
public ArrayList<Author> getAllAuthors() {
ArrayList<Author> authorList = new ArrayList<>();
// Select all query
String selectQuery = "SELECT id, name FROM " + AUTHORS + " ORDER BY name_alphabetic";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
// create new author object
Author author = new Author();
// set ID and name of author object
author.setID(Integer.parseInt(cursor.getString(0)));
author.setName(cursor.getString(1));
// pass author object to authorList array
authorList.add(author);
} while (cursor.moveToNext());
}
// return author list
return authorList;
}
}
Your can try
In your activity
ArrayList<Author> authors = dbHandler. getAllAuthors();
recyclerView.setHasFixedSize(true);
// ListView
recyclerView.setLayoutManager(new LinearLayoutManager(youractivity.this));
// create an Object for Adapter
CardViewDataAdapter1 mAdapter = new CardViewDataAdapter1(authors);
// set the adapter object to the Recyclerview
recyclerView.setAdapter(mAdapter);
Your adapter is look like
class CardViewDataAdapter1 extends RecyclerView.Adapter<CardViewDataAdapter1.ViewHolder> {
private ArrayList<Author> dataSet;
public CardViewDataAdapter1(ArrayList<Author> os_versions) {
dataSet = os_versions;
}
#Override
public CardViewDataAdapter1.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
// create a new view
View itemLayoutView = LayoutInflater.from(viewGroup.getContext()).inflate(
R.layout.recycler_item, null);
itemLayoutView.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT));
// create ViewHolder
CardViewDataAdapter1.ViewHolder viewHolder = new CardViewDataAdapter1.ViewHolder(itemLayoutView);
return viewHolder;
}
#Override
public void onBindViewHolder(CardViewDataAdapter1.ViewHolder viewHolder, int i) {
Author fp = dataSet.get(i);
viewHolder.tv_name.setText(fp.getName());
viewHolder.menu = fp;
}
#Override
public int getItemCount() {
return dataSet.size();
}
public void updateList(List<Author> temp) {
dataSet = (ArrayList<Author>) temp;
notifyDataSetChanged();
}
// inner class to hold a reference to each item of RecyclerView
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView tv_name;
public Author menu;
public ViewHolder(View itemLayoutView) {
super(itemLayoutView);
tv_name = (TextView) itemLayoutView .findViewById(R.id.tv_name);
}
}
}
Your recycler_item.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
card_view:cardCornerRadius="5dp"
card_view:cardBackgroundColor="#FFFFFF"
card_view:cardUseCompatPadding="true"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/tv_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Enamul"/>
</LinearLayout>
</android.support.v7.widget.CardView>
Related
Question: How do I pass a TextView information into a variable so when a button is clicked it will add that information to a created SQLite database called collections.
Files left out (because I didn't think they related: androidmanafest.xml, database.java (this was for populating the cards database), and cards.java (for setters getters).
What it looks like:
enter image description here
Main Activity:
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
RecyclerView.LayoutManager layoutManager;
SearchAdapter adapter;
MaterialSearchBar materialSearchBar;
List<String> suggestList = new ArrayList<>();
Database database;
//used for inserting card into collection database
DB_Controller controller;
TextView card_name, type, rarity, artist;
Button addCollectionButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//This is all for the controller in order to pass each card into collection database
controller = new DB_Controller(this,"collection.db",null,1);
setContentView(R.layout.layout_item);
card_name = (TextView)findViewById(R.id.card_name);
type = (TextView)findViewById(R.id.type);
rarity = (TextView)findViewById(R.id.rarity);
artist = (TextView)findViewById(R.id.artist);
//functionality of button "ADD TO COLLECTION"
addCollectionButton = (Button)findViewById(R.id.button_collection);
addCollectionButton.setOnClickListener(new View.OnClickListener() {
//when button clicked, insert into collection database
#Override
public void onClick(View view) {
String nameCard = card_name.getText().toString();
String typeCard = type.getText().toString();
String rarityCard = rarity.getText().toString();
String artistCard = artist.getText().toString();
//switch is used in case we need to add more buttons elsewhere in the app
//switch(view.getId()){
// case R.id.button_collection:
//controller.insert_card("drl","drl", "drl", "drl", "drl");
Toast.makeText(getBaseContext(), "ADDED TO COLLECTION", Toast.LENGTH_LONG).show(); //confirm card was added
//break;
//}
}
});
setContentView(R.layout.activity_main);
//init View
recyclerView = (RecyclerView)findViewById(R.id.recycler_search);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
materialSearchBar = (MaterialSearchBar)findViewById(R.id.search_bar);
//materialSearchBar.inflateMenu(R.layout.activity_main);
//init DB
database = new Database(this);
//setup search bar
//materialSearchBar.setHint("Search");
//materialSearchBar.setCardViewElevation(10);
loadSuggestList();
//This is used when typing in search bar suggesting words like those that have been typed
materialSearchBar.addTextChangeListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) {
}
// method for when user types in search bar, return suggested strings
#Override
public void onTextChanged(CharSequence charSequence, int start, int before, int after) {
List<String> suggest = new ArrayList<>();
for(String search : suggestList) {
if(search.toLowerCase().contains(materialSearchBar.getText().toLowerCase()))
suggest.add(search);
}
materialSearchBar.setLastSuggestions(suggest);
}
#Override
public void afterTextChanged(Editable editable) {
}
});
//This is used when user has typed the word(s) needed to search and hits the search icon
materialSearchBar.setOnSearchActionListener(new MaterialSearchBar.OnSearchActionListener() {
#Override
public void onSearchStateChanged(boolean enabled) {
if(!enabled)
recyclerView.setAdapter(adapter);
}
#Override
public void onSearchConfirmed(CharSequence text) {
startSearch(text.toString());
}
#Override
public void onButtonClicked(int buttonCode) {
}
});
//init Adapter default set all result
//adapter = new SearchAdapter(this, database.getFriends());
adapter = new SearchAdapter(this, database.getCards());
recyclerView.setAdapter(adapter);
}
private void startSearch(String text) {
//adapter = new SearchAdapter(this, database.getFriendByName(text));
adapter = new SearchAdapter(this, database.getCardsByName(text));
recyclerView.setAdapter(adapter);
}
//for populating suggestion list when search bar has been activated
private void loadSuggestList() {
suggestList = database.getNames();
materialSearchBar.setLastSuggestions(suggestList);
}
}
layout_item.xml:
<?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:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardElevation="8dp"
android:layout_margin="8dp">
<!--Creation of overall look of searched results
Main design tile for each searched result-->
<LinearLayout
android:orientation="horizontal"
android:layout_margin="8dp"
android:background="#android:color/white"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--default image for each tile-->
<ImageView
android:src="#drawable/ic_image_black_24dp"
android:layout_width="70dp"
android:layout_height="70dp" />
<!--design tile within the main tile to display the information pulled from database-->
<LinearLayout
android:orientation="vertical"
android:layout_weight="9"
android:layout_width="0dp"
android:layout_height="wrap_content">
<!--information pulled from database design: NAME
android:id="#+id/name"-->
<TextView
android:id="#+id/card_name"
android:layout_marginLeft="10dp"
android:gravity="center_vertical|start"
android:textAllCaps="true"
android:textStyle="bold"
android:text="Eddy Lee"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<!--information pulled from database design: EMAIL
android:id="#+id/email"-->
<TextView
android:id="#+id/type"
android:layout_marginLeft="10dp"
android:gravity="center_vertical|start"
android:textStyle="italic"
android:text="eddy#gmail.com"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<!--information pulled from database design: PHONE
android:id="#+id/phone"-->
<TextView
android:id="#+id/rarity"
android:layout_marginLeft="10dp"
android:gravity="center_vertical|start"
android:textAllCaps="true"
android:textStyle="bold"
android:text="(123)456-7890"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<!--information pulled from database design: ADDRESS
android:id="#+id/address"-->
<TextView
android:id="#+id/artist"
android:layout_marginLeft="10dp"
android:gravity="center_vertical|start"
android:textAllCaps="true"
android:textStyle="normal"
android:text="123 Seseme Street"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="#+id/button_collection"
android:layout_width="200dp"
android:layout_height="35dp"
android:text="Add to Collection"
/>
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.darrelbott.search.MainActivity">
<com.mancj.materialsearchbar.MaterialSearchBar
app:mt_speechMode="false"
app:mt_hint="Custom hint"
app:mt_maxSuggestionsCount="10"
app:mt_searchBarColor="#color/colorPrimary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/search_bar" />
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_search"
android:layout_below="#+id/search_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
DB_Controller:
public class DB_Controller extends SQLiteOpenHelper {
private static final String TABLE_COLLECTION = "collection";
private static final String COLUMN_COLLECTION_ACCOUNT = "account";
private static final String COLUMN_COLLECTION_NAME = "card_name";
private static final String COLUMN_COLLECTION_TYPE = "type";
private static final String COLUMN_COLLECTION_RARITY = "rarity";
private static final String COLUMN_COLLECTION_ARTIST = "artist";
SQLiteDatabase db;
Context context;
int version = 1;
public DB_Controller(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, "collection.db", factory, version);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_COLLECTION + " (id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ COLUMN_COLLECTION_ACCOUNT + " TEXT, "
+ COLUMN_COLLECTION_NAME + " TEXT, "
+ COLUMN_COLLECTION_TYPE + " TEXT, "
+ COLUMN_COLLECTION_RARITY + " TEXT, "
+ COLUMN_COLLECTION_ARTIST + " TEXT)");
}
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
//sqLiteDatabase.execSQL("DROP TABLE IF EXISTS collection;");
//onCreate(sqLiteDatabase);
}
public void insert_card(String account, String card_name, String type, String rarity, String artist) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(COLUMN_COLLECTION_ACCOUNT,account);
contentValues.put(COLUMN_COLLECTION_NAME,card_name);
contentValues.put(COLUMN_COLLECTION_TYPE,type);
contentValues.put(COLUMN_COLLECTION_RARITY,rarity);
contentValues.put(COLUMN_COLLECTION_ARTIST,artist);
db.insert(TABLE_COLLECTION,null,contentValues);
//this.getWritableDatabase().insertOrThrow("collection.db","",contentValues);
}
}
Adapter (which holds both SearchAdapter & SearchViewHolder):
class SearchViewHolder extends RecyclerView.ViewHolder {
//public TextView name, address, email, phone;
public TextView card_name, type, rarity, artist;
public SearchViewHolder(#NonNull View itemView) {
super(itemView);
card_name = (TextView)itemView.findViewById(R.id.card_name);
type = (TextView)itemView.findViewById(R.id.type);
rarity = (TextView)itemView.findViewById(R.id.rarity);
artist = (TextView)itemView.findViewById(R.id.artist);
}
}
public class SearchAdapter extends RecyclerView.Adapter<SearchViewHolder> {
private Context context;
//private List<Friend> friends;
private List<Cards> cards;
public SearchAdapter(Context context, List<Cards> cards /*List<Friend> friends*/ ) {
this.context = context;
//this.friends = friends;
this.cards = cards;
}
#NonNull
#Override
public SearchViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View itemView = inflater.inflate(R.layout.layout_item, parent, false);
return new SearchViewHolder(itemView);
}
Button addCollectionButton;
#Override
public void onBindViewHolder(#NonNull SearchViewHolder holder, int position) {
/*
holder.name.setText(friends.get(position).getName());
holder.address.setText(friends.get(position).getAddress());
holder.email.setText(friends.get(position).getEmail());
holder.phone.setText(friends.get(position).getPhone());
*/
holder.card_name.setText(cards.get(position).getName());
holder.type.setText(cards.get(position).getType());
holder.rarity.setText(cards.get(position).getRarity());
holder.artist.setText(cards.get(position).getArtist());
/*
//functionality of button "ADD TO COLLECTION"
final DB_Controller controller = new DB_Controller(this,"collection.db",null,1);
addCollectionButton.setOnClickListener(new View.OnClickListener() {
//when button clicked, insert into collection database
#Override
public void onClick(View view) {
//String card_name1 = card_name.setText(cards.get(position).getName());
//switch is used in case we need to add more buttons elsewhere in the app
//switch(view.getId()){
// case R.id.button_collection:
controller.insert_card("drl","drl", "drl", "drl", "drl");
//Toast.makeText(getApplicationContext(), "ADDED TO COLLECTION", Toast.LENGTH_LONG).show(); //confirm card was added
//break;
//}
}
});
*/
}
#Override
public int getItemCount() {
//return friends.size();
return cards.size();
}
}
You need to have the onClickListener inside the adapter where the button actually is. What you have done is have the listener in the main activity which is not correct. Put your listener in onBindViewHolder() and it should work if there is no issue in the sql code
As I commented earlier: You need to add the onClick() method of your "addCollectionButton" Button to your custom adapter class in the onBindViewHolder() method. The "button_collection" Button in your CardView layout has nothing to do with the "main_activity" layout.
Try this code for your Adapter.
Note: I did this in a text editor, so there might be a couple of typos!
Also Note: I changed you "cards" List into an ArrayList--so you will need to compensate in you Activity code.
public class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.MyViewHolder> {
private static final String TAG = SearchAdapter.class.getSimpleName();
private Context mContext;
private final DB_Controller dbController;
private ArrayList<Cards> cards;
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView card_name, type, rarity, artist;
public Button addCollectionButton;
public MyViewHolder(View itemView) {
super(itemView);
card_name = (TextView)itemView.findViewById(R.id.card_name);
type = (TextView)itemView.findViewById(R.id.type);
rarity = (TextView)itemView.findViewById(R.id.rarity);
artist = (TextView)itemView.findViewById(R.id.artist);
addCollectionButton = (Button)itemView.findViewById(R.id.button_collection);
}
}
public SearchAdapter(Context context, ArrayList<Cards> cards) {
this.mContext = context;
dbController = new DB_Controller(context,"collection.db",null,1);
this.cards = cards;
}
#Override
public MyViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View itemView = inflater.inflate(R.layout.layout_item, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Cards cardsData = cards.get(position);
holder.card_name.setText(cardsData.getName());
holder.type.setText(cardsData.getType());
holder.rarity.setText(cardsData.getRarity());
holder.artist.setText(cardsData.getArtist());
holder.addCollectionButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.e(TAG, "on click " + position);
String cardName = cardsData.getName();
String cardType = cardsData.getType();
String cardRarity = cardsData.getRarity();
String cardArtist = cardsData.getArtist();
// You will need to add the data as needed!
dbController.insert_card("drl","drl", "drl", "drl", "drl");
Toast.makeText(mContext, "ADDED TO COLLECTION: " + cardName, Toast.LENGTH_LONG).show(); //confirm card was added
}
});
}
#Override
public int getItemCount() {
return cards.size();
}
}
----------
Please let me know if you have any issues with the above code.
I am trying to have 2 layout in one RecyclerView
I have a recycler view list which is called Bookmark and it is parsed from an xml and this is all working , but I wanna in this recyclerview to put another layout which contains a button and that can be clickable.
Like in the photo the icons are from recyclerview and the plus button need to be compatible with the list, if the list is larger or smaller the button will be compatible with the space of list.
This is my new code for the Adapter which depends on the answer #LluisFelisart
And this is the error
ViewHolder views must not be attached when created. Ensure that you are not passing 'true' to the attachToRoot parameter of LayoutInflater.inflate(..., boolean attachToRoot)
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
ArrayList<Bookmark> arrayList = new ArrayList<>();
public MyAdapter(Context context, ArrayList<Bookmark> arrayList) {
this.context = context;
this.arrayList = arrayList;
}
public class ViewHolder0 extends RecyclerView.ViewHolder {
TextView tvName,tvId,tvSearchUrl,tvNativeUrl;
ImageView tvIcon;
public ViewHolder0(#NonNull View itemView) {
super(itemView);
tvName=itemView.findViewById(R.id.textView);
tvIcon = itemView.findViewById(R.id.image_view);
/* tvId=itemView.findViewById(R.id.tvId);
tvSearchUrl=itemView.findViewById(R.id.tvSearchUrl);
tvNativeUrl=itemView.findViewById(R.id.tvNativeUrl);*/
}
}
public class ViewHolder2 extends RecyclerView.ViewHolder {
ImageView tvAddBookmark;
public ViewHolder2(#NonNull View itemView) {
super(itemView);
tvAddBookmark = itemView.findViewById(R.id.image_button_add);
}
}
#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;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.grid_item, viewGroup, false);
switch (i) {
case 0: return new ViewHolder0(viewGroup);
case 2: return new ViewHolder2(viewGroup);
}
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case 0:
ViewHolder0 viewHolder0 = (ViewHolder0) holder;
((ViewHolder0) holder).tvName.setText(arrayList.get(position).getName());
((ViewHolder0) holder).tvIcon.setImageResource(arrayList.get(position).getIcon());
break;
case 2:
ViewHolder2 viewHolder2 = (ViewHolder2) holder;
}
((ViewHolder0) holder).tvIcon.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent;
intent = new Intent(context, BookmarkActivity.class);
v.getContext().startActivity(intent);
}
});
((ViewHolder0) holder).tvIcon.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
Intent intent = new Intent(context, ActivityBookmarksFavorites.class);
v.getContext().startActivity(intent);
return false;
}
});
}
#Override
public int getItemCount() {
return arrayList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView tvName,tvId,tvSearchUrl,tvNativeUrl;
ImageView tvIcon;
public ViewHolder(#NonNull View itemView) {
super(itemView);
tvName=itemView.findViewById(R.id.textView);
tvIcon = itemView.findViewById(R.id.image_view);
/* tvId=itemView.findViewById(R.id.tvId);
tvSearchUrl=itemView.findViewById(R.id.tvSearchUrl);
tvNativeUrl=itemView.findViewById(R.id.tvNativeUrl);*/
}
}
}
This is the grid item layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:orientation="vertical"
android:visibility="visible"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:id="#+id/image_view"
style="#style/BookmarkIconIv" />
<TextView android:id="#+id/textView"
android:layout_marginTop="1.0dip"
style="#style/BookmarkTextTv" />
</LinearLayout>
This is the layout of button which I want to be in the recycler view
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageButton
android:id="#+id/image_button_add"
android:layout_width="45dp"
android:layout_height="45dp"
android:src="#drawable/ic_add_black_24dp"
android:background="#color/transparent" />
</android.support.constraint.ConstraintLayout>
This is the Fragment which the recycler view it is shown
public class FragmentBookmark extends Fragment {
ArrayList<Bookmark> arrayList = new ArrayList<>();
XmlPullParser pullParser;
MyAdapter myAdapter;
View paramView;
RecyclerView myRecyclerView;
private Context mContext;
#Override
public void onAttach(Context context) {
super.onAttach(context);
mContext = context;
}
#Nullable
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
paramView = inflater.inflate(R.layout.bookmark, container, false);
myRecyclerView = paramView.findViewById(R.id.myRecyclerView);
myRecyclerView.setLayoutManager(new GridLayoutManager(mContext, 4));
myRecyclerView.setHasFixedSize(true);
myAdapter = new MyAdapter(mContext, arrayList);
myRecyclerView.setAdapter(myAdapter);
try {
XmlPullParser xpp = getResources().getXml(R.xml.bookmarks);
while (xpp.getEventType() != XmlPullParser.END_DOCUMENT) {
if (xpp.getEventType() == XmlPullParser.START_TAG) {
if (xpp.getName().equals("Bookmark")) {
Bookmark bookmark = new Bookmark();
bookmark.setName(xpp.getAttributeValue(null, "name"));
int drawableResourceId = getResources().getIdentifier(xpp.getAttributeValue(null, "icon"),"drawable", mContext.getPackageName());
bookmark.setIcon(drawableResourceId);
arrayList.add(bookmark);
}
}
xpp.next();
}
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
myAdapter.notifyDataSetChanged();
return paramView;
}
}
This is the layout bookmark which contains recyclerview
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/myRecyclerView"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:fillViewport="false">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
Here is the answer
Follow this steps
First Create a two layout for your Multiple viewType
SAMPLE CODE
layout.layout_one
<?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:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:cardCornerRadius="15dp"
app:cardElevation="5dp"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="Name : " />
<TextView
android:id="#+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="Icon : " />
<ImageView
android:id="#+id/tvIcon"
android:layout_width="20dp"
android:layout_height="20dp"
android:padding="10dp"
android:text="" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="Id : " />
<TextView
android:id="#+id/tvId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="SearchUrl : " />
<TextView
android:id="#+id/tvSearchUrl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="NativeUrl : " />
<TextView
android:id="#+id/tvNativeUrl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
layout.button_two
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/imgButton"
android:layout_width="50dp"
android:layout_height="50dp" />
</LinearLayout>
Now you need to create two RecyclerView.ViewHolder for your both viewType
Now you need to Override getItemViewType()
it Return the viewType of the item at position for the purposes of view recycling.
Now in your onCreateViewHolder() method you need to return your instance of your ViewHolder based on your viewType which you will get using getItemViewType() method
Than in your onBindViewHolder() method based your viewType set your view property
here is the sample code of RecyclerView.Adapter with multiple view types
DataAdapter
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
public class DataAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
ArrayList<Bookmark> arrayList = new ArrayList<>();
public static final int ITEM_TYPE_ONE = 0;
public static final int ITEM_TYPE_TWO = 1;
public DataAdapter(Context context, ArrayList<Bookmark> arrayList) {
this.context = context;
this.arrayList = arrayList;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = null;
// check here the viewType and return RecyclerView.ViewHolder based on view type
if (viewType == ITEM_TYPE_ONE) {
view = LayoutInflater.from(context).inflate(R.layout.layout_one, parent, false);
return new ViewHolder(view);
} else if (viewType == ITEM_TYPE_TWO) {
view = LayoutInflater.from(context).inflate(R.layout.button_two, parent, false);
return new ButtonViewHolder(view);
}else {
return null;
}
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
final int itemType = getItemViewType(position);
// First check here the View Type
// than set data based on View Type to your recyclerview item
if (itemType == ITEM_TYPE_ONE) {
ViewHolder viewHolder = (ViewHolder) holder;
viewHolder.tvName.setText(arrayList.get(position).getName());
viewHolder.tvIcon.setImageResource(arrayList.get(position).getIcon());
viewHolder.tvSearchUrl.setText(arrayList.get(position).getSearchUrl());
viewHolder.tvNativeUrl.setText(arrayList.get(position).getNativeUrl());
} else if (itemType == ITEM_TYPE_TWO) {
ButtonViewHolder buttonViewHolder = (ButtonViewHolder) holder;
buttonViewHolder.imgButton.setImageResource(arrayList.get(position).getIcon());
}
}
#Override
public int getItemViewType(int position) {
// based on you list you will return the ViewType
if (arrayList.get(position).getViewType() == 0) {
return ITEM_TYPE_ONE;
} else {
return ITEM_TYPE_TWO;
}
}
#Override
public int getItemCount() {
return arrayList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView tvName, tvId, tvSearchUrl, tvNativeUrl;
ImageView tvIcon;
public ViewHolder(#NonNull View itemView) {
super(itemView);
tvName = itemView.findViewById(R.id.tvName);
tvIcon = itemView.findViewById(R.id.tvIcon);
tvId = itemView.findViewById(R.id.tvId);
tvSearchUrl = itemView.findViewById(R.id.tvSearchUrl);
tvNativeUrl = itemView.findViewById(R.id.tvNativeUrl);
}
}
public class ButtonViewHolder extends RecyclerView.ViewHolder {
ImageView imgButton;
public ButtonViewHolder(#NonNull View itemView) {
super(itemView);
imgButton = itemView.findViewById(R.id.imgButton);
}
}
}
When you adding data in your list you need to provide the viewtype in list
Make some changes in your Bookmark POJO class
Bookmark POJO class
public class Bookmark
{
String name,id,nativeUrl,searchUrl;
int icon;
int viewType;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getIcon() {
return icon;
}
public void setIcon(int icon) {
this.icon = icon;
}
public String getNativeUrl() {
return nativeUrl;
}
public void setNativeUrl(String nativeUrl) {
this.nativeUrl = nativeUrl;
}
public String getSearchUrl() {
return searchUrl;
}
public void setSearchUrl(String searchUrl) {
this.searchUrl = searchUrl;
}
public int getViewType() {
return viewType;
}
public void setViewType(int viewType) {
this.viewType = viewType;
}
#Override
public String toString() {
return "Bookmark{" +
"name='" + name + '\'' +
", icon='" + icon + '\'' +
", id='" + id + '\'' +
", nativeUrl='" + nativeUrl + '\'' +
", searchUrl='" + searchUrl + '\'' +
'}';
}
}
Sample activity code
import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private Context mContext;
ArrayList<Bookmark> arrayList = new ArrayList<>();
RecyclerView myRecyclerView;
DataAdapter dataAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
myRecyclerView = findViewById(R.id.myRecyclerView);
myRecyclerView.setLayoutManager(new LinearLayoutManager(mContext));
myRecyclerView.setHasFixedSize(true);
dataAdapter = new DataAdapter(mContext, arrayList);
myRecyclerView.setAdapter(dataAdapter);
try {
XmlPullParser xpp = getResources().getXml(R.xml.bookmarks);
while (xpp.getEventType() != XmlPullParser.END_DOCUMENT) {
if (xpp.getEventType() == XmlPullParser.START_TAG) {
if (xpp.getName().equals("Bookmark")) {
Log.e("MY_VALUE", " * " + xpp.getAttributeValue(0) + " * ");
Log.e("MY_VALUE", " * " + xpp.getAttributeValue(1) + " * ");
Log.e("MY_VALUE", " * " + xpp.getAttributeValue(5) + " * ");
Log.e("MY_VALUE", " * " + xpp.getAttributeValue(2) + " * ");
Log.e("MY_VALUE", " * " + xpp.getAttributeValue(3) + " * ");
Log.e("MY_VALUE", " * " + xpp.getAttributeValue(4) + " * ");
Bookmark bookmark = new Bookmark();
bookmark.setName(xpp.getAttributeValue(0));
int drawableResourceId = this.getResources().getIdentifier(xpp.getAttributeValue(1), "drawable", mContext.getPackageName());
bookmark.setIcon(drawableResourceId);
bookmark.setId(xpp.getAttributeValue(2));
bookmark.setSearchUrl(xpp.getAttributeValue(3));
bookmark.setNativeUrl(xpp.getAttributeValue(4));
// here you need to set view type
bookmark.setViewType(0);
arrayList.add(bookmark);
}
}
xpp.next();
}
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// here i have added second viewType
// you need to set as per your requirement
Bookmark bookmark = new Bookmark();
bookmark.setViewType(1);
bookmark.setIcon(R.drawable.dishu);
arrayList.add(bookmark);
dataAdapter.notifyDataSetChanged();
}
}
NOTE
In the below code i have set second viewType at the last index of Arraylist
you need to set viewType as per your requirement
For more information you can check below articles
Working with RecyclerView and multiple view types
A RecyclerView with multiple item types
Android RecyclerView with Different Child Layouts
Android Pagination Tutorial—Handling Multiple View Types
Heterogenous Layouts inside RecyclerView
Android RecyclerView Example – Multiple ViewTypes
How to create RecyclerView with multiple view type?
Android Multiple row layout using RecyclerView
You can use different layouts on the same RecyclerView , just override adapter getItemViewType() method and return a different int value for the button layout, in your example you should return for example 1 for the normal item and 2 for the button item.
The view type is passed as argument to onCreateViewHolder() method and depending of the viewType value you inflate the normal layout or the button layout.
It seems that you need also make getItemCount() to return one more than the array size
Hope it will help
Here an example:
How to create RecyclerView with multiple view type?
Do this operations in your Activity.
ArrayList<Bookmark> data = new ArrayList<>();
//data.addAll(your array list bookmark); uncomment this line add your all array list of bookmark
Bookmark d = new Bookmark(0);
data.add(d);
mList.setAdapter(new BookMarkAdapter(activity, data));
Try This adapter
public class BookMarkAdapter extends RecyclerView.Adapter {
private Context context;
private ArrayList<Bookmark> data;
public BookMarkAdapter(Context context, ArrayList<Bookmark> data) {
this.context = context;
this.data = data;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
if (viewType == 1)
return new ViewBookmarkHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_with_normal_image_and_textview, parent, false));
else
return new AddBookmarkHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_with_image, parent, false));
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
Bookmark d = data.get(position);
if (d.getType()==1) {
ViewBookmarkHolder viewBookmarkHolder =(ViewBookmarkHolder) holder;
// do your show image and textview operation here
} else {
AddBookmarkHolder addBookmarkHolder =(AddBookmarkHolder) holder;
// do your on click operation here. Like adding new bookmark and update your arraylist and notify data changed for adapter.
}
}
#Override
public int getItemViewType(int position) {
return data.get(position).getType();
}
#Override
public int getItemCount() {
return data.size();
}
}
Update this methods and variables in your Bookmark Pojo
public class Bookmark {
private Integer type;
public Bookmark(Integer type) {
this.type = type;
}
public void setType(Integer type) {
this.type = type;
}
public Integer getType() {
if(type==null)
return 1;
return type;
}
}
I've got a RecyclerView which populates from an ArrayList. The output is a CardView layout.
In the Cardview, there are 2 buttons amongst other Views.
They only have to read the current value of a TextView, which by default is 1, and increase or decrease it.
The Arraylist contains 8 items.
When I run the app the UI works fine. Trouble is when I try to modify the value of the TextView.
The value is correctly increased and decreased on the CardView I'm working on, but ALSO the value is modified on another CardView. And in that second CardView, modifying its TextView value, also modifies the first one.
So, what am I doing wrong?
This is my Fragment:
public class Fragment_rosas extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.layout_rosas,container,false);
RecyclerView recyclerview_rosas;
RecyclerView.Adapter adaptador_rv_rosas;
RecyclerView.LayoutManager lm_rosas;
List rosas = new ArrayList();
rosas.add(new Tropa(1,R.drawable.minibarbaro, getResources().getString(R.string.barbaro),7,1));
recyclerview_rosas = (RecyclerView) view.findViewById(R.id.recyclerView_tropasRosas);
recyclerview_rosas.setHasFixedSize(true);
lm_rosas = new LinearLayoutManager(getContext());
recyclerview_rosas.setLayoutManager(lm_rosas);
adaptador_rv_rosas = new AdaptadorTropa(rosas);
recyclerview_rosas.setAdapter(adaptador_rv_rosas);
return view;
}
}
And here the part of code on my Adapter:
#Override
public void onBindViewHolder(final TropaViewHolder viewHolder, int i) {
viewHolder.imagen.setImageResource(items.get(i).getImagen());
viewHolder.nombre.setText(items.get(i).getNombre());
viewHolder.maxnivel.setText(String.valueOf(items.get(i).getNivelMax()));
viewHolder.espacioencamp.setText((String.valueOf(items.get(i).getEspacioEnCamp())));
final String nombre = items.get(i).getNombre();
final int maxnivel = items.get(i).getNivelMax();
viewHolder.nivelmas.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String niveltemp = viewHolder.nivel.getText().toString();
String nivelmaxtemp = viewHolder.maxnivel.getText().toString();
int nivel = Integer.parseInt(niveltemp);
int maxxnivel = Integer.parseInt(nivelmaxtemp);
int nuevonivel = nivel+1 ;
if (nuevonivel<=maxxnivel) {
viewHolder.txtv_nivel.setText(String.valueOf(nuevonivel));
}
}
});
My OnCreateViewHolder (nothing really happens here):
#Override
public TropaViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.cardview, viewGroup, false);
return new TropaViewHolder(v);
}
Here is the solution, as mentioned in the comment above, it addresses two problems:
1. positiontoValueMap - saves current value for each position
2. onclicklistener is passed to the ViewHolder in onCreateViewHolder
Adapter Class
public class MyAdapter extends RecyclerView.Adapter {
private Context context;
private List<String> dataList;
private Map<Integer, Integer> positionToValueMap = new HashMap<>();
public MyAdapter(Context context, List<String> dataList) {
this.context = context;
this.dataList = dataList;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.recycler_view_item, null, false);
return new MyViewHolder(view, new OnRecyclerItemClickListener());
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
((MyViewHolder) holder).onRecyclerItemClickListener.updatePosition(position);
((MyViewHolder) holder).position.setText("" + position);
((MyViewHolder) holder).title.setText(dataList.get(position));
int valueToDisplay = 1;
if(positionToValueMap.containsKey(position)) {
valueToDisplay = positionToValueMap.get(position);
} else {
positionToValueMap.put(position, valueToDisplay);
}
((MyViewHolder) holder).valueView.setText("value: " + valueToDisplay);
}
#Override
public int getItemCount() {
return dataList.size();
}
private class MyViewHolder extends RecyclerView.ViewHolder {
private OnRecyclerItemClickListener onRecyclerItemClickListener;
private TextView position;
private TextView title;
private TextView valueView;
public MyViewHolder(View itemView, OnRecyclerItemClickListener onRecyclerItemClickListener) {
super(itemView);
itemView.setOnClickListener(onRecyclerItemClickListener);
this.onRecyclerItemClickListener = onRecyclerItemClickListener;
this.position = (TextView) itemView.findViewById(R.id.position);
this.title = (TextView) itemView.findViewById(R.id.title);
this.valueView = (TextView) itemView.findViewById(R.id.value_view);
}
}
private class OnRecyclerItemClickListener implements View.OnClickListener {
private int position = -1;
public void updatePosition(int position) {
this.position = position;
}
#Override
public void onClick(View v) {
int oldValue = positionToValueMap.get(position); // get current value
oldValue++; // increment
positionToValueMap.put(position, oldValue); // save current value
notifyItemChanged(position); // update clicked view so that it picks up the new saved value from the positionToValueMap in onBindViewHolder
}
}
}
RecyclerView item layout
<TextView
android:id="#+id/position"
android:layout_width="30dp"
android:layout_height="50dp"
android:textColor="#android:color/white"
android:gravity="center"
android:background="#android:color/holo_green_light"
android:layout_alignParentLeft="true"/>
<TextView
android:id="#+id/title"
android:layout_width="50dp"
android:layout_height="50dp"
android:textColor="#android:color/white"
android:gravity="center"
android:background="#android:color/holo_green_dark"
android:layout_toRightOf="#id/position" />
<TextView
android:id="#+id/value_view"
android:layout_width="match_parent"
android:layout_height="50dp"
android:textColor="#android:color/white"
android:gravity="center"
android:background="#android:color/holo_green_light"
android:layout_toRightOf="#id/title"
android:layout_alignParentRight="true"/>
</RelativeLayout>
And Activity to test it out
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
recyclerView.setAdapter(new MyAdapter(getApplicationContext(), getSampleData()));
}
private static List<String> getSampleData() {
List<String> dataList = new ArrayList<>();
dataList.add("zero");
dataList.add("one");
dataList.add("two");
dataList.add("three");
dataList.add("four");
dataList.add("five");
dataList.add("six");
dataList.add("seven");
dataList.add("eight");
dataList.add("nine");
dataList.add("ten");
dataList.add("eleven");
dataList.add("twelve");
dataList.add("thirteen");
dataList.add("fourteen");
dataList.add("fifteen");
dataList.add("sixteen");
dataList.add("seventeen");
dataList.add("eighteen");
dataList.add("nineteen");
dataList.add("twenty");
return dataList;
}
}
activity layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"/>
</RelativeLayout>
I have list of contacts and i have show this list on RecyclerView using CardView.
List is showing perfectly But now I want to make clickable Card View. So that When I click on particular contact i will show details of particular contact.
List is perfectly shown but when i click on particular contact click event is not working .
I have also used clickable true on CardView and OnClickListener event on ContactAdapter class .
What I did :
I have three layout activity_main, contact_list, contact_detail.
In activity_main i used recycler_view.
In contact_list i used card_view and bind it with recycler view.
I have three java class :
Contact - where i defined variable with getter and setter
ContactAdapter - where i get contacts and bind it with card view.
MainActivity - where i get all contacts and show it on recycler view.
activity_main layout code:
<android.support.v7.widget.RecyclerView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="#+id/recycler_view">
</android.support.v7.widget.RecyclerView>
contact_list_layout code:
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/card_view"
android:clickable="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Remo"
android:id="#+id/person_name"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/person_name"
android:text="example#gmail.com"
android:id="#+id/person_email"/>
</RelativeLayout>
</android.support.v7.widget.CardView>
Java Class Code:
MainActivity Code :
RecyclerView recyclerView;
RecyclerView.Adapter adapter;
RecyclerView.LayoutManager layoutManager;
String[] name,email;
ArrayList<Contact> list = new ArrayList<Contact>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
name = getResources().getStringArray(R.array.person_name);
email = getResources().getStringArray(R.array.person_email);
int count = 0;
for (String Name : name)
{
Contact contact = new Contact(Name,email[count]);
count++;
list.add(contact);
}
recyclerView= (RecyclerView) findViewById(R.id.recycler_view);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
adapter=new ContactAdapter(list,this);
recyclerView.setAdapter(adapter);
}
ContactAdapter code :
ArrayList<Contact> contacts = new ArrayList<Contact>();
Context ctx;
public ContactAdapter(ArrayList<Contact> contacts, Context ctx) {
this.contacts = contacts;
this.ctx = ctx;
}
#Override
public ContactViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.contact_list_layout, parent, false);
ContactViewHolder contactViewHolder = new ContactViewHolder(view, ctx, contacts);
return contactViewHolder;
}
#Override
public void onBindViewHolder(ContactViewHolder holder, int position) {
Contact CON = contacts.get(position);
holder.person_name.setText(CON.getName());
holder.person_email.setText(CON.getEmail());
}
#Override
public int getItemCount() {
return contacts.size();
}
public static class ContactViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView person_name, person_email;
ArrayList<Contact> contacts = new ArrayList<Contact>();
Context ctx;
public ContactViewHolder(View view, Context ctx, ArrayList<Contact> contacts) {
super(view);
this.contacts = contacts;
this.ctx = ctx;
person_name = (TextView) view.findViewById(R.id.person_name);
person_email = (TextView) view.findViewById(R.id.person_email);
}
#Override
public void onClick(View v) {
int position = getAdapterPosition();
Contact contact = this.contacts.get(position);
Intent intent =new Intent(this.ctx,ContactDetail.class);
this.ctx.startActivity(intent);
}
}
I fixed the same issue when I remove android:clickable="true" on item view.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="#dimen/item_dashboard_size"
android:layout_margin="#dimen/item_dashboard_margin">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?selectableItemBackground"
android:padding="#dimen/item_dashboard_padding">
.....
</android.support.v7.widget.CardView>
From your code, you are missed setting listener for your cardview. to trigger onClick(View v) method you have to set listener for the corresponding view.
example:
#Override
public void onBindViewHolder(ContactViewHolder holder, int position) {
Contact CON = contacts.get(position);
holder.person_name.setText(CON.getName());
holder.person_email.setText(CON.getEmail());
holder.card_view.setOnClickListener(this)
}
UPDATED ViewHolder
public static class ContactViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView person_name, person_email;
CardView card_view;
ArrayList<Contact> contacts = new ArrayList<Contact>();
Context ctx;
public ContactViewHolder(View view, Context ctx, ArrayList<Contact> contacts) {
super(view);
this.contacts = contacts;
this.ctx = ctx;
card_view = (CardView) view.findViewById(R.id.card_view);
person_name = (TextView) view.findViewById(R.id.person_name);
person_email = (TextView) view.findViewById(R.id.person_email);
}
EDIT
Since your parent layout is CardView you can directly set listener without initiating
Example
public ContactViewHolder(View view, Context ctx, ArrayList<Contact> contacts) {
super(view);
view.setOnClickListener(this);
this.contacts = contacts;
this.ctx = ctx;
person_name = (TextView) view.findViewById(R.id.person_name);
person_email = (TextView) view.findViewById(R.id.person_email);
}
make sure you use the foreground and cardBackgroundColor of your card view
<android.support.v7.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
app:cardBackgroundColor="#color/blue">
this must seem weird but works, cause without that the cardview is not triggering the OnClickEvent.
I have test and only with the app:cardBackgroundColor="#color/blue" works!!!
Instead of implementing OnClickListener() in ContactViewHolder class (your private static class inside adapter), implement it inside onBindViewHolder() method.
Check this code.
#Override
public ContactViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.contact_list_layout, parent, false);
ContactViewHolder contactViewHolder = new ContactViewHolder(view);
return contactViewHolder;
}
#Override
public void onBindViewHolder(ContactViewHolder holder, int position) {
Contact CON = contacts.get(position);
holder.person_name.setText(CON.getName());
holder.person_email.setText(CON.getEmail());
holder.card_view.setOnClickListener(new OnClickListener{
#Override
public void onClick(View v) {
// your click code here
}
});
}
#Override
public int getItemCount() {
return contacts.size();
}
public static class ContactViewHolder extends RecyclerView.ViewHolder {
TextView person_name, person_email;
CardView card_view;
public ContactViewHolder(View view) {
super(view);
person_name = (TextView) view.findViewById(R.id.person_name);
person_email = (TextView) view.findViewById(R.id.person_email);
card_view=(CardView) view.findViewById(R.id.card_view);
}
}
I looked up for the possible solutions but I could not figure out how to apply them in my case.
I am using a RecyclerView to display several CardViews inside it. Initially all cards have white background and I want to change the background color when a card is touched. Each CardView displays a name and an id as described in 'MyCards' class :
public class MyCards {
private String sName;
private int sId;
private boolean sPresent;
public String getName() {
return this.sName;
}
public MyCards(String sName, int sId, boolean sPresent) {
this.sName = sName;
this.sId = sId;
this.sPresent = sPresent;
}
public void setName(String t) {
this.sName = t;
}
public int getId() {
return sId;
}
public void setId(int id) {
this.sId = id;
}
public boolean isPresent() {
return sPresent;
}
public void setPresent(boolean present) {
this.sPresent = present;
}
}
I am making an ArrayList of these MyCards object in the 'Roster' class :
public class Roster extends ActionBarActivity{
private static final int READ_REQUEST_CODE = 42;
private static final String TAG = null;
private RecyclerView rObject;
private MyAdapter adapter;
String abc = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.roster_recycle);
rObject = (RecyclerView)findViewById(R.id.recycler_view);
LinearLayoutManager llm = new LinearLayoutManager(this);
llm.setOrientation(LinearLayoutManager.VERTICAL);
rObject.setLayoutManager(llm);
MyCards c1 = new MyCards("Abhinav", 123, true);
MyCards c2 = new MyCards("Abhishek", 13, false);
performFileSearch();
c1.setName("Abhinav");
c2.setName("Baba");
List<MyCards> cardList = new ArrayList<MyCards>();
cardList.add(c1);
cardList.add(c2);
adapter = new MyAdapter(Roster.this,cardList);
rObject.setAdapter(adapter);
}
The CardView is defined in the item_layout.xml file :
<android.support.v7.widget.CardView
android:id="#+id/card_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"
card_view:cardCornerRadius="4dp" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/sName"
android:layout_width="match_parent"
android:layout_height="20dp"
android:gravity="center_vertical"
android:text="contact det"
android:textSize="14dp" />
<TextView
android:id="#+id/sId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/sName"
android:layout_marginLeft="5dp"
android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:text="Name"
android:textSize="10dp" />
<TextView
android:id="#+id/sPresent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/sId"
android:layout_marginLeft="5dp"
android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:text="Present"
android:textSize="10dp" />
</RelativeLayout>
</android.support.v7.widget.CardView>
My question is : If I click on a card displaying data for 'c1' object then how can I identify that it was from 'c1' and not 'c2'. How do I use click handler in such cases where we display multiple cards?
I'm sorry if my question is too basic but I'm really stuck at it.
Thank you so much for your responses, they really helped. Finally I found a video on YouTube which explained the concept in a nice manner. I am posting the link so that others can also benefit if they get stuck. Here is the video -
see this :- https://www.youtube.com/watch?v=zE1E1HOK_E4
Take a look at this answer for using an onItemClickListener with a RecyclerView.
public class MyAdapter extends RecyclerView.Adapter {
Context mContext;
ArrayList<MyCard> mData;
public MyAdapter(Context context , ArrayList<MyCard> data ) {
mContext = context;
mData = data;
}
public class ViewHolder extends RecyclerView.ViewHolder{
private TextView sName, sId , sPresent;
public ViewHolder(View itemView) {
super(itemView);
sName = (TextView) itemView.findViewById(R.id.sName);
sId = (TextView) itemView.findViewById(R.id.sId);
sPresent = (TextView) itemView.findViewById(R.id.sPresent);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// your logic
}
});
}
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout , parent , false);
ViewHolder vh = new ViewHolder(v);
return vh;
}
#Override
public int getItemCount() {
return mData.size();
}
#Override
public void onBindViewHolder(ViewHolder holder, final int position) {
final MyCard card = mData.get(position);
holder.sName.setText(card.getName().toString());
holder.sId.setText(card.getId().toString());
holder.sPresent.setText(card.getPresent().toString());
}
}