I'm creating a custom ListView with multiple elements - TextView and ImageView.
Here's a part of my getView method:
#override
public View getView(int position, View convertView, ViewGroup parent) {
View itemView = convertView;
if (itemView == null) {
itemView = getLayoutInflater().inflate(R.layout.individual_items_in_options, parent, false);
}
// Find the option to start with.
Options currentOption = optionsOfAQuestion.get(position);
// option number
TextView optionNumber = (TextView) itemView.findViewById(R.id.option_number);
optionNumber.setText(currentOption.getOptionNumber());
// option content
TextView optionContent = (TextView) itemView.findViewById(R.id.option_content);
optionContent.setText(currentOption.getOptionContent());
ImageView imageView = (ImageView)findViewById(R.id.option_icon);
imageView.setImageResource(R.drawable.icon_wrong);
I'm getting NPE while setting the image resource, though I've defined it in my layout. Why is setting image giving me NPE, while setting the TextViews work completely fine? What's the point I'm missing here?
replace this
ImageView imageView = (ImageView)findViewById(R.id.option_icon);
by this
ImageView imageView = (ImageView)itemView.findViewById(R.id.option_icon);
this will help you
Please Update your code like below
ImageView imageView = (ImageView) itemView .findViewById(R.id.option_icon);
imageView.setImageResource(R.drawable.icon_wrong);
Related
I have a custom layout for a Listview, each row item contains a button that when clicked it shows a small imageview in the item, however the actions i perform in one item, repeats for another item down the list, for example, if i click the button in item 1, the imageview will show up in item 1 and item 10, if i click the button in item 2, the Imageview will show up on item 2 and item 11 and while i scroll it will keep repeating in different items, heres the code for my custom adapter:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
mparent = parent;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.places_item, parent, false);
holder = new ViewHolder();
holder.placeimage = (CircularImageView) convertView.findViewById(R.id.locationimage_pilayout);
holder.addbtn = (TextView) convertView.findViewById(R.id.addbtn_pilayout);
holder.delbtn = (TextView) convertView.findViewById(R.id.delbtn_pilayout);
holder.oribtn = (TextView) convertView.findViewById(R.id.oribtn_pilayout);
holder.placename = (TextView) convertView.findViewById(R.id.locationname_pilayout);
holder.selected = (ImageView) convertView.findViewById(R.id.selected_pilayout);
holder.origin = (ImageView) convertView.findViewById(R.id.origin_pilayout);
holder.swipeLayout = (SwipeRevealLayout) convertView.findViewById(R.id.swipe_pilayout);
holder.mainLayout = (LinearLayout) convertView.findViewById(R.id.main_pilayout);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final Place item = getItem(position);
/*
my code assigning the button click listener and assigning the views
*/
return convertView;
}
Am i missing something? im sure this could be a simple fix, but i havent found it yet. any help would be kindly appreciated.
In ListView the individual views for rows, get reused. For example, let's say the window can show up to 10 rows inside the ListView. Now when you scroll down, the 1st view gets out of the window from the top, and a new 11th view comes into the window from the bottom. In order to save memory and CPU power, Android uses the same 1st view for the 11th view. That's the purpose of convertView and the if (convertView == null) {} else {} code.
So the reason why the image is being shown in the 1st item and also in the 11th item, is that they are exactly one view object. To tackle this issue, in the getView() method, you need to reset every attribute of every view and don't rely on the defaults.
So adding a line like the one below, will get rid of the mentioned problem:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// all your code ...
holder.placeImage.setImageResource(0); //<-- This clears any previously set image.
return convertView;
}
As Adapter for ListView, I am using custom adapter. On Adapter's getView method, I am trying to change listitem's background image using setBackgroundDrawable.
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
CurrencyModel currency = new CurrencyModel();
currency = currencyList.get(position);
if (convertView == null) {
vi = inflater.inflate(R.layout.listitem_currency, null);
}
TextView tvSymbol = (TextView) vi.findViewById(R.id.tvSymbol);
TextView tvSize = (TextView) vi.findViewById(R.id.tvSize);
TextView tvName = (TextView) vi.findViewById(R.id.tvName);
TextView tvRate = (TextView) vi.findViewById(R.id.tvRate);
tvSymbol.setText(currency.getSymbol());
tvSize.setText(currency.getSize());
tvName.setText(currency.getName());
tvRate.setText(currency.getRate());
if (currency.getSymbol().equals("AUD")) {
vi.setBackgroundDrawable(context.getResources().getDrawable(
R.drawable.bg_exch_high_cell));
}
return vi;
}
When activity starts, everything is working correctly - listitem with AUD has different background. All mystery starts when I scroll the listview - other listitems also get "special" background. The more scroll, the more listitems changed. I do not have idea why this is happening. How to solve this problem?
if (currency.getSymbol().equals("AUD")) {
vi.setBackgroundDrawable(context.getResources().getDrawable(
R.drawable.bg_exch_high_cell));
}
else {//restore default background}
This happens because cell views are reused by listview. You should restore default background for other items.
More about list view performance
TextView tvSymbol = (TextView) vi.findViewById(R.id.tvSymbol);
Before this line add the default background the you put to the item. The reason in your code why it happens is that android try using the the already created view(vi). Since if it is assigned bg_exch_high_cell, it will retain it. So reset it in the beginning.
vi.setBackgroundDrawable(context.getResources().getDrawable(
//default background drawable here ));
TextView tvSymbol = (TextView) vi.findViewById(R.id.tvSymbol);
I have a custom row that contains a text view and 3 Clickable Image Views.
onClick on any one of the ImageView this Image changes to another one.
My problem is that when I click on Image1 on row1, the image changed in both row1 and row9 as well, and when I click on row2, the image changed in row2 and row10 as well.. so On. I don't know why.
But I think it it about scrolling.
This is getView() in my Adapter:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
if (vi == null) {
vi = inflater.inflate(R.layout.comprow, null);
}
TextView text = (TextView) vi.findViewById(R.id.name);
text.setText(data.get(position));
return vi;
}
And this is OnClick function for the first ImageView
public void one(View v) {
RelativeLayout row = (RelativeLayout)v.getParent();
ImageView im1 = (ImageView) row.findViewById(R.id.one);
ImageView im2 = (ImageView) row.findViewById(R.id.two);
ImageView im3 = (ImageView)row.findViewById(R.id.three);
im1.setImageResource(R.drawable.c0);
im2.setImageResource(R.drawable.b1);
im3.setImageResource(R.drawable.b2);
simpleAdpt.notifyDataSetChanged();
}
When you don't use of id, your changed repeat in all row because you worked with position,then you must set id to each row that create in getView(), now if you have a few choice, you can handle with array of integer with size of list, that in default is equal 0 then if you press one row the value of row changed, then in show image check the value of this row, if is zero then let in default, else check the value and select image that you want to show, I hope that you understand my word
I have a Grid View adapter where all is in this code:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View v = convertView;
CheckBox check = null;
ImageView pic = null;
if (convertView == null) { // if it's not recycled, initialize some
// attributes
LayoutInflater vi = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.check_box_and_imageview, null);
}
pic = (ImageView)v.findViewById(R.id.imageView);
check = (CheckBox) v.findViewById(R.id.checkBox);
check.setTag(position);
ImageLoader loader = new ImageLoader(mContext);
//this loads image from given url
loader.DisplayImage(url[position], pic);
return v;
}
Here i create a view with check box and image view. There is the problem because image view is different size and gridview make aligment by both size checkbox and image view. But i want to order element by check box.
For better explanation what i want to do will show this pic:
This i want to do. How ever my image views isn't all same size. Now i will illustrate how it looks:
So this don't suite me. I want to make alignment not all checkbox and imageview. But just that check boxes would be under checks boxes.
So isn't this possible to do with gird view ?
Check if the convertView is null:
If it is null it's time to inflate a new View for this GridView's element. You could also use the holder pattern to cache looking for the composing Views(instead of searching with findViewById everytime)(You use the setTag element for the inflated View but it's a piece of data from the Node data element ?!? What do you plan to do with it?!?)
I have an imageButton inside a listview and I want to change its image depending on two cases. In the first case the imagebutton is enabled and has an image. In the second case the imagebutton is disabled and should have a different image.
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
if(convertView==null)
vi = inflater.inflate(R.layout.list_row, null);
TextView title = (TextView)vi.findViewById(R.id.title);
TextView retail_price = (TextView)vi.findViewById(R.id.retail_price);
TextView deal_price = (TextView)vi.findViewById(R.id.deal_price);
TextView duration = (TextView)vi.findViewById(R.id.duration);
ImageView thumb_image=(ImageView)vi.findViewById(R.id.list_image);
ImageButton imgb = (ImageButton)vi.findViewById(R.idIMGB);
HashMap<String, String> otherdeals = new HashMap<String, String>();
otherdeals = data.get(position);
title.setText(otherdeals.get(dealsparsing.TAG_TITLE));
retail_price.setText(otherdeals.get(dealsparsing.TAG_RETAIL));
retail_price.setPaintFlags(retail_price.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
deal_price.setText(otherdeals.get(dealsparsing.TAG_DEAL));
duration.setText(otherdeals.get(dealsparsing.TAG_FINAL_TIME));
Bitmap bitmap = DownloadImage(otherdeals.get(dealsparsing.TAG_IMAGE_URL));
thumb_image.setImageBitmap(bitmap);
return vi;
}
You can implement your case logic for imageButton like this.
if(case1)
{
imgb.setImageResource(R.drawable.enableImage);
}
if(case2)
{
imgb.setImageResource(R.drawable.disableImage);
}
You need to define your own (custom) list adapter (if you haven't). In adapter's getView() method you set your button enabled/disbabled and change the image (depending on your case/condition)
Edit: You edited your code and added your adapter's getView method. Now where is the problem? Check your condition and set the ImageButton to enabled/disabled and change the image