I want to create an image gallery (with lots of pictures). I need a GridView to show the various categories, and in every row there's an ImageView and a TextView. All the pictures are loaded in the drawable folder. According to the category the user chooses, I need to show all the pictures of a folder in a new Activity. My problem is with the adapter for the gridview. I'm trying to create a custom one but with little success. All the examples I found aren't useful for my task...
Here is a sample code for creating a GridView gallery with text.
At first, add GridView to your main layout(ex: activity_main.xml).
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<GridView
android:numColumns="auto_fit"
android:gravity="center"
android:columnWidth="100dp"
android:stretchMode="columnWidth"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/grid"/>
</LinearLayout>
Then, you need to create a layout to inflate the view of Custom Adapter.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp" >
<ImageView
android:id="#+id/grid_image"
android:layout_width="50dp"
android:layout_height="50dp">
</ImageView>
<TextView
android:id="#+id/grid_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:textSize="9sp" >
</TextView>
</LinearLayout>
Create a custom adapter which will receive array of image resources and string.
public class CustomGrid extends BaseAdapter{
private Context mContext;
private final String[] names;
private final int[] Imageid;
public CustomGrid(Context c,String[] names,int[] Imageid ) {
mContext = c;
this.Imageid = Imageid;
this.names = names;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return names.length;
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View grid;
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
grid = new View(mContext);
grid = inflater.inflate(R.layout.grid_single, null);
TextView textView = (TextView) grid.findViewById(R.id.grid_text);
ImageView imageView = (ImageView)grid.findViewById(R.id.grid_image);
textView.setText(names[position]);
imageView.setImageResource(Imageid[position]);
} else {
grid = (View) convertView;
}
return grid;
}
}
Finally set this Custom Adapter to the GridView adapter in your activity:
public class MainActivity extends Activity
{
GridView grid;
String[] names =
{
"String1",
"String2",
"String3",
"String4",
"String5",
"String6",
"String8",
"String9",
"String10"
} ;
int[] imageId =
{
R.drawable.image1,
R.drawable.image2,
R.drawable.image3,
R.drawable.image4,
R.drawable.image5,
R.drawable.image6,
R.drawable.image7,
R.drawable.image8,
R.drawable.image9,
R.drawable.image10
};
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CustomGrid adapter = new CustomGrid(MainActivity.this, names, imageId);
grid=(GridView)findViewById(R.id.grid);
grid.setAdapter(adapter);
grid.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id)
{
Toast.makeText(MainActivity.this, "You Clicked at " +names[+ position], Toast.LENGTH_SHORT).show();
}
});
}
}
Hope this helps. :)
Related
I'm removing images from a gridview when a button is pressed.
The images does remove fine and the gridview also updates with the call "adapter.notifyDataSetChanged();".
When an imageview is removed another image next to this position should take its position. This happens, but the image here won't reload so there's just a blank space? How can I get this imageview to reload its image?
The problem:
Here is my gridadapter:
public class FavoriteMovieGridAdapter extends BaseAdapter {
Context context;
ArrayList<DataFavorites> List;
FavoritesMovie fragment;
private static LayoutInflater inflater = null;
FavoriteMovieGridAdapter adapter = this;
public FavoriteMovieGridAdapter(Context context, ArrayList<DataFavorites> List, FavoritesMovie fragment) {
this.context = context;
this.List = List;
this.fragment = fragment;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return List.size();
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return position;
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
// Avoid unneccessary calls to findViewById() on each row
final ViewHolder holder;
/*
* If convertView is not null, reuse it directly, no inflation
* Only inflate a new View when the convertView is null.
*/
if (convertView == null) {
convertView = inflater.inflate(R.layout.favorite_grid_item, null);
holder = new ViewHolder();
holder.poster = (ImageView) convertView.findViewById(R.id.upcoming_image);
holder.editbutton = (ImageView) convertView.findViewById(R.id.delete_item);
// The tag can be any Object, this just happens to be the ViewHolder
convertView.setTag(holder);
}
else{
// Get the ViewHolder back to get fast access to the TextView
// and the ImageView.
holder = (ViewHolder) convertView.getTag();
}
final View finalConvertView = convertView;
final DataFavorites e;
new DataFavorites();
e = List.get(position);
String url = String.valueOf(e.getUrl());
// load image url into poster
// Seems as if this doesn't run for the imageview next to this when this view is removed?
Picasso.with(context).load(url).fit().placeholder(R.drawable.movie_back).into(holder.poster);
// Create onclick and show edit button
convertView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
// show edit button
holder.editbutton.setVisibility(View.VISIBLE);
YoYo.with(Techniques.FadeIn).duration(700).playOn(finalConvertView.findViewById(R.id.delete_item));
// onclick edit button remove item and update gridview
holder.editbutton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
YoYo.with(Techniques.ZoomOut).duration(700).playOn(finalConvertView.findViewById(R.id.favorite_relative));
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
adapter.List.remove(e);
adapter.notifyDataSetChanged();
// Delete specific movie from data base
DatabaseHandlerMovie db = new DatabaseHandlerMovie(context);
// Reading all movies
db.deleteMovie(e);
}
}, 1000);
}
});
return false;
}
});
return convertView;
}
static class ViewHolder {
ImageView poster;
ImageView editbutton;
}
}
My grid item layout:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="#+id/favorite_relative"
android:layout_centerHorizontal="true"
android:gravity="center_horizontal">
<ImageView android:layout_width="123.3dp"
android:layout_height="185.3dp"
android:id="#+id/upcoming_image"
android:scaleType="fitXY" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/delete_item"
android:src="#drawable/ic_remove_circle_outline_white_24dp"
android:tint="#color/colorPrimaryDark"
android:clickable="true"
android:visibility="gone"
android:layout_alignRight="#+id/upcoming_image"
android:layout_alignEnd="#+id/upcoming_image"/>
</RelativeLayout>
My grid layout:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context=".Favorites"
android:background="#FFFFFF"
android:focusableInTouchMode="true">
<GridView
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:id="#+id/movies_gridlayout"
android:paddingRight="-1dp"
android:paddingEnd="-1dp"
android:numColumns="3"
android:background="#ffffff"
android:visibility="invisible"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:id="#+id/favorite_none"
android:text="No favorite movies found"
android:textSize="15sp"
android:visibility="gone"
android:textColor="#color/SecondaryText"
/>
<ProgressBar
android:id="#+id/progressBar"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"
>
</ProgressBar>
</FrameLayout>
Turns out a 3rd-party lib was causing this:
YoYo.with(Techniques.ZoomOut).duration(700).playOn(finalConvertView.findViewById(R.id.favorite_relative));
you will have adapter and mainactivity for gridview
So u will have to implement public interface in both of them to communicate
following code may help you :)
In Adapter class add following code
private OnItemClickListner onItemClickListner;
public MyAdapter(Context c, List<PDFDoc> pdfDocs,OnItemClickListner onItemClickListner) {
this.context = c;
this.pdfDocs = pdfDocs;
this.onItemClickListner=onItemClickListner;
}
public interface OnItemClickListner {
void removefromadapter(int position);
}
ImageButton imageButton = view.findViewById(R.id.cancelid);
imageButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// write your stuff here
onItemClickListner.removefromadapter(position);
}
});
In MainActivity of gridview add following code
implements OnItemClickListner required**
public class addclient_fragment extends Fragment implements MyAdapter.OnItemClickListner {
you will required to add this method in mainactivity
#Override
public void removefromadapter(int position) {
// write your stuff here
}
I know how to make every single cell in a gridview into a button, but that's not what I'm after.
I have a gridview that's filled with this adapter.
public class TaskAdapter extends BaseAdapter{
private Context mContext;
public TaskAdapter(Context c)
{
mContext = c;
}
#Override
public int getCount() {
return nThumbsIds.size();
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View sView = convertView;
if(convertView == null){
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
sView = inflater.inflate(R.layout.task_square, parent, false);
TextView tView = (TextView) sView.findViewById(R.id.textView);
tView.setText(nThumbsIds.get(position));
}
return sView;
}
}
And nThumbsIds is filled with Strings whose contents will be different at almost every build.
I want to add a button as the last element of the grid, always after all the Strings. Is there a way?
Try like this:
Create Adapter
public class TaskAdapter extends BaseAdapter
{
private Context mContext;
public TaskAdapter(Context c)
{
mContext = c;
}
#Override
public int getCount()
{
return nThumbsIds.size();
}
#Override
public Object getItem(int position)
{
// TODO Auto-generated method stub
return nThumbsIds.get(position);
}
#Override
public long getItemId(int position)
{
// TODO Auto-generated method stub
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
TextView tView =null;
Button tBtn =null;
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
convertView = inflater.inflate(R.layout.task_square, parent, false);
tView = (TextView) convertView.findViewById(R.id.grid_item_txv);
tBtn = (Button) convertView.findViewById(R.id.grid_item_btn);
if(position < nThumbsIds.size()-1)
{
tView.setText(nThumbsIds.get(position));
tView.setVisibility(View.VISIBLE);
tBtn.setVisibility(View.GONE);
}
else
{
tBtn.setText(nThumbsIds.get(position));
tView.setVisibility(View.GONE);
tBtn.setVisibility(View.VISIBLE);
}
return convertView;
}
Your Grid Item layout xml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/grid_item_txv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="20dp"
android:layout_centerInParent="true"
android:gravity="center"
android:text="Smaple"/>
<Button
android:id="#+id/grid_item_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="20dp"
android:gravity="center"
android:layout_centerInParent="true"
android:text="sample"
android:visibility="gone" />
</RelativeLayout>
GridView in your activity's layout :
<GridView
android:id="#+id/test_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnWidth="100dp"
android:numColumns="auto_fit"
android:stretchMode="columnWidth" >
</GridView>
how to select row item using Tick mark like iphone in android?iam using imageview in list_row.xml.when i click the list row item then i show image in row imageview.
if(getItem(position)!=null){
img.setvisibilty(View.Visible);}
else{System.out.println("imagenull");}
iam using this but image display in last row only.please help me how to select item using tickmark image.
public class DistanceArrayAdapter extends ArrayAdapter<Constant>{
public static String category,state,miles;
public ImageView img;
private Context context;
private int current = -1;
ArrayList<Constant> dataObject;
public DistanceArrayAdapter(Context context, int textViewResourceId,
ArrayList<Constant> dataObject) {
super(context, textViewResourceId, dataObject);
this.context=context;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View rowView=convertView;
if(rowView==null){
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowView = inflater.inflate(R.layout.category_row, parent, false);
}
//TextView textView = (TextView) rowView.findViewById(R.id.text1);
TextView textView1 = (TextView) rowView.findViewById(R.id.text2);
//textView.setText(""+getItem(position).id);
textView1.setText(""+getItem(position).caption);
img=(ImageView)rowView.findViewById(R.id.img);
img.setVisibility(View.GONE);
if(position%2==1)
{
rowView.setBackgroundResource(R.color.even_list);
}
else
{
rowView.setBackgroundResource(R.color.odd_list);
}
rowView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(img.getVisibility()==View.GONE)
{
img.setVisibility(View.VISIBLE);
System.out.println("1");
}
if(img.getVisibility()==View.VISIBLE){
img.setVisibility(View.GONE);
System.out.println("12");
}
miles=getItem(position).caption;
System.out.println("miles"+miles);
}
});
return rowView;
}
}
Drawing from https://groups.google.com/forum/?fromgroups#!topic/android-developers/No0LrgJ6q2M
public class MainActivity extends Activity implements AdapterView.OnItemClickListener {
String[] GENRES = new String[] {"Action", "Adventure", "Animation", "Children", "Comedy", "Documentary", "Drama", "Foreign", "History", "Independent", "Romance", "Sci-Fi", "Television", "Thriller"};
private CheckBoxAdapter mCheckBoxAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ListView listView = (ListView) findViewById(R.id.lv);
listView.setItemsCanFocus(false);
listView.setTextFilterEnabled(true);
listView.setOnItemClickListener(this);
mCheckBoxAdapter = new CheckBoxAdapter(this, GENRES);
listView.setAdapter(mCheckBoxAdapter);
Button b = (Button) findViewById(R.id.button1);
b.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
StringBuilder result = new StringBuilder();
for (int i = 0; i < GENRES.length; i++) {
if (mCheckBoxAdapter.mCheckStates.get(i) == true) {
result.append(GENRES[i]);
result.append("\n");
}
}
Toast.makeText(MainActivity.this, result, 1000).show();
}
});
}
public void onItemClick(AdapterView parent, View view, int position, long id) {
mCheckBoxAdapter.toggle(position);
}
class CheckBoxAdapter extends ArrayAdapter implements CompoundButton.OnCheckedChangeListener {
LayoutInflater mInflater;
TextView tv1, tv;
CheckBox cb;
String[] gen;
private SparseBooleanArray mCheckStates;
private SparseBooleanArray mCheckStates;
CheckBoxAdapter(MainActivity context, String[] genres) {
super(context, 0, genres);
mCheckStates = new SparseBooleanArray(genres.length);
mInflater = (LayoutInflater) MainActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
gen = genres;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return gen.length;
}
}
}
activity_main.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView
android:id="#+id/lv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/button1"/>
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="Button" />
</RelativeLayout>
And the XML file for the checkboxes:
<?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" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="15dp"
android:layout_marginTop="34dp"
android:text="TextView" />
<CheckBox
android:id="#+id/checkBox1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="#+id/textView1"
android:layout_marginRight="22dp"
android:layout_marginTop="23dp" />
</RelativeLayout>
When you click the button a toast message with list of item choosen is displayed. You can modify the above according to your requirements.
Set selection mode on your ListView
//if using ListActivity or ListFragment
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
//or
myListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
//myListView is reference to your ListView
1.Make visibility gone to you tick mark image
2.Implement view.setOnClickListener in arrayadapter.
3.In that check image.getVisibility()==View.GONE then make image.setVisibity(View.Visible)
4.if image.getVisiblity()==View.VISIBLE then make your image.setVisibity(View.GONE)
Try this.
I am working on Android project. I follow tutorial from http://www.vogella.com/articles/AndroidSQLite/article.html but I stuck on something. Tutorial shows how to use Class with 1 String object. I am working with 2 String objects. So I changed few things (add new String to my class, change layout.simple_list_item_1 to android.R.layout.simple_list_item_2 etc.) And now the question is - how to make something to get Stoliki class objects (override toString() gives me only 1 item, so It's useless).
Class Stoliki
public class Stoliki {
private long id;
private String numer;
private String opis;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getNumer() {
return numer;
}
public void setNumer(String numer) {
this.numer = numer;
}
public String getOpis() {
return opis;
}
public void setOpis(String opis) {
this.opis = opis;
}
}
Activity
import android.app.ListActivity;
import android.os.Bundle;
import java.util.List;
import java.util.Random;
import android.view.View;
import android.widget.ArrayAdapter;
public class FirstGridPage extends ListActivity {
private StolikiDataSource datasource;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_list_stoliki);
datasource = new StolikiDataSource(this);
datasource.open();
List<Stoliki> values = datasource.getAllStoliki();
// Use the SimpleCursorAdapter to show the
// elements in a ListView
ArrayAdapter<Stoliki> adapter = new ArrayAdapter<Stoliki>(this,
android.R.layout.simple_list_item_1, values);
setListAdapter(adapter);
}
// Will be called via the onClick attribute
// of the buttons in main.xml
public void onClick(View view) {
#SuppressWarnings("unchecked")
ArrayAdapter<Stoliki> adapter = (ArrayAdapter<Stoliki>) getListAdapter();
Stoliki stolik = null;
switch (view.getId()) {
case R.id.add:
String[] stoliki_numer = new String[] { "1", "2", "3" };
String[] stoliki_opis = new String[] { "Czerwony", "Niebieski", "Zielony" };
int nextInt = new Random().nextInt(3);
// Save the new comment to the database
stolik = datasource.createStolik(stoliki_numer[nextInt], stoliki_opis[nextInt]);
adapter.add(stolik);
break;
case R.id.delete:
if (getListAdapter().getCount() > 0) {
stolik = (Stoliki) getListAdapter().getItem(0);
datasource.deleteStolik(stolik);
adapter.remove(stolik);
}
break;
}
adapter.notifyDataSetChanged();
}
#Override
protected void onResume() {
datasource.open();
super.onResume();
}
#Override
protected void onPause() {
datasource.close();
super.onPause();
}
}
http://www.youtube.com/watch?v=wDBM6wVEO70. Listview talk by Romain guy( android developer at google).
Main.xml
<ListView android:id="#+id/list"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:focusableInTouchMode="false"
android:listSelector="#android:color/transparent"
android:layout_weight="2"
android:headerDividersEnabled="false"
android:footerDividersEnabled="false"
android:dividerHeight="8dp"
android:divider="#000000"
android:cacheColorHint="#000000"
android:drawSelectorOnTop="false">
</ListView>
</LinearLayout>
Customw row. row.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="horizontal"
android:background="#ffffff"
>
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:background="#drawable/itembkg"
/>
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text="TextView" />
</LinearLayout>
public class CustomListView extends Activity {
/** Called when the activity is first created. */
ListView lv1;
Customlistadapter cus;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Button b= (Button) findViewById(R.id.remove);
lv1 = (ListView) findViewById(R.id.list);
cus= new Customlistadapter(this);
lv1.setAdapter(cus);
}
}
Custom list adapter. Inflate custom layout for each row.
public class Customlistadapter extends ArrayAdapter {
private LayoutInflater mInflater;
Context c;
public Customlistadapter(CustomListView customListView) {
super(customListView, 0);
// TODO Auto-generated constructor stub
this.mInflater = LayoutInflater.from(customListView);
c=customListView;
}
public int getCount() {
return 20; // number of listview rows.
}
public Object getItem(int arg0) {
return arg0;
}
public long getItemId(int arg0) {
return arg0;
}
public View getView(final int arg0, View arg1, ViewGroup arg2) {
final ViewHolder vh;
vh= new ViewHolder();
if(arg1==null )
{
arg1=mInflater.inflate(R.layout.row, arg2,false);
vh.tv1= (TextView)arg1.findViewById(R.id.textView1);
vh.tv2= (TextView)arg1.findViewById(R.id.textView2);
}
else
{
arg1.setTag(vh);
}
vh.tv1.setText("hello");
vh.tv2.setText("hello");
return arg1;
}
static class ViewHolder //use a viewholder for smooth scrolling and performance.
{
TextView tv1,tv2;
}
}
Edit:
Your activity will have a listview. This is set in oncreate setContentView(R.layout.activity_main);. The main layout will have a listview. You set the adapter of listview as listview.setAdapter(youradapter);
Then listview will have custom layout ie row.xml inflated for each row item. You custom adapter for listview is where the row.xml is inflated. You defined your class CustomAdapter which extends ArrayAdapter. You override a set of methods.
getCount() --- size of listview.
getItem(int position) -- returns the position
getView(int position, View convertView, ViewGroup parent)
// position is the position in the listview.
//convertview - view that is tobe inflated
// you will return the view that is infated.
You will have to use a viewholder for smooth scrolling and performance. Imagine 1000 rows is lstview with images it may cause memory exceptions. One way to get rid of this is to recycle views. The visible views(rows) are not recycled. The video in the link at the top has a detail explanation on the topic
activity_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"
android:background="#0095FF">
<ListView android:id="#+id/list"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:focusableInTouchMode="false"
android:listSelector="#android:color/transparent"
android:layout_weight="2"
android:headerDividersEnabled="false"
android:footerDividersEnabled="false"
android:dividerHeight="8dp"
android:divider="#000000"
android:cacheColorHint="#000000"
android:drawSelectorOnTop="false">
</ListView>
</LinearLayout>
row.xml (layout inflated for each listview row)
<?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="horizontal" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Header" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="80dp"
android:layout_gravity="center"
android:text="TextView" />
</LinearLayout>
MainActivity
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView ll = (ListView) findViewById(R.id.list);
CustomAdapter cus = new CustomAdapter();
ll.setAdapter(cus);
}
class CustomAdapter extends BaseAdapter
{
LayoutInflater mInflater;
public CustomAdapter()
{
mInflater = (LayoutInflater) MainActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return 30;
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return position;
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
final ViewHolder vh;
vh= new ViewHolder();
if(convertView==null )
{
convertView=mInflater.inflate(R.layout.row, parent,false);
vh.tv2= (TextView)convertView.findViewById(R.id.textView2);
vh.tv1= (TextView)convertView.findViewById(R.id.textView2);
}
else
{
convertView.setTag(vh);
}
vh.tv1.setText("my text");
vh.tv2.setText("Postion = "+position);
return convertView;
}
class ViewHolder
{
TextView tv1,tv2;
}
}
}
Why everytime the onItemClick() event is invoked on a ListView with a custom adapter, the getView() method in the adapter is called again?
I have the following code in API level 7, and when I try to change the checked value in the row's CheckedTextView object (stored in a ViewHolder), the adapter's getView() for each row is invoked and I got a strange behaviour(The selected row in the listView check/uncheck the CheckedTextView in another row) :
The code for the Activity is:
public class EnvioImagenesActivity extends Activity implements OnItemClickListener {
ListView listView;
private EnvioImagenAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.envio_imagenes);
listView=(ListView) findViewById(R.id.listViewEnvios);
adapter=new EnvioImagenAdapter(this,Store.getImages());
listView.setAdapter(adapter);
listView.setOnItemClickListener(this);
}
public void onItemClick(AdapterView<?> arg0, View view, int pos,
long id) {
ViewHolder holder=(ViewHolder) view.getTag();
holder.checkedTextView.toggle();
}
}
The code for the Xml layout activity is:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:orientation="vertical">
<TextView
android:id="#+id/textView1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/envioImagenes"
android:textAppearance="?android:attr/textAppearanceLarge" android:gravity="center"/>
<ListView
android:id="#+id/listViewEnvios"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:choiceMode="multipleChoice">
</ListView>
</LinearLayout>
The listview adapter:
public class EnvioImagenAdapter extends BaseAdapter {
private List<ImageUri> items;
private Context context;
public EnvioImagenAdapter(Context context, List<ImageUri> items) {
this.context=context;
this.items = items;
}
public int getCount() {
return items.size();
}
public Object getItem(int position) {
return items.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
System.out.println("---getView() method called");
View v = convertView;
ViewHolder holder;
if (v == null) {
LayoutInflater vi = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.row_envio_imagen, null);
holder = new ViewHolder();
holder.imageView = (ImageView) v.findViewById(R.id.imageView1);
holder.textView = (TextView) v.findViewById(R.id.textView1);
holder.temporalProgressBar = (ProgressBar) v
.findViewById(R.id.progressBar1);
holder.checkedTextView = (CheckedTextView) v
.findViewById(R.id.checkedTextView12);
holder.selected = true;
holder.position = position;
v.setTag(holder);
} else {
holder = (ViewHolder) v.getTag();
}
ImageUri imageUri = items.get(position);
File f = new File(imageUri.getImageUri().getPath());
String fileSize = Util.formatFileSize(f.length());
holder.textView.setText(fileSize);
new ImageTask(imageUri).execute(holder);
return v;
}
class ImageTask extends AsyncTask<ViewHolder, Void, Bitmap> {
public ImageTask(ImageUri imageUri) {
this.imageUri = imageUri;
}
private ImageUri imageUri;
private ViewHolder viewHolder;
#Override
protected Bitmap doInBackground(ViewHolder... params) {
viewHolder = params[0];
Bitmap bmp = BitmapFactory.decodeFile(imageUri.getThumbUri()
.getPath());
return bmp;
}
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
viewHolder.temporalProgressBar.setVisibility(View.GONE);
viewHolder.imageView.setVisibility(View.VISIBLE);
viewHolder.imageView.setImageBitmap(result);
};
}
class ViewHolder {
public int position;
CheckedTextView checkedTextView;
ProgressBar temporalProgressBar;
ImageView imageView;
TextView textView;
boolean selected;
}
}
And the xml layout for each row is:
<?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="?android:attr/listPreferredItemHeight"
android:padding="6dip" >
<ProgressBar
android:id="#+id/progressBar1"
android:layout_width="45dip"
android:layout_height="45dip"
android:layout_alignParentLeft="true" />
<ImageView
android:id="#+id/imageView1"
android:layout_width="45dip"
android:layout_height="45dip"
android:layout_alignParentLeft="true" />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dip"
android:layout_toRightOf="#id/imageView1" />
<CheckedTextView
android:id="#+id/checkedTextView12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checkMark="?android:attr/textCheckMark"
android:checked="true"
android:layout_alignParentRight="true">
</CheckedTextView>
<ProgressBar
android:id="#+id/progressBar2"
style="?android:attr/progressBarStyleHorizontal"
android:layout_height="wrap_content"
android:layout_width="0dip"
android:layout_below="#+id/textView1"
android:layout_toLeftOf="#id/checkedTextView12"
android:layout_toRightOf="#id/imageView1"
android:paddingLeft="5dip"
android:paddingTop="2dip" />
</RelativeLayout>
And when I run the app in the simulator and make click in a row, I obtain in the LogCat:
System.out(2947): ---getView() method called
for each row displayed in the list.
Thanks in advance!!!!
I had a similar problem in the code caused
ListView.setChoiceMode (ListView.CHOICE_MODE_SINGLE);
When you click on the item for each item getview summoned again, in your case, you can try to remove android:choiceMode="multipleChoice"
Maybe this will help you.
I have noticed that accessing the views from outside the getView() rarely produces the expected behaviour. I suppose it is because of the recycling mechanism. Two alternative options work:
1) implement onClick() in getView()
2) If you want to keep your logic out of the adapter, in onItemClick(), change the underlying data and call adapter.notifyDatasetChanged(). The checkbox will toggle.