I have a grid containing seven rows of five ImageViews. I want to center the images in the views. I've tried setting every layout, gravity, and foregroundGravity property in the xml to centered, but nothing seems to center it. I read a few stackoverflow posts and they all suggested doing things I'd already tried.
The grid is closer to the left side than the right, and when I touch an image, the highlighted area has more space on the right side of the image than the left.
Any suggestions on how to get them to center?
Here's my layout file:
<ImageView
android:id="#+id/grid_image"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:foregroundGravity="center"
>
</ImageView>
</LinearLayout>
Here's the class that I'm using it in:
class CustomGrid extends BaseAdapter {
private Context context;
private final List<Button> buttons;
CustomGrid(Context c, List<Button> buttons) {
context = c;
this.buttons = buttons;
}
#Override
public int getCount() { return buttons.size(); }
#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) {
View grid;
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
grid = inflater.inflate(R.layout.grid_single, null);
ImageView imageView = (ImageView) grid.findViewById(R.id.grid_image);
imageView.setImageResource(buttons.get(position).getBasicImageId());
buttons.get(position).setImageView(imageView);
}
else {
grid = convertView;
}
return grid;
}
}
And here's the image. For now I'm just using an Android stock image.
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M6,18c0,0.55 0.45,1 1,1h1v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L11,19h2v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L16,19h1c0.55,0 1,-0.45 1,-1L18,8L6,8v10zM3.5,8C2.67,8 2,8.67 2,9.5v7c0,0.83 0.67,1.5 1.5,1.5S5,17.33 5,16.5v-7C5,8.67 4.33,8 3.5,8zM20.5,8c-0.83,0 -1.5,0.67 -1.5,1.5v7c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5v-7c0,-0.83 -0.67,-1.5 -1.5,-1.5zM15.53,2.16l1.3,-1.3c0.2,-0.2 0.2,-0.51 0,-0.71 -0.2,-0.2 -0.51,-0.2 -0.71,0l-1.48,1.48C13.85,1.23 12.95,1 12,1c-0.96,0 -1.86,0.23 -2.66,0.63L7.85,0.15c-0.2,-0.2 -0.51,-0.2 -0.71,0 -0.2,0.2 -0.2,0.51 0,0.71l1.31,1.31C6.97,3.26 6,5.01 6,7h12c0,-1.99 -0.97,-3.75 -2.47,-4.84zM10,5L9,5L9,4h1v1zM15,5h-1L14,4h1v1z"/>
</vector>
Related
I have made a GridView with an ImageAdapter but it does not show the images inside.
I tried to change numColumns, columnWidth and other attributes but it didn't work.
In Android Studio xml Design panel i can see my Gridview.
This is my gridview inside my xml layout file:
<GridView
android:id="#+id/gridview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/linear_buttons"
android:layout_above="#+id/btnSearch"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:background="#null"
android:columnWidth="120dp"
android:gravity="center"
android:numColumns="auto_fit"
android:stretchMode="columnWidth" />
This is my Adapter:
public class CustomGridViewAdapter extends BaseAdapter {
private final Context mContext;
public CustomGridViewAdapter(Context c) {
mContext = c;
}
public int getCount() {
return mThumbIds.length;
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(R.dimen.grid_dimens_width, R.dimen.grid_dimens_height));
imageView.setScaleType(ImageView.ScaleType.CENTER);
imageView.setPadding(1, 5, 1, 1);
} else {
imageView = (ImageView) convertView;
}
imageView.setImageResource(mThumbIds[position]);
return imageView;
}
private final Integer[] mThumbIds = {
R.drawable.grid_agapis, R.drawable.grid_asteies, R.drawable.grid_auto,
R.drawable.grid_gamos, R.drawable.grid_goneis,
};
I set the adapter with the following code:
GridView gridview = (GridView) findViewById(R.id.gridview);
gridview.setAdapter(new CustomGridViewAdapter(this));
gridview.setOnItemClickListener(this);
Can you explain me where is the problem?
Thank you.
imageView.setLayoutParams(new GridView.LayoutParams(R.dimen.grid_dimens_width,
R.dimen.grid_dimens_height));
With this line of code you are trying to limit the size of the grabbed drawable to a fixed width & height that are equal to grid_dimens_width & grid_dimens_height respectively.
But actually using R.dimen.foo won't return the value of foo, instead it returns the generated integer value of the resource itself which can be something like a big number (e.g. -21893103 or 33238590) .. this will make you see nothing on the screen because the image is either:
Too big (in case of a positive resource value 33238590) so you are seeing the tiny pixels of it
or too small (in case of a negative resource value -21893103) because its size is zero.
What you need to do instead is to get the dimen resource using getDimention() and pass the resource id to it.
To apply that to your code:
Replace:
imageView.setLayoutParams(new GridView.LayoutParams(R.dimen.grid_dimens_width,
R.dimen.grid_dimens_height));
With:
imageView.setLayoutParams(new GridView.LayoutParams(
(int) mContext.getResources().getDimension(R.dimen.grid_dimens_width),
(int) mContext.getResources().getDimension(R.dimen.grid_dimens_height)));
Result:
I am trying to make some kind of image gallery where images are loaded in the background and are dynamically added to a gridView when they have finished loading. The image loading works quite well, but the gridView's scrolling behaviour won't work as expected if the images inside the gridView exceed the screen's height.
For testing purposes I am loading 15 dummy images, aligend in two columns. After all images are loaded it seems that the gridView's height fits its content height (8 images or rows on the left column) according to the scrollBar on the right. But if I try to scroll past the 4th row item to reach the bottom of the view (row 5/6/7/8), the scrollBar indicates that the gridView's height has changed and the bottom of the view is reached. Scrolling past the 4th line is not possible. If I scroll up again, the gridView seems to contain 8 rows again.
Left view: gridView seems to contain 15 images.
Right view: gridView suddenly seems to contain only 8 images
I have already tried using different approaches like the ExpandableHeightViewGrid mentioned here, but the scrolling behaviour was the same. I would choose using a gridView having multiple columns of images over a single row (like using a listView) because if I there are more than 15 images to load, scrolling to the bottom would be very annoying.
Here is my code:
photo_gallery.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">
<!-- This is basically a HorizontalScrollView where i add some buttons -->
<com.my.HorizontalButtonScrollList
android:id="#+id/horizontalButtonScrollList"
android:layout_width="match_parent"
android:layout_height="50dip">
</com.my.HorizontalButtonScrollList>
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<GridView
android:id="#+id/gridView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnWidth="100dp"
android:numColumns="2"
android:verticalSpacing="0dp"
android:horizontalSpacing="0dp"
android:stretchMode="columnWidth"
android:gravity="center"
android:scrollbars="vertical">
</GridView>
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
PhotoGalleryActivity.java (I simplified the code for better readability)
public class PhotoGalleryActivity extends myBaseView {
private GridView gridView;
private PhotoGalleryImageAdapter imageAdapter;
private PhotoGalleryModel[] photoGalleryModels;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.photo_gallery);
gridView = (GridView) findViewById(R.id.gridView);
loadImages();
}
void loadImages() {
photoGalleryModels = PhotoGalleryModel.getFakeData();
imageAdapter = new PhotoGalleryImageAdapter(this, photoGalleryModels);
gridView.setAdapter(imageAdapter);
}
}
PhotoGalleryImageAdapter (also simplified)
public class PhotoGalleryImageAdapter extends BaseAdapter {
private Context mContext;
private PhotoGalleryModel[] photoGalleryModels;
public PhotoGalleryImageAdapter(Context c, PhotoGalleryModel[] models){
mContext = c;
photoGalleryModels = models;
}
#Override
public int getCount() { return photoGalleryModels.length; }
#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) {
final ImageView imageView = new ImageView(mContext);
DownloadImageWithURL(photoGalleryModels[position].thumb_image_url, new MyHttpCallback() {
#Override
public void MyHttpCallback_OnSuccess(Object data, String responseString)
{
if(data instanceof Bitmap) {
imageView.setImageBitmap((Bitmap)data);
}
}
#Override
public void MyHttpCallback_OnError(String responseString, ErrorDataModel error)
{}
});
convertView = imageView;
return convertView;
}
}
I would be really glad if someone could help me out here and help me fix my gridView so that I can scroll through all of the loaded images as intended.
Well, it seems that I've solved the problem myself by ignoring it. After I skipped fixing the gridView because I did not know what to do anymore I implemented caching the images with an LruCache (like shown in the Android developer's training page) to save some memory. And suddenly the gridView's scrolling behaviour was fixed, too.
Here are my changes:
PhotoGalleryImageAdapter (now with caching)
public class PhotoGalleryImageAdapter extends BaseAdapter {
private Context mContext;
private PhotoGalleryModel[] photoGalleryModels;
private LruCache<String, Bitmap> mMemoryCache;
public PhotoGalleryImageAdapter(Context c, PhotoGalleryModel[] models){
mContext = c;
photoGalleryModels = models;
final int maxMemory = (int)(Runtime.getRuntime().maxMemory() / 1024);
final int cacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
#Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getByteCount() / 1024;
}
};
}
#Override
public int getCount() { return photoGalleryModels.length; }
#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) {
final ImageView imageView = new ImageView(mContext);
final String imageKey = photoGalleryModels[position].thumb_image_url;
final Bitmap bitmapImage = mMemoryCache.get(imageKey);
if (bitmapImage != null) {
imageView.setImageBitmap(bitmapImage);
}
else {
DownloadImageWithURL(photoGalleryModels[position].thumb_image_url, new MyHttpCallback() {
#Override
public void MyHttpCallback_OnSuccess(Object data, String responseString) {
if (data instanceof Bitmap) {
mMemoryCache.put(imageKey, (Bitmap)data);
imageView.setImageBitmap((Bitmap)data);
}
}
#Override
public void MyHttpCallback_OnError(String responseString, ErrorDataModel error)
{}
});
}
convertView = imageView;
return convertView;
}
}
I am happy that the gridView is finally working, but I'm not happy with the fact that it didn't work for me without caching the images. I should have set the imageView's bounds inside the imageAdapter's getView() method before the images were loaded, probably. I will try to fix the gridView without using caching and update my answer if I have found a solution to it in case someone has to face the same problems. Until then, I am glad that I managed to make it work :)
UPDATE:
I finally made it work with and without caching. Here is my updated PhotoGalleryImageAdapter:
public View getView(int position, View convertView, ViewGroup parent) {
final ImageView imageView;
// set the imagge's bounds if it is not loaded yet
if (convertView == null) {
imageView = new ImageView(mContext);
imageView.setLayoutParams(new ViewGroup.LayoutParams(imageSize, imageSize));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(0, 0, 0, 0);
}
else {
imageView = (ImageView) convertView;
}
final String imageKey = photoGalleryModels[position].thumb_image_url;
final Bitmap bitmapImage = mMemoryCache.get(imageKey);
if (bitmapImage != null) {
imageView.setImageBitmap(bitmapImage);
}
else {
imageView.setImageBitmap(emptyBitmap);
DownloadImageWithURL(photoGalleryModels[position].thumb_image_url, new MyHttpCallback() {
#Override
public void MyHttpCallback_OnSuccess(Object data, String responseString) {
if (data instanceof Bitmap) {
mMemoryCache.put(imageKey, (Bitmap)data);
imageView.setImageBitmap((Bitmap)data);
}
}
#Override
public void MyHttpCallback_OnError(String responseString, ErrorDataModel error)
{}
});
}
convertView = imageView;
return convertView;
}
As expected, I needed to set the images bounds before it was loaded.
Because I changed the gridView's numColumns parameter to 'auto_fit', the image's width/height (100dp + stretchMode columnWidth) is calculated as follows:
int imagesPerRow = screenSize.x / (int)(100 * mContext.getResources().getDisplayMetrics().density);
imageSize = screenSize.x / imagesPerRow;
Before loading the imageView's bitmapImage, I create an empty bitmap image and assign it to the imageView (found the code here):
emptyBitmap = Bitmap.createBitmap(imageSize, imageSize, Bitmap.Config.ARGB_8888);
The gridView now works as expected no matter if the LruCache is used or not. I don't know if it's common practice to anser one's own question but in doing so I thought it could help others who facing a similar problem.
I've got a GridView full of images. Here's my custom adapter:
public class ImageAdapter extends ArrayAdapter<String> {
private final String LOG_TAG = ImageAdapter.class.getSimpleName();
public ImageAdapter(Activity context, List<String> urls){
super(context, 0, urls);
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
String url = getItem(position);
View rootView = LayoutInflater.from(getContext()).inflate(R.layout.grid_item, parent, false);
ImageView img = (ImageView) rootView.findViewById(R.id.grid_view_item);
img.setLayoutParams(
new GridView.LayoutParams(
GridView.AUTO_FIT,
500));
img.setScaleType(ImageView.ScaleType.FIT_XY);
Picasso.with(getContext())
.load(url)
.into(img);
return rootView;
}
}
You can see that I set the height to be 500. But I don't want this.
I want the height to be the actual height of the image, just like the width.
How can I do that?
Use adjustViewBounds property to force the height to the correct dimension.
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true" />
I am facing some problem for rendering ListView from a dynamic layout. I don't know why the getView is called only with position 0 and several times!
I searched over internet and stackoverflow but cannot find a suitable answer.
I am actually trying to do a demo of this: http://www.framentos.com/en/android-tutorial/2012/07/16/listview-in-android-using-custom-listadapter-and-viewcache/
Notably, my main layout file is surrounded by scrollbar.
main activity layout file:
<ListView
android:id="#+id/city_list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#+id/questionsList"
android:paddingTop="20sp" >
</ListView>
My layout file for list view:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="80dip" >
<ImageView
android:id="#+id/ImageCity"
android:layout_width="90sp"
android:layout_height="90sp" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_toRightOf="#id/ImageCity"
android:orientation="vertical"
android:paddingLeft="10sp">
<TextView
android:id="#+id/cityName"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="25sp" />
<TextView
android:id="#+id/cityLinkWiki"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:autoLink="web"
android:textSize="15sp" />
</LinearLayout>
</RelativeLayout>
Adapter class:
import com.incidentreport.app.classes.objects.City;
public class CityListAdapter extends ArrayAdapter{
private int resource;
private LayoutInflater inflater;
private Context context;
public CityListAdapter ( Context ctx, int resourceId, List objects) {
super( ctx, resourceId, objects );
resource = resourceId;
inflater = LayoutInflater.from( ctx );
context=ctx;
}
#Override
public View getView ( int position, View convertView, ViewGroup parent ) {
Log.v("adapter", "pos: " + position + "#" + resource);
/* create a new view of my layout and inflate it in the row */
convertView = ( RelativeLayout ) inflater.inflate( resource, null );
/* Extract the city's object to show */
City city = (City)getItem( position );
/* Take the TextView from layout and set the city's name */
TextView txtName = (TextView) convertView.findViewById(R.id.cityName);
txtName.setText(city.getName());
/* Take the TextView from layout and set the city's wiki link */
TextView txtWiki = (TextView) convertView.findViewById(R.id.cityLinkWiki);
txtWiki.setText(city.getUrlWiki());
/* Take the ImageView from layout and set the city's image */
ImageView imageCity = (ImageView) convertView.findViewById(R.id.ImageCity);
return convertView;
}
}
main activity code snipps:
List listCity= new ArrayList();
listCity.add(new City("London","http://en.wikipedia.org/wiki/London","london"));
listCity.add(new City("Rome","http://en.wikipedia.org/wiki/Rome","rome"));
listCity.add(new City("Paris","http://en.wikipedia.org/wiki/Paris","paris"));
ListView listViewCity = ( ListView ) findViewById( R.id.city_list);
listViewCity.setAdapter( new CityListAdapter(this, R.layout.layout_city, listCity ) );
Okay, I figured out the issue by expanding ListView as much possible. Meaning to say, giving a dynamic full height so that all item becomes visible.
I followed the below solution:
Calculate the size of a list view or how to tell it to fully expand
Use a ViewHolder pattern for better performance.
http://developer.android.com/training/improving-layouts/smooth-scrolling.html
static class ViewHolder
{
TextView txtName,txtWiki;
ImageView imageCity;
}
Change getView to
#Override
public View getView ( int position, View convertView, ViewGroup parent ) {
ViewHolder holder;
if(convertView == null)
{
convertView = ( RelativeLayout ) inflater.inflate( resource, parent, false );
holder = new ViewHolder();
holder.txtName = (TextView) convertView.findViewById(R.id.cityName);
holder.txtWiki = (TextView) convertView.findViewById(R.id.cityLinkWiki);
holder.imageCity = (ImageView) convertView.findViewById(R.id.ImageCity);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
City city = (City)getItem( position );
holder.txtName.setText(city.getName());
holder.txtWiki.setText(city.getUrlWiki());
return convertView;
}
ListView recyclues view's. You may also want to read
How ListView's recycling mechanism works
Try this way,hope this will help you to solve your problem.
public class CityListAdapter extends BaseAdapter{
private Context context;
private List objects;
public CityListAdapter ( Context context, int resourceId, List objects) {
this.context=context;
this.objects=objects;
}
#Override
public int getCount() {
return objects.size();
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public Object getItem(int position) {
return objects.get(position);
}
#Override
public View getView ( int position, View convertView, ViewGroup parent ) {
ViewHolder holder;
if(convertView==null){
holder = new ViewHolder();
convertView = LayoutInflater.from(context).inflate(R.layout.layout_city,null);
holder.txtName = (TextView) convertView.findViewById(R.id.cityName);
holder.txtWiki = (TextView) convertView.findViewById(R.id.cityLinkWiki);
holder.imageCity = (ImageView) convertView.findViewById(R.id.ImageCity);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
holder.txtName.setText(((City)getItem(position)).getName());
holder.txtWiki.setText(((City)getItem(position)).getUrlWiki());
return convertView;
}
class ViewHolder{
TextView txtName;
TextView txtWiki;
ImageView imageCity;
}
}
I ran into this same issue. My list view is mostly working, but there's a certain sequence of actions which will make certain items disappear. Clicking on them afterwards causes a NullPointerException.
Here's the steps to reproduce the bug:
Drag an item to the top.
Drag another item up or down.
The item at the top will disappear.
Drag another item up or down.
The top item will reappear.
Behavior continues if you go to step 2
After debugging, I found that my StableArrayAdapter.getView() method was being called twice, only for the blank item at the top of the list.
To fix it, per masum7's answer, I set the layout_height for my DynamicListView to "wrap_content".
Try to get layout inflater as
LayoutInflater inflater = (LayoutInflater)context.getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
This may work
I have an ArrayAdapter for a list view that has multiple buttons in it. For one toggle button, I want to have a default state based on a condition, and let users toggle the button as well.
However, when users click button on row 1, the button for row 3 actually gets selected. I'm not sure why this is happening. Below is snippet of relevant code from my getView method with comments.
layout of my toggle button
<ToggleButton android:id="#+id/color_toggle"
android:layout_width="50px"
android:layout_height="50px"
android:focusable="false"
android:textOn="" android:textOff="" android:layout_alignParentLeft="true"
android:layout_marginRight="10dp"
/>
class Color {
int id;
int something;
}
List<Color> colorsList;
class ColorHolder {
TextView colorNameText;
ToggleButton toggleButton;
}
public View getView(final int position, final View convertView, final ViewGroup parent) {
View rowView = convertView;
Color c = colorsList.get(position);
if (null == rowView) {
rowView = this.inflater.inflate(R.layout.list_item_color, parent, false);
holder = new ColorHolder();
holder.colorNameText = (TextView) rowView.findViewById(R.id.color_name);
holder.toggleButton = (ToggleButton) rowView.findViewById(R.id.color_toggle);
rowView.setTag(holder);
}
else {
holder = (ColorHolder)rowView.getTag();
}
holder.toggleButton.setTag(c.getId());
final ColorHolder thisRowHolder = holder;
holder.toggleButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (thisRowHolder.toggleButton.isChecked()) {
thisRowHolder.toggleButton.setBackgroundDrawable(//normal button);
thisRowHolder.toggleButton.setChecked(false);
for (int i = 0; i < colorList.size(); i++) {
if (colorList.get(i) == (Integer)v.getTag()) {
colorList.get(i).setSomething(0);
break;
}
}
adapter.notifyDataSetChanged();
}
else {
thisRowHolder.toggleButton.setBackgroundDrawable(//enabled button);
thisRowHolder.toggleButton.setChecked(true);
for (int i = 0; i < colorList.size(); i++) {
if (colorList.get(i) == (Integer)v.getTag()) {
colorList.get(i).setSomething(1);
break;
}
}
adapter.notifyDataSetChanged();
}
}
});
if (c.getSomething()>0) {
holder.toggleButton.setBackgroundDrawable(//enabled button);
holder.toggleButton.setChecked(true);
}
else {
holder.toggleButton.setBackgroundDrawable(//normal button);
holder.toggleButton.setChecked(false);
}
return rowView;
}
Question
What am I doing wrong? why are other buttons in third row toggling even though i'm toggling buttons in row one.
I read that this happens because the listView recycles, is there no way to fix it? Some strategies i've tried, to no avail, based on similar questions: 1) put onClickListener in the if clause. 2) instead of setting int in setTag instead set the holder and use that holder in onClickListener
update
I've updated all the code in the question with suggestions I received.
Hope This Helps.
Activity Code
public class DemoActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ColorInfo[] clr= new ColorInfo[20];
for(int i=0;i<20;i++){
clr[i] = new ColorInfo();
}
((ListView)findViewById(R.id.list)).setAdapter(new MyAdapter(this, 0, clr));
}
private static class MyAdapter extends ArrayAdapter<ColorInfo> implements OnClickListener{
LayoutInflater inflater;
public MyAdapter(Context context, int textViewResourceId,
ColorInfo[] objects) {
super(context, textViewResourceId, objects);
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView == null){
convertView = inflater.inflate(R.layout.row, null);
holder = new ViewHolder();
holder.tgl = (ToggleButton) convertView.findViewById(R.id.toggle);
convertView.setTag(holder);
}
holder = (ViewHolder) convertView.getTag();
holder.tgl.setTag(position);
holder.tgl.setOnClickListener(this);
holder.tgl.setChecked(getItem(position).isChecked);
return convertView;
}
private static class ViewHolder{
ToggleButton tgl;
}
public void onClick(View v) {
int pos = (Integer) v.getTag();
ColorInfo cinfo = getItem(pos);
cinfo.isChecked = !cinfo.isChecked;
}
}
private static class ColorInfo{
boolean isChecked=false;
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ListView
android:id="#+id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ToggleButton android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/toggle"
/>
</LinearLayout>
Your problem is listview recycling views
You have to store state of toggle button for each row of listview.
Eg.Create class which stores information about each row,suppose ColorInfo which contains color and isChecked boolean.
so instead of
Color c = colorsList.get(position);
it will be
ColorInfo colorInfo = colorsList.get(position);
and in getview
togglebutton.setCheck(colorInfo.isCheck)
and in onClick listener of toggle buttons you change state of object of ColorInfo for that position to toggleChecked true or false and notifyDatasetChanged,this will solve your problem.
You are using a member variable for your ViewHolder, rather than a final local variable. So your OnClickListener is referencing whatever the latest holder instance is, which will correspond with the most recently created or recycled list item.
Do this instead:
//Lock in this reference for the OnClickListener
final ColorHolder thisRowHolder = holder;
holder.favButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (thisRowHolder.toggleButton.isChecked()) {
thisRowHolder.toggleButton.setBackgroundDrawable(getResources().getDrawable(...);
thisRowHolder.toggleButton.setChecked(false);
}
else {
thisRowHolder.toggleButton.setBackgroundDrawable(getResources().getDrawable(...));
thisRowHolder.toggleButton.setChecked(true);
}
}
});
...
Edit:
Also noticed this. In these two lines:
holder.colorNameText = (TextView) itemView.findViewById(R.id.color_name);
holder.toggleButton = (ToggleButton) itemView.findViewById(R.id.color_toggle);
You are finding the views in some member variable itemView, but you need to be finding them in rowView so you are getting the instances for this specific row. All your view holders are looking at the same ToggleButton instance, which may not even be on screen.
Edit 2:
One more thing you're missing. You need to store the state of the toggle buttons and reapply them. So in your OnClickListener, when you call setChecked() you must also update the backing data in colorsList. Looks like you already cached a reference to the proper list element in your ToggleButton's ID, so should be easy. Then move this block of code out of your if/else block and put it afterwards, so the toggle button is always updated to the latest data:
if (c.getSomething()>0) {
holder.toggleButton.setBackgroundDrawable(getResource().getDrawable(...)));
holder.setChecked(false);
}
else {
holder.toggleButton.setBackgroundDrawable(getResource().getDrawable(...)));
holder.setChecked(true);
}