I created my own adapter that extend BaseAdapter and I use it for GridView. I want to get the number of element and put it into TextView. I did it in my adapter:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View gridView;
if(convertView == null){
gridView = new View(context);
gridView = inflater.inflate(R.layout.grid_element, null);
ImageView logo = (ImageView) gridView.findViewById(R.id.grid_logo);
TextView tv = (TextView) gridView.findViewById(R.id.grid_textView1);
tv.setText(level+position);
}
else
gridView = convertView;
return gridView;
}
It seems to be good until I get elements that are not in the screen in launch:
The position is like reseted.
How can I do it properly?
You were not setting the TextView properly when convertView was not null. Try this:
if (convertView == null) {
gridView = inflater.inflate(R.layout.grid_element, null);
} else {
gridView = convertView;
}
ImageView logo = (ImageView) gridView.findViewById(R.id.grid_logo);
TextView tv = (TextView) gridView.findViewById(R.id.grid_textView1);
tv.setText(level + position);
May help new Visitors.
You have to know two main things :
You need to check if convertView is null, in order to know if that row in your list is not created yet (convertView = null) or is being recycled by the adapter (convertView != null). This is called the Recycling process.
Another important thing to know is the View Holder Pattern. Calling findViewById() on each row of getView() method is to heavy for list populating and slows down scrolling performance. To avoid that, create a static class with some views as class fields. Than use findViewById() if the view is being created (convertView == null), and get it back from getTag() method when it's being recycled
`
static class ViewHolder {
TextView text;
ImageView icon;
}
ViewHolder holder;
if(convertView == null) {
convertView = inflater.inflate(resource, root);
holder = new ViewHolder();
holder.icon = (ImageView) convertView.findViewById(R.id.listitem_image);
holder.text = (TextView) convertView.findViewById(R.id.listitem_text);
holder.timestamp = (TextView) convertView.findViewById(R.id.listitem_timestamp);
holder.progress = (ProgressBar) convertView.findViewById(R.id.progress_spinner);
convertView.setTag(holder);
}
holder = (ViewHolder) convertView.getTag();
// Set here your view's content :
holder.text.setText("Sample");
// ...
Related
In ImageView, my images are being shuffled but not the text. This is my getView() method:
public View getView(int position, View convertView, ViewGroup parent) {
View v;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) mainActivity.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
v = inflater.inflate(R.layout.item_people, parent, false);
} else {
v = (View) convertView;
}
TextView textView = (TextView) v.findViewById(R.id.name);
ImageView imageView = (ImageView) v.findViewById(R.id.image);
if (list.get(position).getClass() == SearchData.Video.class) {
SearchData.Video video = (SearchData.Video) list.get(position);
textView.setText(video.getVideoName());
if (video.getCoverPicture().length > 0)
imageView.setBackground(mainActivity.Base64toImage(video.getCoverPicture()[0].getImg()));
} else if (list.get(position).getClass() == SearchData.Actor.class) {
SearchData.Actor actor = (SearchData.Actor) list.get(position);
textView.setText(actor.getFirstName());
if (actor.getPicture().length > 0)
imageView.setBackground(mainActivity.Base64toImage(actor.getPicture()[0].getImg()));
}
return v;
}
I am setting image and text of actors. When I scroll down then up the images have shuffled, but not text. Why?
Did you tried the same with ViewHolder
Normally when ever getView() method is called, the gridview/ listview will automatically notified as a change, So that is the reason for your image shuffling s / changing in your gridview.
So, try to implement your Gridview with ViewHolder pattern and avoid those shuffling s / re-orderings
here is the sample code for view holder pattern implementation.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolderItem viewHolder;
// The convertView argument is essentially a "ScrapView" as described is Lucas post
// http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/
// It will have a non-null value when ListView is asking you recycle the row layout.
// So, when convertView is not null, you should simply update its contents instead of inflating a new row layout.
if(convertView==null){
// inflate the layout
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
convertView = inflater.inflate(layoutResourceId, parent, false);
// well set up the ViewHolder
viewHolder = new ViewHolderItem();
viewHolder.textViewItem = (TextView) convertView.findViewById(R.id.textViewItem);
// store the holder with the view.
convertView.setTag(viewHolder);
}else{
// we've just avoided calling findViewById() on resource everytime
// just use the viewHolder
viewHolder = (ViewHolderItem) convertView.getTag();
}
// object item based on the position
ObjectItem objectItem = data[position];
// assign values if the object is not null
if(objectItem != null) {
// get the TextView from the ViewHolder and then set the text (item name) and tag (item ID) values
viewHolder.textViewItem.setText(objectItem.itemName);
viewHolder.textViewItem.setTag(objectItem.itemId);
}
return convertView;
}
your ViewHodler should be like this
// ViewHolder.
// caches our TextView
static class ViewHolderItem {
TextView textViewItem;
}
This is not the exactly same to your question, but you can edit the above logic for your way.
Hope it Helps :)
I'm developing an android application which has background photos
so I decided to make my listView or recyclerView transparent to show these backgrounds
every thing works good except on lollipop version!
I want to make the lollipop version like all previous versions like kitkat
here is the code snippet that I use to set the transparency of each item
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder mHolder;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.dairy_item, parent, false);
CardView listItem = (CardView) convertView.findViewById(R.id.dairy_card);
listItem.setCardElevation(5);
listItem.setUseCompatPadding(true);
// listItem.setPadding(0, 0, 5, 6);
listItem.setPreventCornerOverlap(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
Drawable mBackground = listItem.getBackground();
mBackground.setAlpha(127);
listItem.setBackground(mBackground);
} else {
listItem.getBackground().setAlpha(127);
}
mHolder = new ViewHolder();
mHolder.typeIcon = (ImageView) convertView.findViewById(R.id.reminder_icon);
mHolder.title = (TextView) convertView.findViewById(R.id.reminder_identifier);
mHolder.subtitle = (TextView) convertView.findViewById(R.id.reminder_status);
mHolder.time = (TextView) convertView.findViewById(R.id.item_time);
mHolder.order = (TextView) convertView.findViewById(R.id.item_order);
convertView.setTag(mHolder);
} else
mHolder = (ViewHolder) convertView.getTag();
mHolder.typeIcon.setImageResource(imgRec[position]);
mHolder.title.setText(title[position]);
mHolder.subtitle.setText(subtitle[position]);
String orders = String.valueOf(position + 1);
if (SettingsFragment.isArabic(mContext))
orders = Referances.ArabtizeDigits(mContext, orders);
mHolder.order.setText(orders);
mHolder.time.setText(time[position]);
return convertView;
}
from my own listView adapter.
thanks in advance ....
I have an android app where i want to display some messages.The messages are classified into two categories, images and text.Text messages have two types,sent and received.I have created a custom listview adapter to display the messages in a listview.When calling the adapter,i pass an arraylist of 13 objects.Problem is not all the messages in arraylist are displayed.Only the first five messages are displayed.The messages are displayed three times each.When a message item in the listview is clicked,more than one message is highlited.What could be the problem.
Here is the listview adapter:
public class CustomMessageListAdapter extends BaseAdapter {
private ArrayList<?> listData;
private LayoutInflater layoutInflater;
public CustomMessageListAdapter(Context context, ArrayList<?> listData) {
this.listData = listData;
layoutInflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return listData.size();
}
#Override
public Object getItem(int position) {
return listData.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.listview_message,
null);
viewHolder = new ViewHolder();
viewHolder.incoming_message = (RelativeLayout) convertView
.findViewById(R.id.received_layout);
viewHolder.outgoing_message = (RelativeLayout) convertView
.findViewById(R.id.sent_layout);
viewHolder.sent_message = (TextView) convertView
.findViewById(R.id.sent_messages_textView_message);
viewHolder.sent_time = (TextView) convertView
.findViewById(R.id.sent_messages_textview_time);
viewHolder.sent_image = (ImageView) convertView
.findViewById(R.id.sent_image_imageview);
viewHolder.received_image = (ImageView) convertView
.findViewById(R.id.received_image_imageview);
viewHolder.sent_image_layout = (RelativeLayout) convertView
.findViewById(R.id.sent_image_layout);
viewHolder.received_image_layout = (RelativeLayout) convertView
.findViewById(R.id.received_image_layout);
viewHolder.received_message = (TextView) convertView
.findViewById(R.id.messages_textView_message);
viewHolder.received_time = (TextView) convertView
.findViewById(R.id.messages_textview_time);
viewHolder.date = (TextView) convertView
.findViewById(R.id.messages_textView_date);
viewHolder.sent_hepasnap = (RelativeLayout) convertView
.findViewById(R.id.chat_layout_sent_hepasnap);
viewHolder.recieved_hepasnap = (RelativeLayout) convertView
.findViewById(R.id.chat_layout_received_hepasnap);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
MessageItem messageItem = (MessageItem) listData.get(position);
Log.i("msg", "" + position);
if (messageItem.getCategory().equalsIgnoreCase("text")) {
if (messageItem.getType().equalsIgnoreCase("sent")) {
viewHolder.outgoing_message.setVisibility(View.VISIBLE);
viewHolder.sent_message.setText(messageItem.getMessage());
viewHolder.sent_time.setText(messageItem.getTime());
} else {
viewHolder.incoming_message.setVisibility(View.VISIBLE);
viewHolder.received_message.setText(messageItem.getMessage());
viewHolder.received_time.setText(messageItem.getTime());
}
}
return convertView;
}
public class ViewHolder {
TextView sent_message;
TextView sent_time;
TextView received_message;
TextView received_time;
RelativeLayout outgoing_message;
RelativeLayout incoming_message;
RelativeLayout sent_hepasnap;
RelativeLayout recieved_hepasnap;
TextView date;
ImageView sent_image;
ImageView received_image;
RelativeLayout sent_image_layout;
RelativeLayout received_image_layout;
}
}
And when message is clicked:
add viewHolder.incoming_message.setVisibility(View.GONE); to if condition
(messageItem.getType().equalsIgnoreCase("sent"))
and viewHolder.outgoing_message.setVisibility(View.GONE); to else condition.
If your Problem not solved then let me know.
I think the messages are getting displayed multiple times because they carry older values whenever convert view is non-null.
And since your incoming and outgoing messages are both getting filled it is giving the illusion of multiple items getting selected.
So you should change visibility of unused views to View.GONE.
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
if(position == 1 ){
Toast.makeText(getApplicationContext(),
"Click ListItem Number " + position,
Toast.LENGTH_LONG)
.show();
}else{
}
i have a list view from a custom adapter that works fine and when i click an item it gets the correct position.
how can i exract a field views text out of the position. ie
holder.txtDesc = (TextView) convertView.findViewById(R.id.desc);
i want to target the desc field out of the position listem that i clicked..
i know you can use hash mapping but is there a way to just target a field view on item click by its list position? I know this is "webby" but I am sure java has the same flexibility
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
RowItem rowItem = getItem(position);
LayoutInflater mInflater = (LayoutInflater) context
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item, null);
holder = new ViewHolder();
holder.txtDesc = (TextView) convertView.findViewById(R.id.desc);
holder.txtTitle = (TextView) convertView.findViewById(R.id.title);
convertView.setTag(holder);
} else
holder = (ViewHolder) convertView.getTag();
holder.txtDesc.setText(rowItem.getDesc());
holder.txtTitle.setText(rowItem.getTitle());
return convertView;
}
how can i exract a field views text out of the position. ie
holder.txtDesc = (TextView) convertView.findViewById(R.id.desc);
Inside onItemClick() you can use:
TextView textview = (TextView) view.findViewById(R.id.desc);
// Now use textView.getText().toString() to get the description
Since convertView from the Adapter is the same object as view in the Listener.
Can't you just call adapter.getItem(position)?
If you need only text current item use BaseAdapter and you can get text following way:
(String) adapter.getItem(position);
If you need TextView object current item you can get TextView following way:
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
ViewHolder holder = (ViewHolder)view;
TextView txtDescTV = holder.txtDesc;
}
}
I have made my own CustomArrayAdapter to show list of Brazilian Restaurants. I have overidden the GetView method to make my own custom view.
private class MyAdapter extends ArrayAdapter<String> {
public MyAdapter(Context context, int resource, int textViewResourceId,
String[] strings) {
super(context, resource, textViewResourceId, strings);
// TODO Auto-generated constructor stub
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.list_item, parent,false);
String [] items= getResources().getStringArray(R.array.locations_array);
TextView tv= (TextView) row.findViewById(R.id.textView1);
ImageView iv = (ImageView) row.findViewById(R.id.imageView1);
tv.setText(items[position]);
iv.setImageResource(R.drawable.brazil);
return row;
}
}
Currently this new GetView class is pulling in a text string from a resource xml file and putting it into the list item.
If I wanted to incorporate an array of extra data generated within the app, I assume that I don't do the array generating in the GetView class as this will be recreated each time a new row is made.
Where do I put the code to make the array, and how do I call this data into the GetView code above?
It's worth pointing out that for better performance you should be making use of the convertView variable passed into the getView() method.
The use of convertView allows you to re-use list item views instead of creating new ones which has a heavy performance hit. If you have a large data set or value performance in your app, you would do well to check out the documentation for getView()
Your code would then look something more like this:
...
//it's also worth moving these methods to your constructor so they aren't called every time getView() for better performance
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
String [] items= getResources().getStringArray(R.array.locations_array);
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null)
convertView = inflater.inflate(R.layout.list_item, parent, false);
TextView tv= (TextView) convertView.findViewById(R.id.textView1);
ImageView iv = (ImageView) convertView.findViewById(R.id.imageView1);
tv.setText(items[position]);
iv.setImageResource(R.drawable.brazil);
return row;
}
...
Building on #CodeDownZero's answer, I highly recommend you adopt the ViewHolder pattern, and definitely recycle your listviews (using convertview).
...
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(textViewResourceId, parent, false);
final ViewHolder viewHolder = new ViewHolder();
viewHolder.tv1 = (TextView) view.findViewById(R.id.textView1);
viewHolder.tv2 = (TextView) view.findViewById(R.id.textView2);
view.setTag(viewHolder);
} else {
view = convertView;
}
ViewHolder holder = (ViewHolder) view.getTag();
MyDataClass data = this.getItem(position);
holder.tv1.setText(data.street);
holder.tv2.setText(data.name);
return view;
}
...
private class ViewHolder {
private TextView tv1;
private TextView tv2;
}
You can base an ArrayAdapter on a custom class instead of string. Here is an example:
public class MyDataClass {
public String street;
public String name;
}
private class MyAdapter extends ArrayAdapter<MyDataClass> {
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.list_item, parent,false);
TextView tv1= (TextView) row.findViewById(R.id.textView1);
TextView tv2= (TextView) row.findViewById(R.id.textView2);
MyDataClass data = this.getItem(position);
tv1.setText(data.street);
tv2.setText(data.name);
return row;
}
}
To populate the Adapter with data you can use this snippet in the OnCreate method of the Activity:
..
MyAdapter adapter = new MyAdapter();
MyDataClass lData = new MyDataClass(); // here was a mistake
lData.name = "MyName";
lData.street = "MyRoad";
adapter.Add(lData);
..
ListView.Adapter=adapter; // where Listview is the Listview