getView showing wrong images in a custom adapter? - android

I have a list with a custom adapter and a custom row.
The problem is that when I scroll the listview, the images are at the wrong positions...
Here is the custom row xml:
<LinearLayout
android:id="#+id/imagequality_listview_row_linearlayout"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:weightSum="1"
android:orientation="horizontal" xmlns:android="http://schemas.android.com/apk/res/android">
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/imagequality_listview_row_textview"
android:layout_width="0dp"
android:layout_height="40dip"
android:gravity="right"
android:paddingLeft="5dip"
android:drawableLeft="?android:attr/listChoiceIndicatorMultiple"
android:layout_weight="0.6"
/>
<com.example.listviewtest.LoaderImageView
android:id="#+id/imagequality_listview_row_loaderImageView"
android:layout_width="0dp"
android:layout_weight="0.4"
android:layout_height="100dp"
image="http://developer.android.com/images/dialog_buttons.png"
/>
</LinearLayout>
Here is the GetView:
List<ImageQuality_Item> items;
Context context;
List<CheckedTextView> checkedList;
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = View.inflate(context, R.layout.imagequality_listview_row, null);
holder = new ViewHolder();
holder.layout = (LinearLayout) convertView.findViewById(R.id.imagequality_listview_row_linearlayout);
holder.textview = (CheckedTextView) convertView.findViewById(R.id.imagequality_listview_row_textview);
holder.image = (LoaderImageView) convertView.findViewById(R.id.imagequality_listview_row_loaderImageView);
checkedList.add(holder.textview);
holder.layout.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
for (int i = 0; i < checkedList.size(); i++)
if (checkedList.get(i).isChecked())
checkedList.get(i).setChecked(false);
((CheckedTextView) ((LinearLayout) v).getChildAt(0)).setChecked(true);
}
});
holder.textview.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
for (int i = 0; i < checkedList.size(); i++)
if (checkedList.get(i).isChecked())
checkedList.get(i).setChecked(false);
((CheckedTextView) v).setChecked(true);
}
});
convertView.setTag(holder);
} else
holder = (ViewHolder) convertView.getTag();
holder.textview.setText(items.get(position).getDescription());
if (holder.image.used == false) {
holder.image.setImageDrawable(items.get(position).getURL());
holder.image.used = true;
}
return convertView;
}
class ViewHolder {
LinearLayout layout;
LoaderImageView image;
CheckedTextView textview;
}
How can I fix this?

You have to set the Drawable every time getView() gets called, since android is reusing the list elements. It is likely that an earlier set image appears, if you dont update it.
Just remove your condition to set the image drawable, and it will work.

Related

OnItemClick listener does not work with custom adapter with checkbox

I am having custom adapter with item with checkbox and textview. Here is the layout of the item:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="#dimen/standard_margin"
>
<CheckBox
android:id="#+id/checkBox1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:focusable="false"
android:focusableInTouchMode="false"
/>
<TextView
android:id="#+id/checkBoxDesc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:layout_marginLeft="#dimen/new_small_margin"
android:layout_alignBaseline="#+id/isEbank"
android:layout_alignBottom="#+id/isEbank"
android:layout_toRightOf="#+id/isEbank"
android:layout_alignTop="#+id/isEbank"
android:gravity="left"
android:focusable="false"
android:focusableInTouchMode="false"
/>
Here is how the list looks like:
I like when user clicks on list item , or on checkbox to perform same action. However onItemClick does not fire when user clicks on item.
Here is my code for the view:
#Override
public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
View mRoot = inflater.inflate(R.layout.fragment_user, container, false);
ArrayList<Option> listOptions=new ArrayList<Option>();
Option optionYes=new Option(true,getResources().getString(R.string.Yes));
listOptions.add(optionYes);
Option optionNo=new Option(false,getResources().getString(R.string.No));
listOptions.add(optionNo);
listView=(ListView)mRoot.findViewById(R.id.lst);
adapter=new OptionAdapter(getActivity(),R.layout.item_option,listOptions);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
CheckBox box = (CheckBox) view.findViewById(R.id.checkBox1);
box.setChecked(true);
}
});
return mRoot;
}
Here is my code for the adapter:
#Override
public View getView(int position, View convertView, final ViewGroup parent) {
final Option selectedOption = optionsList.get(position);
ViewHolder holder = null;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.item_option, null);
holder = new ViewHolder();
holder.optionDesc = (TextView) convertView.findViewById(R.id.optionDesc);
holder.optionDesc.setText(selectedOption.getDesc());
holder.optionCheckBox = (CheckBox) convertView.findViewById(R.id.isEbank);
holder.optionCheckBox.setFocusable(false);
holder.optionCheckBox.setFocusableInTouchMode(false);
convertView.setTag(holder);
holder.optionCheckBox.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
});
} else {
holder = (ViewHolder) convertView.getTag();
}
return convertView;
}
However it does not work.
you should disable user interaction add this to xml
android:clickable="false"
I suggest you to do this inside getView like here
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.item_option, null);
holder = new ViewHolder();
holder.name = (CheckBox) convertView.findViewById(R.id.checkBox1);
convertView.setTag(holder);
holder.name.setOnClickListener( new View.OnClickListener() {
public void onClick(View v) {
CheckBox cb = (CheckBox) v ;
//Check if cb is checked or not here
cb.isChecked();
});
}
else {
holder = (ViewHolder) convertView.getTag();
}
}

How to click on listview item after change it to different to layout?

When I click on listview, it will change that item to different layout. But after that I can't click on that item anymore. What am I supposed to do? Please help me. Thank you.
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null || convertView.getTag() == null) {
convertView = inflater.inflate(R.layout.activity_mainlist_item, parent, false);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
}else {
holder = (ViewHolder) convertView.getTag();
}
holder.rl_item.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
selectedItem(position);
notifyDataSetChanged();
Intent intent = new Intent(mContext.getApplicationContext(), DetailActivity.class);
mContext.startActivity(intent);
}
});
if (this.clk_position == position) {
View view = inflater.inflate(R.layout.activity_mainlist_item_p, null);
return view;
}
return convertView;
}
I suggest using single layout and divide it into two sections. First section will be visible by default and second section will be invisible. When you click on list item, make first section invisible and second section visible.
For example,
list_item_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- replace below TextView with the layout of activity_mainlist_item.xml -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="Layout 1"
android:id="#+id/layout1"
android:background="#android:color/holo_blue_bright"
/>
<!-- replace below TextView with the layout activity_mainlist_item_p.xml and don't forget to set android:visibility="gone" -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="Layout 2"
android:id="#+id/layout2"
android:visibility="gone"
android:background="#android:color/holo_purple"
/>
</LinearLayout>
In getView(), try as below
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null || convertView.getTag() == null) {
convertView = inflater.inflate(R.layout.list_item_layout, parent, false);
holder = new ViewHolder(convertView);
// Assuming `ViewHolder` has layout1 and layout2.
holder.layout1 = (TextView) convertView.findViewById(R.id.layout1);
holder.layout2 = (TextView) convertView.findViewById(R.id.layout2);
convertView.setTag(holder);
}else {
holder = (ViewHolder) convertView.getTag();
}
holder.rl_item.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
selectedItem(position);
notifyDataSetChanged();
Intent intent = new Intent(mContext.getApplicationContext(), DetailActivity.class);
mContext.startActivity(intent);
}
});
if (this.clk_position == position) {
// Here, set swap the visibility or vice versa depending on your conditions
holder.layout1.setVisibility(View.GONE);
holder.layout2.setVisibility(View.VISIBLE);
return view;
}
return convertView;
}

OnPause method for GridView ListActivity - Android

There is a bit of a pattern used when displaying a ListView or GridView. Given the XML file and my first method shown, what will my corresponding second method be? How it is now, I am getting an exception that a RelativeLayout cannot be cast to an ImageView at this line of the second method shown: ImageView v = (ImageView) gridView.getChildAt(i); I know my gridView is a bunch of relativeLayouts but not sure how to access their drawables.
Here is myLayout.XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="#+id/icon"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:padding="8dp"
android:scaleType="fitCenter" />
</RelativeLayout>
ImageAdapter.getView()
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
ImageHelper ih = new ImageHelper();
if (convertView == null) {
convertView = mInflater.inflate(R.layout.mylayout, null);
holder = new ViewHolder();
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.icon.setImageBitmap(ih.decodeSampledBitmapFromImagePath(mList.get(position), 150, 150));
return convertView;
}
ViewGridView.OnPause()
#Override
protected void onPause() {
GridView gridView = (GridView) findViewById(R.id.gridviewViewOutfits);
int count = gridView.getCount();
for (int i = 0; i < count; i++) {
ImageView v = (ImageView) gridView.getChildAt(i);
if (v != null) {
if (v.getDrawable() != null) v.getDrawable().setCallback(null);
}
}
super.onPause();
}
Thanks
Try this
ImageView v = (ImageView)((ViewGroup)gridView.getChildAt(i)).getChildAt(0);

Why is my adapter's getView() executing infinite times?

In my app I have a GridView inside ViewPager.
I am not using anywhere match_parent or wrap_content. I am using values like 200dp or 150dp. So why is my getView() of GridView adapter is calling multiple times?
I searched a lot like here,
here, here, and here.
This is my adapter class.
public class CustomGridViewAdapter1 extends BaseAdapter {
ArrayList<Integer> list2 = new ArrayList<Integer>();
private LayoutInflater mInflater;
public CustomGridViewAdapter1(Context context, ArrayList<Integer> list2) {
mInflater = LayoutInflater
.from(context.getApplicationContext());
this.list2 = list2;
}
#Override
public int getCount() {
return 6;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
try {
View hView = convertView;
if (convertView == null) {
hView = mInflater.inflate(R.layout.greeditem, null);
ViewHolder1 holder = new ViewHolder1();
holder.song_pic = (ImageView) hView.findViewById(R.id.pic1);
holder.name = (TextView) hView
.findViewById(R.id.tabletext1);
holder.layout = (LinearLayout) hView
.findViewById(R.id.bingo_rlayout1);
hView.setTag(holder);
}
ViewHolder1 holder = (ViewHolder1) hView.getTag();
imageLoader.DisplayImage(list1.get(position), holder.song_pic);
holder.name.setText(list.get(position));
if (list2.get(position) == 1) {
holder.layout.setBackgroundColor(getActivity()
.getResources().getColor(R.color.lightblue));
holder.name.setTextColor(getActivity().getResources().getColor(R.color.white));
}
return hView;
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
And this is my XML layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<GridView
android:id="#+id/gridView1"
android:layout_width="320dp"
android:layout_height="250dp"
android:layout_below="#+id/ticketText"
android:numColumns="2"
android:background="#fff"
android:listSelector="#android:color/white">
</GridView>
<TextView
android:id="#+id/scoreId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#+id/ticketText"
android:layout_alignBottom="#+id/ticketText"
android:layout_alignParentRight="true"
android:layout_marginRight="32dp"
android:text="Score 1/6"
android:textColor="#000000"
android:textSize="16sp" />
<TextView
android:id="#+id/ticketText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/tablayout"
android:layout_marginLeft="16dp"
android:text="My Ticket #1"
android:textColor="#000000"
android:textSize="16sp" />
</RelativeLayout>
We need to check the null condition in getView(). Try with below code:
#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;
}

gridview with image and text android

I successfully created a gridview populated with images. Now, what I want to do is put a text below the image.
This is the screenshot of my app so far.
http://i203.photobucket.com/albums/aa266/paulocarabuena_bucket/screen-2.png
Here is my getView method in my imageadapter class..
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
imageView = new ImageView(this.context);
imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(8, 8, 8, 8);
} else {
imageView = (ImageView) convertView;
}
imageView.setImageResource(this.thumbs[position]);
return imageView;
}
Here is the onCreate method of my main activity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.launchFullScreen();
this.setContentView(R.layout.main);
this.grids = (GridView) this.findViewById(R.id.elements);
ImageAdapter adapter = new ImageAdapter(this);
this.grids.setAdapter(adapter);
this.grids.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
}
});
}
Thanks in advance. :)
Instead of Directly using Image View , you should inflate a view as below :
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/widget44"android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_x="201px"
android:layout_y="165px"
android:gravity="center_horizontal">
<ImageView
android:id="#+id/icon_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</ImageView>
<TextView
android:id="#+id/icon_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:gravity="center_horizontal"
android:textColorHighlight="#656565">
</TextView>
</LinearLayout>
And your Adapter should be like this :
public class ImageAdapter extends BaseAdapter{
Context mContext;
public static final int ACTIVITY_CREATE = 10;
public ImageAdapter(Context c){
mContext = c;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return 5;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View v;
if(convertView==null){
LayoutInflater li = getLayoutInflater();
v = li.inflate(R.layout.icon, null);
TextView tv = (TextView)v.findViewById(R.id.icon_text);
tv.setText("Profile "+position);
ImageView iv = (ImageView)v.findViewById(R.id.icon_image);
iv.setImageResource(R.drawable.icon);
}
else
{
v = convertView;
}
return v;
}
}
You can do it using an XML, that defines the GridView cell:
image.xml
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_horizontal"
>
<ImageView
android:id="#+id/image"
android:layout_marginBottom = "10dp"
android:src="#drawable/cell_sfondo"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</ImageView>
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
Then in your getView():
if(convertView == null) {
view = inflater.inflate(R.layout.image, null);
}
else
view = convertView;
ImageView image = (ImageView)view.findViewById(R.id.image);
image.setImageResource(this.thumbs[position]);
Paresh Mayani have a really good and simple example. This helped me a lot.
http://www.technotalkative.com/android-gridview-example/
You can create a layout for your image and text in each cell of the grid layout. And I suggest inflating the layout from an xml. You can try to do something like this:
//Use a viewHolder to optimize the list
ViewHolder holder = null;
if (convertView == null) {
//Create a new view holder to optimize the loading of elements in list
holder = new ViewHolder();
convertView = LayoutInflater.from(this.context).inflate(R.layout.my_custom_xml,null) ;
holder.imageView = (ImageView)convertView.findViewByID(R.id.my_image_view);
holder.textView = (TextView)convertView.findViewByID(R.id.my_text_view);
convertView.setTag(holder);
} else {
holder = (ViewHolder)convertView.getTag();
}
//Bind data to the row
//Set the position in holder
holder.position = position;
//Set the image for each row
holder.imageView ...
//Set the text for each row
holder.textView.setText()...
//And the viewholder looks like this
private class ViewHolder{
//The position of this row in list
private int position;
//The image view for each row
private ImageView imageView;
//The textView for each row
private TextView textView;
}
And now you can simply create my_custom_xml which contain the text and image view:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width= "fill_parent"
android:layout_height = "wrap_content"
android:orientation= "vertical">
<ImageView
android:id = "#+id/my_image_view"
android:layout_width = ....
android:layout_height = ...
/>
<TextView
android:id = "#+id/my_text_view"
android:layout_width = ....
android:layout_height = ....
/>
</LinearLayout>
Instead of taking dynamic imageview,you can inflate layout having textview under imageview in adapter as:
if(convertView==null){
inflater=(LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
holder=new Holder();
convertView=inflater.inflate(R.layout.gridinflater, null);
holder.imageView=(ImageView) convertView.findViewById(R.id.img);
holder.textView=(TextView) convertView.findViewById(R.id.txt);
convertView.setTag(holder);
}
else {
holder = (Holder) convertView.getTag();
}
where gridInflater is layout having textview under imageview in Relative Layout as parent.
public static class Holder {
public ImageViewProgress imageView;
public TextView textView;
}

Categories

Resources