I have an Adapter that I pass to RecyclerView. When trying to change the text in the Recycler view, an error occurs android.content.res.Resources$NotFoundException: String resource ID #0xde. After debagging, I saw that an error occurs in the onBindViewHolder method when I change the text. At the same time, the holder object is initialized and access to the input fields is available. Please help, I'm a beginner. Thanks!
Adapter class
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
public class ListAdapter extends RecyclerView.Adapter<ListAdapter.ViewHolder> {
private final ArrayList<Income> incomes;
ListAdapter(ArrayList<Income> incomes) {
this.incomes = incomes;
}
#NonNull
#Override
public ListAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ListAdapter.ViewHolder holder, int position) {
Income income = incomes.get(position);
holder.summaView.setText(income.getSumma());
holder.typeView.setText(income.getType());
holder.dataView.setText(income.getData());
}
#Override
public int getItemCount() {
return incomes.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
public TextView typeView, dataView, summaView;
ViewHolder(View view){
super(view);
summaView = view.findViewById(R.id.SumListItem);
typeView = view.findViewById(R.id.TypeListItem);
dataView = view.findViewById(R.id.DateListItem);
}
}
}
Initialize recyclerview
#Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState
) {
View view = inflater.inflate(R.layout.fragment_incomes_list, container, false);
RecyclerView = recyclerView = view.findViewById(R.id.list_INC);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(view.getContext()));
recyclerView.setAdapter(new ListAdapter(incomes));
return view;
}
Error:
enter image description here
enter image description here
note that TextView have multiple setText method implementation, e.g.
setText(CharSequence) - may takeString and will show it
setText(int) - takes an int and will treat it like resource id (strings.xml pointer)
when you call setText(someIntValue) then TextView will try to resolve such number as a resources refence, which most probably doesn't exists (thus Resources$NotFoundException)
so you have to convert by own your int to String, by e.g. ""+someIntValue or String.valueOf(someIntValue)
String summaAsString = ""+income.getSumma();
holder.summaView.setText(summaAsString);
PS. don't EVER post text as screenshot/picture, it's hard to copy it...
Related
I currently have a recycler view that works off Latitude and Longitude within Android studio. On load due to using an emulator i pass a default location, this loads areas around the location within a map. I also have a spinner which allows you to change area and display markers on a map on screen. However the problem is when the Location which in my case is the current location (set to default emulator location Google Pixel San Francisco?) is used, the recycler view shows as empty, i want to edit my recycler view within my Adapter class so that IF the view is empty set the text to "No places around you" if code needed please ask.
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
QuietPlace quietPlace = mQuietPlace.get(position);
if (mQuietPlace.size() > 0){
TextView textView = holder.titleTextView;
textView.setText(quietPlace.getName());
TextView textView2 = holder.noiseTextView;
textView2.setText(quietPlace.getNoise());
TextView textView3 = holder.distanceTextView;
textView3.setText(String.valueOf(quietPlace.getDistance()));
}
else {
TextView textViewEmpty = holder.titleTextView;
textViewEmpty.setText("No Quiet Places near your location");
TextView textViewEmpty2 = holder.noiseTextView;
textViewEmpty2.setText(" ");
TextView textViewEmpty3 = holder.distanceTextView;
textViewEmpty3.setText(" ");
}
}
Edit:
package com.example.myapplication;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
public class QuietPlaceAdapter extends RecyclerView.Adapter<QuietPlaceAdapter.ViewHolder> {
private List<QuietPlace> mQuietPlace;
public QuietPlaceAdapter(List<QuietPlace> quietPlaces)
{
mQuietPlace = quietPlaces;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View quietPlaceView = inflater.inflate(R.layout.recycler_view, parent, false);
ViewHolder viewHolder = new ViewHolder(quietPlaceView);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
QuietPlace quietPlace = mQuietPlace.get(position);
TextView textView = holder.titleTextView;
textView.setText(quietPlace.getName());
TextView textView2 = holder.noiseTextView;
textView2.setText(quietPlace.getNoise());
TextView textView3 = holder.distanceTextView;
textView3.setText(String.valueOf(quietPlace.getDistance()));
}
#Override
public int getItemCount() {
return mQuietPlace.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView titleTextView;
public TextView noiseTextView;
public TextView distanceTextView;
public ViewHolder(View itemView) {
super(itemView);
titleTextView = (TextView) itemView.findViewById(R.id.quietPlaceTitle);
noiseTextView = (TextView) itemView.findViewById(R.id.quietPlaceNoise);
distanceTextView = (TextView) itemView.findViewById(R.id.quietPlaceDistance);
}
}
}
Don't pass the list in constructor if it is dynamic.
Add this function in your adapter
public void setPanelList(List<QuietPlace> quietPlaces){
mQuietPlace = quietPlaces;
notifyDataSetChanged();
}
In activity, setPanelList(quietPlaces) when your quietPlaces changed.
quietPlaceAdapter.setPanelList(quietPlaces)
Hope this helps.
I am having a problem with my GridView wherein the images loads in different places when scrolling. I know this has something to do with recycling but as I am new to Android, I have no idea about this.
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
final Listing listing = getItem(position);
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.listing_items, parent, false);
}
final ImageView imageView = (ImageView) convertView.findViewById(R.id.imageView);
FirebaseStorage.getInstance().getReference().child(listing.authorUid).child(listing.adId).child(listing.images.get(0)).getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
try {
GlideApp.with(getContext())
.load(new URL(uri.toString()))
.into(imageView);
} catch(Exception e) {
e.printStackTrace();
}
}
});
imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getContext(), ItemInfoActivity.class);
intent.putExtra("title", listing.title);
intent.putExtra("location", listing.city);
intent.putExtra("price", listing.price);
intent.putExtra("desc", listing.description);
intent.putExtra("category", listing.category);
intent.putExtra("author", listing.authorUid);
intent.putExtra("adId", listing.adId);
intent.putExtra("authorId", listing.authorUid);
startActivity(intent);
}
});
TextView price = (TextView)convertView.findViewById(R.id.price_txt);
TextView title = (TextView)convertView.findViewById(R.id.title_txt);
title.setText(listing.title);
price.setText(listing.price +"DH");
return convertView;
}
Please advise on what to do.
import android.content.Context;
import android.content.Intent;
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 CustomAdapter extends RecyclerView.Adapter {
ArrayList personNames;
ArrayList personImages;
Context context;
public CustomAdapter(Context context, ArrayList personNames, ArrayList personImages) {
this.context = context;
this.personNames = personNames;
this.personImages = personImages;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// infalte the item Layout
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.rowlayout, parent, false);
// set the view's size, margins, paddings and layout parameters
MyViewHolder vh = new MyViewHolder(v); // pass the view to View Holder
return vh;
}
#Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
// set the data in items
holder.name.setText(personNames.get(position));
holder.image.setImageResource(personImages.get(position));
// implement setOnClickListener event on item view.
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// open another activity on item click
Intent intent = new Intent(context, SecondActivity.class);
intent.putExtra("image", personImages.get(position)); // put image data in Intent
context.startActivity(intent); // start Intent
}
});
}
#Override
public int getItemCount() {
return personNames.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
// init the item view's
TextView name;
ImageView image;
public MyViewHolder(View itemView) {
super(itemView);
// get the reference of item view's
name = (TextView) itemView.findViewById(R.id.name);
image = (ImageView) itemView.findViewById(R.id.image);
}
}
}
Use this adapter structure.
import android.content.Context;
import android.content.Intent;
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 CustomAdapter extends RecyclerView.Adapter {
ArrayList personNames;
ArrayList personImages;
Context context;
public CustomAdapter(Context context, ArrayList personNames, ArrayList personImages) {
this.context = context;
this.personNames = personNames;
this.personImages = personImages;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// infalte the item Layout
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.rowlayout, parent, false);
// set the view's size, margins, paddings and layout parameters
MyViewHolder vh = new MyViewHolder(v); // pass the view to View Holder
return vh;
}
#Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
// set the data in items
holder.name.setText(personNames.get(position));
holder.image.setImageResource(personImages.get(position));
// add your firebase code here
// implement setOnClickListener event on item view.
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// open another activity on item click
Intent intent = new Intent(context, SecondActivity.class);
intent.putExtra("image", personImages.get(position)); // put image data in Intent
context.startActivity(intent); // start Intent
}
});
}
#Override
public int getItemCount() {
return personNames.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
// init the item view's
TextView name;
ImageView image;
public MyViewHolder(View itemView) {
super(itemView);
// get the reference of item view's
name = (TextView) itemView.findViewById(R.id.name);
image = (ImageView) itemView.findViewById(R.id.image);
}
}
}
Here is the updated answer of above answer.
if you are using recyclerview you can not override getView() method.
i would suggest you to use recyclerview.
Can someone please tell what's the error in that specific line.
Here is the error message showing.
package com.example.souravkumar.sqaurewallpapers;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.firebase.ui.database.FirebaseRecyclerAdapter;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.squareup.picasso.Picasso;
/**
* Created by Sourav Kumar on 11/3/2017.
*/
public class popular extends AppCompatActivity {
private RecyclerView recyclerView;
private DatabaseReference myRef;
#Override
public void onCreate(#Nullable Bundle savedInstanceState, #Nullable PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
myRef = FirebaseDatabase.getInstance().getReference();
FirebaseRecyclerAdapter<image_details, BlogViewHolder> adapter = new FirebaseRecyclerAdapter<image_details, BlogViewHolder>(
image_details.class,
R.layout.individual_row,
myRef) {
#Override
protected void onBindViewHolder(BlogViewHolder holder, int position, image_details model) {
holder.setDate(model.getDate());
holder.setUrl(model.getUrl());
}
#Override
public BlogViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return null;
}
};
recyclerView.setAdapter(adapter);
}
public static class BlogViewHolder extends RecyclerView.ViewHolder {
TextView textView;
ImageView imageView;
public BlogViewHolder(View itemView) {
super(itemView);
textView = (TextView)itemView.findViewById(R.id.date);
imageView = (ImageView)itemView.findViewById(R.id.imageView);
}
public void setDate(Long date) {
textView.setText(date.toString());
}
public void setUrl(String url) {
Picasso.with(itemView.getContext())
.load(url)
.resize(50, 50)
.centerCrop()
.into(imageView);
}
}
}
Link to the whole code
The latest version (3.x) of FirebaseUI implements a different method of initializing a FirebaseRecyclerAdapter than previous versions. From the using the FirebaseRecyclerAdapter documentation:
First, configure the adapter by building FirebaseRecyclerOptions. In
this case we will continue with our chat example:
FirebaseRecyclerOptions<Chat> options =
new FirebaseRecyclerOptions.Builder<Chat>()
.setQuery(query, Chat.class)
.build();
Next create the FirebaseRecyclerAdapter object. You should already
have a ViewHolder subclass for displaying each item.
So, for your example, you'll need to do something similar to:
FirebaseRecyclerOptions<image_details> options =
new FirebaseRecyclerOptions.Builder<image_details>()
.setQuery(myRef, image_details.class)
.build();
FirebaseRecyclerAdapter adapter = new FirebaseRecyclerAdapter<image_details, BlogViewHolder>(options) {
#Override
public BlogViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.individual_row, parent, false);
return new BlogViewHolder(view);
}
#Override
protected void onBindViewHolder(BlogViewHolder holder, int position, image_details model) {
// Bind the image_details object to the BlogViewHolder
// ...
}
};
Finally, the FirebaseRecyclerAdapter uses an event listener to monitor changes to the Firebase query. To begin listening for data, call adapter.startListening() and adapter.stopListening() to stop the listener. It's recommended to call these in onStart() and onStop() respectively. Further details on this are available in the FirebaseRecyclerAdapter lifecycle documentation.
You missed a method to start the activity.
Add this in onStart() method:
firebaseRecyclerAdapter.startListening();
Hello your error is due to a missing argument in these () that are found beside this
<image_details, BlogViewHolder>
so you missed one more argument of your BlogViewHolder class so I will add the piece of code and refer your missing argument by a comment in this :
FirebaseRecyclerAdapter<image_details, BlogViewHolder> adapter = new FirebaseRecyclerAdapter<image_details, BlogViewHolder>(
image_details.class,
R.layout.individual_row,
BlogViewHolder.class //see this is missing so you should add it
myRef) {
This is the right way :
FirebaseRecyclerOptions<image_details> options =
new FirebaseRecyclerOptions.Builder<image_details>()
.setQuery(myRef, image_details.class)
.build();
FirebaseRecyclerAdapter adapter = new FirebaseRecyclerAdapter<image_details, BlogViewHolder>(options) {
#Override
public BlogViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.individual_row, parent, false);
return new BlogViewHolder(view);
}
#Override
protected void onBindViewHolder(BlogViewHolder holder, int position, image_details model) {
// Bind the image_details object to the BlogViewHolder
// ...
}
};
I had the same error and this worked very well for me. Hope it helps someone
//loads data into recycler view onstart up
#Override
protected void onStart() {
super.onStart();
FirebaseRecyclerOptions<Data> options =
new FirebaseRecyclerOptions.Builder<Data>()
.setQuery(dbReference, Data.class)
.build();
FirebaseRecyclerAdapter firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Data, DataViewHolder>(options) {
#Override
public DataViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.row, parent, false);
return new DataViewHolder(view);
}
#Override
protected void onBindViewHolder(#NonNull DataViewHolder holder, int position, #NonNull Data model) {
// Bind the image_details object to the BlogViewHolder
// ...
holder.setDetails(getApplicationContext(), model.getName(), model.getDepartment(), model.getDescription());
}
};
firebaseRecyclerAdapter.startListening();
recyclerView.setAdapter(firebaseRecyclerAdapter);
}
I am working on an app
I have implemented a working recycler view that receives a jsonarray, passes the data to a string array.
I now want to add section headers to the layout manager.
I have read two schools of thought on this:
- Change the spansize of the view to match the total columns of the grid
- create a custom adapter that loads a different view if the item is a section header.
Im not sure which way to go with this and its starting to confuse me
I have a list of data in an array which includes both headers and grid data (myDataset), i have also created another array with the mapping for the dataset in (myDatamap). In myDatamap i have a list of field types (1 for header and 0 for griddata. I was hoping to pass both arrays to the adaptor and for it decide if its a header or a griditem and then load the appropriate view.
I am leaning more towards loading a different view for the header items, allowing for me to customise the layout of the header easier.
Here is my adaptor code
package com.example.alex.recyclerview2;
import java.util.ArrayList;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private ArrayList<String> mDataset;
private ArrayList<Integer> mDatamap;
private Context context;
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView txtHeader;
public TextView txtFooter;
public ImageView imgImage;
public ViewHolder(View v) {
super(v);
txtHeader = (TextView) v.findViewById(R.id.firstLine);
txtFooter = (TextView) v.findViewById(R.id.secondLine);
imgImage = (ImageView) v.findViewById(R.id.icon);
}
}
public void add(int position, String item) {
mDataset.add(position, item);
notifyItemInserted(position);
}
public void remove(String item) {
int position = mDataset.indexOf(item);
mDataset.remove(position);
notifyItemRemoved(position);
}
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(ArrayList<String> myDataset, ArrayList<Integer> myDatamap) {mDataset = myDataset;myDatamap=mDatamap; }
// Create new views (invoked by the layout manager)
#Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.sub_layout, parent, false);
context = v.getContext();
// set the view's size, margins, paddings and layout parameters
ViewHolder vh = new ViewHolder(v);
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
final String name = mDataset.get(position);
Picasso.with(context).load("http://www.500kgiveaway.co.uk/" + name).resize(200,200).into(holder.imgImage);
// holder.txtHeader.setText(mDataset.get(position));
holder.txtHeader.setText(name);
holder.txtHeader.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
remove(name);
}
});
holder.txtFooter.setText("Footer: " + mDataset.get(position));
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return mDataset.size();
}
}
ive not had much interest in this post but here is the answer
i hope this help someone else
What i have done is implemented a custom view adaptor to manage the item types
import android.content.Context;
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 com.squareup.picasso.Picasso;
import java.util.ArrayList;
public class ElementsAdapter extends RecyclerView.Adapter<ElementsAdapter.ViewHolder> {
private ArrayList<String> mDataset;
private ArrayList<Integer> mDatamap;
public Context context;
private static final int VIEW_HEADER = 0;
private static final int VIEW_NORMAL = 1;
private View headerView;
private int datasetSize;
public class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView txtHeader;
public TextView txtFooter;
public ImageView imgImage;
//header
public TextView headertext;
public ViewHolder(View v, int viewType) {
super(v);
switch (viewType){
case 1:
txtHeader = (TextView) v.findViewById(R.id.firstLine);
txtFooter = (TextView) v.findViewById(R.id.secondLine);
imgImage = (ImageView) v.findViewById(R.id.icon);
case 0:
headertext = (TextView) v.findViewById(R.id.headertext);
}
}
}
public ElementsAdapter(ArrayList<String> myDataset, ArrayList<Integer> myDatamap) {
mDataset = myDataset;
mDatamap = myDatamap;
}
#Override
public int getItemViewType(int position) {
return isHeader(position) == 1 ? VIEW_HEADER : VIEW_NORMAL;
}
#Override
public int getItemCount() {
return mDataset.size();
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_HEADER) {
// create a new view
View sub_view = LayoutInflater.from(parent.getContext()).inflate(R.layout.header, parent, false);
Context context = sub_view.getContext();
// set the view's size, margins, paddings and layout parameters
ViewHolder vh = new ViewHolder(sub_view,viewType);
return vh;
// return new HeaderViewHolder(headerView);
} else {
// create a new view
View sub_view = LayoutInflater.from(parent.getContext()).inflate(R.layout.sub_layout, parent, false);
context = sub_view.getContext();
// set the view's size, margins, paddings and layout parameters
ViewHolder vh = new ViewHolder(sub_view, viewType);
return vh;
}
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
if (isHeader(position) == 1) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
final String name = mDataset.get(position);
// holder.txtHeader.setText(mDataset.get(position));
viewHolder.headertext.setText(name);
} else {
// - get element from your dataset at this position
// - replace the contents of the view with that element
final String name = mDataset.get(position);
Picasso.with(context).load("http://www.500kgiveaway.co.uk/"+name).resize(200,200).into(viewHolder.imgImage);
// holder.txtHeader.setText(mDataset.get(position));
viewHolder.txtHeader.setText(name);
viewHolder.txtHeader.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick (View v){
//remove(name);
}
}
);
viewHolder.txtFooter.setText("Footer: "+mDataset.get(position));
}
//ViewHolder holder = (ViewHolder) viewHolder;
//holder.textView.setText("Position " + (position - 1));
}
public int isHeader(int position) {
return mDatamap.get(position) ==1 ? 1:0;}
}
Why don't you use both solutions? If you set the span size you can easily set a textview or whatever you want the header to be.
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
return adapter.isHeader(position) ? gridLayoutManager.getSpanCount() : 1;
}
});
Then in the adapter have a general class Item that says if the item is a header and has some information about the real item that should be shown, in my case since I have image paths for showing images and titles for headers I just use a attribute text but you can use something like int realPositionInTheirLists since headers titles and images paths are in two separate lists:
private static class Item {
public boolean isHeader;
public String text;
public Item(String text, boolean isHeader) {
this.isHeader = isHeader;
this.text = text;
}
}
Then you have something like this on the methods that tell which type of item it is:
#Override
public int getItemViewType(int position) {
return mItems.get(position).isHeader ? VIEW_TYPE_HEADER : VIEW_TYPE_CONTENT;
}
public boolean isHeader(int position) {
return mItems.get(position).isHeader;
}
Then finally on the two methods that inflate the view and bind the data you inflate the view that you want depending on whether it is a header or not and bind the data using the Item class:
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
if (viewType == VIEW_TYPE_HEADER) {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.grid_header, parent, false);
} else {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.grid_item, parent, false);
}
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
final Item item = mItems.get(position);
holder.bindItem(item, position);
}
Being the holder.bindItem a method of the ViewHolder class. There you can choose however you want to separate both views.
i want to use Customizing Android ListView Rows by Subclassing in my application but after wending that way i get an error to Import correct class for Item & ItemView my app support old version of android and i'm using android.support for any class.
Notify for import Item:
Notify for import ItemView:
introducing class for inport not correct and i get an error such as setItem.
How to resolve this problem and can be import correct class?
ItemAdapter class:
import java.util.List;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import ir.tsms.wsdl.ReceiveFields;
public class ItemAdapter extends ArrayAdapter<ReceiveFields> {
public ItemAdapter(Context c, List<ReceiveFields> items) {
super(c, 0, items);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ItemView itemView = (ItemView)convertView;
if (null == itemView)
itemView = ItemView.inflate(parent);
itemView.setItem(getItem(position));
return itemView;
}
}
Fragment:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ArrayList<ReceiveFields> items = new ArrayList<ReceiveFields>();
for (int i = 0; i < 100; i++) {
String url = String.format("http://www.google.com/image/%d.png", i);
String title = String.format("Item %d", i);
String description = String.format("Description of Item %d", i);
Item item = new Item(url, title, description);
items.add(item);
}
setListAdapter(new ItemAdapter(getActivity(), items));
return super.onCreateView(inflater, container, savedInstanceState);
}
As Mike M says you should be defining the Item and ItemView classes rather then trying to import them. Hence, and this is from your link, you should have two classes. ItemView looks kind of like:
public class ItemView extends RelativeLayout {
private TextView mTitleTextView;
private TextView mDescriptionTextView;
private ImageView mImageView;
public ItemView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
LayoutInflater.from(context).inflate(R.layout.item_view_children, this, true);
setupChildren();
}
public static ItemView inflate(ViewGroup parent) {
ItemView itemView = (ItemView)LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_view, parent, false);
return itemView
}
private void setupChildren() {
mTitleTextView = (TextView) findViewById(R.id.item_titleTextView);
mDescriptionTextView = (TextView) findViewById(R.id.item_descriptionTextView);
mImageView = (ImageView) findViewById(R.id.item_imageView);
}
public void setItem(Item item) {
mTitleTextView.setText(item.getTitle());
mDescriptionTextView.setText(item.getDescription());
// TODO: set up image URL
}
}
And then you would also need an Item class and to set up your layout files. I hope this helps.
The sample code for the tutorial is on github. Here are the key classes I used:
https://github.com/bignerdranch/android-listview-custom-view/tree/master/ListItemViewDemo/src/com/bignerdranch/android/listitemviewdemo
"Item" and "ItemView" are just the names I chose; you might want to use something more specific to your application's domain.
Glad you like the pattern!