Reputation: 3105
I want to use different layouts based on card position on screen. For example I need that first card (position 0 uses layout first_card.xml
) and other cards should use other_cards.xml
layout and it should be positioned horizontally (see picture below (picture taken from official google site)).
Here's my code
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder>{
private List<CardData> mItems;
private Context context;
private SendInfoToCards cardDatas;
private boolean mainMenu;
private static final int FIRST = 1;
private static final int SECOND = 2;
public CardAdapter(Context c, SendInfoToCards datas, boolean main) {
super();
this.context = c;
this.cardDatas = datas;
mItems = datas.getList();
this.mainMenu = main;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) {
if(!mainMenu) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recycler_view_card_item, viewGroup, false);
ViewHolder viewHolder = new ViewHolder(v);
v.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TextView city = (TextView) v.findViewById(R.id.tv_movie);
String fragmentSwitcher = city.getText().toString();
if (fragmentSwitcher.equals("Zemelapis")) {
switchFragments(0);
} else {
switchFragments(1);
}
}
});
return viewHolder;
} else {
View v;
if(position == 0){
v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.first_layout, viewGroup, false);
}else{
v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.second_layout, viewGroup, false);
}
ViewHolder viewHolder = new ViewHolder(v);
v.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TextView city = (TextView) v.findViewById(R.id.tv_movie);
String fragmentSwitcher = city.getText().toString();
}
});
return viewHolder;
}
}
private void switchFragments(int nr){
if(nr == 0){
Log.d("TAG", "mapo");
} else {
Intent intent = new Intent(context, DetailTourActivity.class);
context.startActivity(intent);
}
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
if(i != 0){
} else {
CardData data = mItems.get(i);
viewHolder.tvMovie.setText(data.getName());
viewHolder.imgThumbnail.setImageResource(data.getThumbnail());
}
}
@Override
public int getItemCount() {
return mItems.size();
}
class ViewHolder extends RecyclerView.ViewHolder{
public ImageView imgThumbnail;
public TextView tvMovie;
public ViewHolder(View itemView) {
super(itemView);
imgThumbnail = (ImageView)itemView.findViewById(R.id.img_thumbnail);
tvMovie = (TextView)itemView.findViewById(R.id.tv_movie);
}
}
}
Sadly but onCreateViewHolder
method second argument position
is always 0. Why is that? How to fix it?
Upvotes: 1
Views: 396
Reputation: 3140
Here is what your adapter class should roughly look like
public class CardAdapter extends RecyclerView.Adapter<RecylerView.ViewHolder>{
private List<CardData> mItems;
private Context context;
private SendInfoToCards cardDatas;
private boolean mainMenu;
private static final int FIRST = 1;
private static final int SECOND = 2;
public CardAdapter(Context c, SendInfoToCards datas, boolean main) {
super();
this.context = c;
this.cardDatas = datas;
mItems = datas.getList();
this.mainMenu = main;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int type) {
if(type == SECOND){
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.second_layout, viewGroup, false);
return new SecondViewViewHolder(v);
} else {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.first_layout, viewGroup, false);
return new FirstViewViewHolder(v);
}
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
if(viewHolder instanceof SecondViewViewHolder){
SecondViewViewHolder secondViewViewHolder = (SecondViewViewHolder) viewHolder;
// bind second views
secondViewViewHolder.imgThumbnail.setImageResource(R.id.img_resource);
} else {
FirstViewViewHolder firstViewViewHolder = (FirstViewViewHolder) viewHolder;
// bind firs view
firstViewViewHolder.imgThumbnail.setImageResource(R.id.img_resource);
}
}
@Override
public int getItemViewType(int position) {
if (position == 0) {
return FIRST;
} else {
return SECOND;
}
}
@Override
public int getItemCount() {
return mItems.size();
}
class FirstViewViewHolder extends RecyclerView.ViewHolder{
public ImageView imgThumbnail;
public TextView tvMovie;
public FirstViewViewHolder(View itemView) {
super(itemView);
imgThumbnail = (ImageView)itemView.findViewById(R.id.img_thumbnail);
tvMovie = (TextView)itemView.findViewById(R.id.tv_movie);
}
}
class SecondViewViewHolder extends RecyclerView.ViewHolder{
public ImageView imgThumbnail;
public TextView tvMovie;
public ImageView imgThumbnail2;
public TextView tvMovie2;
public SecondViewViewHolder(View itemView) {
super(itemView);
//find viewby id
}
}
}
What is changed
Since recyclerview can handle multiple view types you can decide which layout to inflate depending on some condition. You do this by overriding getItemViewTypeMethod() of the RecylerView Adapter
@Override
public int getItemViewType(int position) {
if (position == 0) {
return FIRST;
} else {
return SECOND;
}
}
When creating viewholder. the onCreateViewHolder method will get the view type. Based on the type you should inflate the appropriate layout and return the appropriate viewholder
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int type) {
if(type == SECOND){
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.second_layout, viewGroup, false);
return new SecondViewViewHolder(v);
} else {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.first_layout, viewGroup, false);
return new FirstViewViewHolder(v);
}
}
Since there are two layouts involved, I have created two View Holders to hold first and second layouts. (FirstViewHolder & SecondViewHolder). Because of this you have to set your adapter's ViewHolder type to the base ViewHolder class like this
public class CardAdapter extends RecyclerView.Adapter<RecylerView.ViewHolder>{
...
}
and now in the onBindViewHolder method, you can determine which ViewHolder is currently being bound and do your work accordingly
@Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
if(viewHolder instanceof SecondViewViewHolder){
SecondViewViewHolder secondViewViewHolder = (SecondViewViewHolder) viewHolder;
// bind second views
secondViewViewHolder.imgThumbnail.setImageResource(R.id.img_resource);
} else {
FirstViewViewHolder firstViewViewHolder = (FirstViewViewHolder) viewHolder;
// bind firs view
firstViewViewHolder.imgThumbnail.setImageResource(R.id.img_resource);
}
}
Check this for an example
Upvotes: 2
Reputation: 647
The thing is that the second parameter is not position, it is viewType
.
From the docs:
public abstract VH onCreateViewHolder (ViewGroup parent, int viewType)
Look at public void onBindViewHolder (VH holder, int position, List<Object> payloads)
, this is what you actually need
Upvotes: 1