I'm currently making a menu for my app, using a DrawerLayout and an ArrayAdapter subclass to achieve something looking like Facebook's drawer menu.
I currently have no problems creating the list, but now that it looks good, i'd like to add separators between different kind of options (i.e. user-related and application-related options) and a search bar on top of the menu.
The code of my current ArrayAdaptor subclass is as following :
public class DrawerMenuAdapter extends ArrayAdapter<String>{
private Context context;
private String[] values;
private int resId;
public DrawerMenuAdapter(Context context, int textViewResourceId, String[] values) {
super(context, textViewResourceId, values);
this.context = context;
this.values = values;
this.resId = textViewResourceId;
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(this.resId, parent, false);
TextView elementText = (TextView)rowView.findViewById(R.id.element_text);
ImageView elementImage = (ImageView)rowView.findViewById(R.id.element_icon);
String textValue = values[position];
elementText.setText(textValue);
//This switch adds the icons to the related elements
switch (position){
case 0:
elementImage.setImageResource(R.drawable.search);
break;
case 1:
elementImage.setImageResource(R.drawable.facebook_friends);
break;
case 2:
elementImage.setImageResource(R.drawable.flirts_history);
break;
case 3:
elementImage.setImageResource(R.drawable.premium);
break;
case 4:
elementImage.setImageResource(R.drawable.settings);
break;
case 5:
elementImage.setImageResource(R.drawable.share_app);
break;
case 6:
elementImage.setImageResource(R.drawable.cgu);
break;
}
return rowView;
}
}
I assume that I have to override the function that populates the ListView by calling the getView function, but I can't find which function it is.
If you want simple sections in your ListView, take a look at this tutorial:
http://cyrilmottier.com/2011/07/05/listview-tips-tricks-2-section-your-listview/
or this tutorial:
http://bartinger.at/listview-with-sectionsseparators/
The second one is not as detailed, but probably easier to understand / kept simpler.
The basic idea is that you make your ListAdapter have different kinds of views. For example two different Views where one kind is the actual list item displaying the information, and the other kind of View being the Section divider.
From the tutorial:
ListViews and more specifically Adapters can handle several types of Views. If you take a look at the Adapter interface you will notice it contains two specific methods:
getViewTypeCount() which returns the number of types of Views your
AdapterView manages. Most of the time this method returns 1 because
all items of the ListView are similar. In this case, by returning 2,
the ListView will handle two types of Views: the regular item Views
and the separator Views
getItemViewType(int) must return an integer between 0 (inclusive) and
getViewTypeCount() (exclusive). The given number expresses the type
of the View at the given position. For instance, we can ensure the
returned values are 0 for the regular item Views and 1 for the
separators
I'm adding an answer here since i've figured another way to to this. It looks a bit like the links #Phil posted.
First i set a string array of the menu i want to display. I've written this array in an XML resource file for personal convenience.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array
name="drawer_menu_options">
<item>Username</item>
<item>-sep-Flirter</item>
<item>Recherche</item>
<item>Amis Facebook</item>
<item>Flirts</item>
<item>Compte premium</item>
<item>-sep-Menu</item>
<item>Réglages</item>
<item>Inviter des amis</item>
<item>CGU</item>
</string-array>
</resources>
Notice that I have two elements using the prefix -sep-. These will be our separators.
Then comes the DrawerMenuAdapter i've shown earlier, which is still an ArrayAdapter, on which I've added some functionalities :
public class DrawerMenuAdapter extends ArrayAdapter<String>{
private Context context;
private String[] values;
private int resId;
private int separatorId = 0;
private int userbarId = 0;
public DrawerMenuAdapter(Context context, int textViewResourceId, String[] values) {
super(context, textViewResourceId, values);
this.context = context;
this.values = values;
this.resId = textViewResourceId;
}
public void setSeparator(int resId){
separatorId = resId;
}
public void setUserbarId(int resId){
userbarId = resId;
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
View rowView;
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(userbarId != 0 && values[position].equals("Username")){
rowView = inflater.inflate(this.userbarId, parent, false);
}else if(separatorId != 0 && values[position].startsWith("-sep-")){
rowView = inflater.inflate(this.separatorId, parent, false);
}else{
rowView = inflater.inflate(this.resId, parent, false);
}
TextView elementText = (TextView)rowView.findViewById(R.id.element_text);
String textValue = values[position];
/* If the current line is a separator, just display a separator. Otherwise, set the
matching picture
*/
if(textValue.startsWith("-sep-")){
elementText.setText(textValue.substring("-sep-".length()));
}else{
if(textValue.equals("Username")){
elementText.setText(context.getSharedPreferences("LovRUserSettings", 0)
.getString("firstName", "Username"));
}else{
elementText.setText(textValue);
}
ImageView elementImage = (ImageView)rowView.findViewById(R.id.element_icon);
switch (position){
case 2:
elementImage.setImageResource(R.drawable.search);
break;
case 3:
elementImage.setImageResource(R.drawable.facebook_friends);
break;
case 4:
elementImage.setImageResource(R.drawable.flirts_history);
break;
case 5:
elementImage.setImageResource(R.drawable.premium);
break;
case 7:
elementImage.setImageResource(R.drawable.settings);
break;
case 8:
elementImage.setImageResource(R.drawable.share_app);
break;
case 9:
elementImage.setImageResource(R.drawable.cgu);
break;
}
}
return rowView;
}
}
In this code, there's an object called userBar. You don't really need to pay attention to this but if you're interested, it's another menu element, using a specific layout file instead of the one I use for regular menu elements. It's a way to demonstrate that you can add whatever kind of specific layout anywhere you want, just by reading your strings.
The main point here is in the way the code searches for separators, the strings with the -sep- prefix. Once one is found, the prefix is removed, and the matching layout is attributed to the separator.
Aight, that's what i've found. After this, you'll have to find your own way to add click listeners. Mines are implemented in the DrawerLayout.setOnCliclListener which basically does the job the exact same way the Google's documentation says. But you can also use setOnclickListenerto your view as you add them, and use an XML file where you can set your own onClick attributes...
Hope it will help =)
Related
I have a String[][] of data and I am trying to make a custom listView from it.
Here is the data
String[][] myDataArray = {{"cat1","cat2","cat3","cat4"},
{"dog1","dog2","dog3"},
{"lion1"},
{"monkey1","monkey2"}};
And now here is how I am trying to display this data in my listView. I want each array within the array to have its own row. So all the cats will be in one row (cell), all the dogs will be in another row and so on. Here is a picture to make it clear each item in the row, is a textView.
I have made cell_4.xml, cell_3.xml, cell_2.xml, cell_1.xml layout file for each of the rows.
And then in the activity that I am trying to show this, I just have a plain old listView.
Now I am not quite sure how to edit/ adapt the data. I have to display it in this way. So that it uses the correct cell layout for each array within the String[]. I was thinking about using a switch statement to get the number of items in each inner array. But having some trouble with the ArrayAdapter. To get it set up.
I have looked at a couple of examples on stackoverflow like this one Custom ListView Android to try and figure this out but can't get it.
EDIT
Here is trying to set up adapter and call MyListViewAdapter, but I don't know what to set as context.
here is the code:
private void handleData(String[][] data){
BaseAdapter adapter = MyListAdapter(context, data);
ListView list = (ListView) findViewById(R.id.mealsListView);
list.setAdapter(adapter);
}
Some thoughts:
1) If you are determined to use ListView, skip this point. Else, you might be interested in GRIDVIEW that natively support a table structure.
2) Your idea is consistent. ListView only knows about ROWS, so your adapter will be called for you to display a ROW, and it's up to you to transform the array in that row into an element with multiple cells. You'll do that in getView()
3) You'll make use of the Item Types (getViewTypeCount and getItemViewType) to declare you have different item types. Each type will be a row with a given number of cells: 1,2,3,4...
you will override getViewTypeCount() to return the maximum number of cells in a row
you will either inflate a static layout for the number of cells a row has, or generate it dynamically
Let's get started ... First of all in the adapter we override the Type methods to declare
our rows will be of different types:
#Override
public int getViewTypeCount() {
return 4;
// you have 4 types of rows.
// SUPER IMPORTANT: No row in the array can have more cells than this number
// or getView will crash (you'd have to define additional layouts)
}
#Override
public int getItemViewType(int position) {
// for a given position, you need to return what type is it. This number ranges
// from 0 to itemtypecount-1. We return the length of the array (number of cells)
// this function is called by the View Recycler to appropriately pass you the
// correct view to reuse in convertView
return myDataArray[position].length - 1;
}
And then we need to implement getView(). The typical implementation will be the first one, where you create different XMLs, and the second one is a more advanced implementation where we dynamically create the layouts without any xml.
First Case: Static Layouts
Ideal if you limit the Row Array Length to say 3 or 4, to avoid creating dozens of layouts. So you define 4 xmls (ie. row_1_childs, row_2_childs, row_3_childs, row_4_childs) that will be the templates of rows with that number of children. Then,
and then in GetView:
// we define an array of layout ids to quickly select the layout to inflate depending on
// the number of rows:
private final static int[] sLayouts=new int[] {
R.layout.row_1_childs,
R.layout.row_2_childs,
R.layout.row_3_childs,
R.layout.row_4_childs
};
public View getView (int position, View convertView, ViewGroup parent) {
int maxcells=myDataArray[position].length;
if (convertView == null) {
// generate the appropriate type
if (maxcells<=sLayout.length) {
// just check we are in bounds
convertView=LayoutInflater.from(parent.getContext()).inflate(sLayout[maxcells-1], null);
} else {
// you have a row with too many elements, need to define additional layouts
throw new RuntimeException ("Need to define more layouts!!");
}
}
// At this point, convertView is a row of the correct type, either just created,
// or ready to recycle. Just fill in the cells
// for example something like this
ViewGroup container=(ViewGroup)convertView;
for (int i=0; i<maxcells; i++) {
// We assume each row is a (linear)layout whose only children are textviews,
// one for each cell
TextView cell=(TextView)container.getChildAt(i); // get textview for cell i
cell.setText(myDataArray[position][i]);
cell.setTag( new PositionInfo(position, i)); // we store the cell number and row inside the TextView
cell.setOnClickListener(mCellClickListener);
}
return convertView;
}
Second Case: Dynamic Layouts
Another solution would be to dynamically generate the rows, and dynamically generate as many text views as you might need. To do so, keep overriding getViewTypeCount() to return the Maximum number of children, and define getView like this:
public View getView (int position, View convertView, ViewGroup parent) {
String rowData=myDataArray[position];
if (convertView==null) {
// generate a LinearLayout for number of children:
LinearLayout row=new LinearLayout(context);
for (int i=0, len=rowData.length(); i<len; i++) {
// generate a textview for each cell
TextView cell=new TextView(parent.getContext());
// we will use the same clicklistener (very efficient)
cell.setOnClickListener(mCellClickListener);
row.addView(cell, new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1)); // same width for each cell
}
convertView=row;
}
// here convertView has the correct number of children, same as before:
ViewGroup container=(ViewGroup)convertView;
for (int i=0, len=rowData.length(); i<len; i++) {
TextView cell=(TextView)container.getChildAt(i);
cell.setText(rowData[i]);
cell.setTag( new PositionInfo(position, i)); // we store the cell number and row inside the TextView
}
return convertView;
}
// auxiliar class to store row and col in each textview for the clicklistener
private class PositionInfo {
public int row, col;
public PositionInfo(int row, int col) { this.row=row; this.col=col; }
}
// trick: only one clicklistener for millions of cells
private View.OnClickListener mCellClickListener=new View.OnClickListener() {
#Override
public void onClick(View v) {
PositionInfo position=(PositionInfo)v.getTag(); // we stored this previously
// you pressed position.row and position.col
}
}
Solution (1) is cool to manually create the layouts and configure them a lot.
Solution (2) is cool to programmatically support any number of cells, in case they are very different
Both solutions are pretty efficient, because they play nice with the View recycler: If you fail to use View Types and you constantly inflate layouts, your ListView will be laggy and waste a lot of memory and resources.
You might run into problems if the size of each string in the row varies and you might then have to push data onto the next line.
Try using an alternate view, if your aim is categorization of similar data, expandable listview is an option to consider.
You will need to make your own adapter by extending BaseAdapter. You can check the data's size the getView() method, and inflate the correct layout.
UPDATE:
public class MyListAdapter extends BaseAdapter{
String[][] mData;
LayoutInflater mLayoutInflater;
public MyListAdapter(Context context, String[][] data) {
mData = data;
mLayoutInflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return mData.length;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
String data[] = mData.get(position);
switch(data.length){
case 4:
convertView = mLayoutInflater.inflate(R.layout.cell_4, parent, false);
TextView t1 = (TextView) convertView.findViewById(R.id.one);
t1.setText(data[0]);
break;
case 3:
convertView = mLayoutInflater.inflate(R.layout.cell_3, parent, false);
break;
case 2:
convertView = mLayoutInflater.inflate(R.layout.cell_2, parent, false);
break;
case 1:
convertView = mLayoutInflater.inflate(R.layout.cell_1, parent, false);
break;
default:
convertView = mLayoutInflater.inflate(R.layout.blank, parent, false);
}
return convertView;
}
}
I just started learning android and I'm at a point where I want to do the question described below but I'm not sure how to start.
I have an array of data with the following data,
1, text1, image1.png
2, text2, image2.png
3, text3, null
4, null, image3.png
I know how to create a ListView with ArrayAdapter along with their xml layout following some tutorial.
As you see in the array above sometimes it doesn't contain an image, sometimes it doesn't contain text and sometimes it has both.
My question is how to make that work with layout so that it dynamically changes based on the array values?
In other words how can I start thinking about building a listview+ArrayAdapter+layout where I can view an imageiew only where the array record has an image only, viewing a textview when there is a text only and viewing both of them when both are available.
A link to a tutorial will be extremely helpful
You could create a type MyCustomType that represents one array element (In your case it holds a number, a text and an image). Furthermore you need to implement your custom array adapter. This adapter uses an ArrayList of your MyCustomType.
public class CustomAdapter extends ArrayAdapter<MyCustomType> {
//...
private ArrayList<MyCustomType> foo;
public CustomAdapter(Context context, Activity bar, ArrayList<MyCustomType> foo) {
super(bar, R.layout.row, foo);
this.foo = foo;
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
Override getViewTypeCount() to determine how many different kinds of rows you have. getItemViewType returns the kind of row that has to be displayed.
Your getView method could be similiar to his one:
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
int type = getItemViewType(position); // decide what row type has to be displayed
if (convertView == null) {
convertView = mInflater.inflate(R.layout.row, parent, false);
viewHolder = new ViewHolder();
viewHolder.number = //...
viewHolder.text = //...
viewHolder.image = //...
convertView.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder) convertView.getTag(); // avoided to call findViewById
}
switch(type) {
case TYPE1:
//... you could just change the visibility of the corresponding view
break;
case TYPE 2:
// ...
break;
}
return convertView;
}
My advice is to use a custom array adapter. There is a good tutorial here.
The official documentation can be found here.
Essentially you will create a class that extends the ArrayAdapter class. Implement the overrides and put your handling to show or not show particular views in the getView method. This method will fire for each item in the list passed it.
I have a ListView that uses a custom SimpleCursorAdapter to display information. Each ListView row has Three TextView items.
Due to the nature of the application, the reader may or may not want to change the font size to ease the reading of the text displayed on the row items.
What I want to accomplish is a way to update the text size of this TextView items, without having to do it from bindView().
Here's how I currently am doing it:
Step one: Notify the adapter that the textSize should be changed.
public void setAdjustTextSize(int size) {
switch (size) {
case ArticleViewFragment.FONT_SIZE_SMALL:
mTitleTextSizeRes = R.dimen.title_size_small;
mCategoryTextSizeRes = R.dimen.description_size_small;
mDescripTextSizeRes = R.dimen.description_size_small;
break;
case ArticleViewFragment.FONT_SIZE_MEDIUM:
mTitleTextSizeRes = R.dimen.title_size_medium;
mCategoryTextSizeRes = R.dimen.description_size_medium;
mDescripTextSizeRes = R.dimen.description_size_medium;
break;
case ArticleViewFragment.FONT_SIZE_LARGE:
mTitleTextSizeRes = R.dimen.title_size_large;
mCategoryTextSizeRes = R.dimen.description_size_large;
mDescripTextSizeRes = R.dimen.description_size_large;
break;
case ArticleViewFragment.FONT_SIZE_EXTRA_LARGE:
mTitleTextSizeRes = R.dimen.title_size_extra_large;
mCategoryTextSizeRes = R.dimen.description_size_extra_large;
mDescripTextSizeRes = R.dimen.description_size_extra_large;
break;
default:
break;
}
}
mTitleTextSizeRes, mCategoryTextSizeRes and mDescripTextSizeRes are instance variables of the Custom Adapter.
Step Two: Set the textSize during bindView().
#Override
public void bindView(View view, Context arg1, Cursor arg2) {
ViewHolder mHolder = (ViewHolder) view.getTag();
//Some other initialization
mHolder.category.setTextSize(TypedValue.COMPLEX_UNIT_PX, mResources.getDimension(mCategoryTextSizeRes));
mHolder.title.setTextSize(TypedValue.COMPLEX_UNIT_PX, mResources.getDimension(mTitleTextSizeRes));
mHolder.description.setTextSize(TypedValue.COMPLEX_UNIT_PX, mResources.getDimension(mDescripTextSizeRes));
}
Now, that works, yes, but there are a few point I'd like to argue about:
1- The fact that I am changing the TextSize at runtime each time the convertView is reused. It'd be best to do this via onNewView and then the convertViews will already be using the new set size. However, attempting to do so will fail, since most of the times, the adapter has already been created, and the Views are there already.
2 - The fact that some since the code is ran on bindView, existing views will not see the change right away, and at some point during the scrolling, the user will have a few views with the old text size, and some with the new text size. Example Image attached.
With that said, I was hoping I could accmoplish something of the likes of re-initializing the adapter maybe, but I'm not sure how to do that, other than maybe creating the adapter from scratch. I tried calling notifyDataSetChanged and that did nothing
Any ideas?
Try altering your custom adapter's getView() to something like this:
public View getView(int position, View convertView, ViewGroup parent)
{
View view = super.getView(position, convertView, parent);
TextView tv = (TextView)view;
// NOTE: textSize is set in the custom adapter's constructor
// int textSize
tv.setTextSize(textSize);
return view;
}
creating your own adapter is very easy, especially if all you use are just textViews for each row.
you just override the getView() method and re-use the convertView if it's not null, or inflate a new view for the row in case it is null (and create its viewholder to be put as a tag) .
then, you use the view's viewHolder to update the textViews to the new size.
when the user has changed the preference of the size of the font, just call notifyDataSetChanged.
for being more familiar with listView and adapters, watch "the world of listView" .
Apparently it wasn't clear that I was using my own implementation of a SimpleCursorAdapter, #MarsAtomic and #android developer both suggested I override getView(), however, when using a SimpleCursorAdapter you don't, you override both onNewView() and onBindView().
What I ended up doing, which is what I wanted to avoid was simply recreating the adapter from scratch, and setting the TextSize during onNewView(). I am pretty pleased with the results, since that minimizes the amount of calls to textview.setTextSize(size) by only setting the size on new views.
First Step, on my activity, check during onResume if font size changed, if it did, recreate the adapter from scratch:
final int oldSize = mCurFontSize;
mCurFontSize = Integer.valueOf(mPreferences.getString(getString(R.string.pref_key_font_size), "0"));
if (oldSize != mCurFontSize) {
//Only re-do the adapter if needed
Constants.logMessage("re-creating adapter");
mArticleAdapter = new CursorListAdapter(Home.this, R.layout.list_item,
mCursor, FROM, TO, 0, mCurFontSize);
mArticlesListView.setAdapter(mArticleAdapter);
}
}
Step two, on the adapter constructor, set the font size values to the instance variables.
public CursorListAdapter(Context context, int layout, Cursor c,
String[] from, int[] to, int flags, int textSize) {
super(context, layout, c, from, to, flags);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mRootLayout = layout;
mResources = context.getResources();
setAdjustTextSize(textSize);
}
Where setAdjustTextSize does this:
public void setAdjustTextSize(int size) {
mTextSize = size;
switch (size) {
case ArticleViewFragment.FONT_SIZE_SMALL:
mTitleTextSizeRes = R.dimen.title_size_small;
mCategoryTextSizeRes = R.dimen.description_size_small;
mDescripTextSizeRes = R.dimen.description_size_small;
break;
case ArticleViewFragment.FONT_SIZE_MEDIUM:
mTitleTextSizeRes = R.dimen.title_size_medium;
mCategoryTextSizeRes = R.dimen.description_size_medium;
mDescripTextSizeRes = R.dimen.description_size_medium;
break;
case ArticleViewFragment.FONT_SIZE_LARGE:
mTitleTextSizeRes = R.dimen.title_size_large;
mCategoryTextSizeRes = R.dimen.description_size_large;
mDescripTextSizeRes = R.dimen.description_size_large;
break;
case ArticleViewFragment.FONT_SIZE_EXTRA_LARGE:
mTitleTextSizeRes = R.dimen.title_size_extra_large;
mCategoryTextSizeRes = R.dimen.description_size_extra_large;
mDescripTextSizeRes = R.dimen.description_size_extra_large;
break;
default:
break;
}
}
Step Three: During onNewView() set the text size.
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View container = mInflater.inflate(mRootLayout, null);
ViewHolder mHolder = new ViewHolder();
mHolder.category = (TextView) container.findViewById(R.id.article_category);
mHolder.title = (TextView) container.findViewById(R.id.article_title);
mHolder.description = (TextView) container.findViewById(R.id.article_descrp);
mHolder.image = (ImageView) container.findViewById(R.id.article_image);
mHolder.category.setTextSize(TypedValue.COMPLEX_UNIT_PX, mResources.getDimension(mCategoryTextSizeRes));
mHolder.title.setTextSize(TypedValue.COMPLEX_UNIT_PX, mResources.getDimension(mTitleTextSizeRes));
mHolder.description.setTextSize(TypedValue.COMPLEX_UNIT_PX, mResources.getDimension(mDescripTextSizeRes));
container.setTag(mHolder);
return container;
}
And that is about it. It works, it doesn't call setTextSize many times during the adapter's life, I only recreate the adapter when the font size did change, and we are all happy.
I need to display a list of A objects (think List<A>). A has the following structure:
class A {
List<B> bList;
List<C> cList;
}
All three lists can be of arbitrary length. bList and cList should be displayed in their entire length in each row of the list of As. Each list is backed by a SQLite cursor. It's a sort of calendar view. The following image illustrates the idea:
Now, I'm wondering what's the best way to achieve this "in the Android way". I tried multiple things:
ListView for A with nested ListViews for B and C: Not recommended, hard to disable the scrolling behaviour of B and C.
ListView for A with LinearLayout for B and C and programmatically adding child views to the LinearLayouts in the Adapter: I have to manage Cursor updates for B and C and adjust the height of the rows myself, lots of view management code in the Adapter where it does not belong.
Composing everything of nested LinearLayouts: Same problem as 2, even more Cursors to deal with.
Maybe there's a different way where I can fully take advantage of existing functionality?
I already had a look at similar questions on StackOverflow. The top two suggestions seem to be:
Spread data over multiple Activities/Fragments: Considered, not an option because not user friendly (in this case).
Use ExpandableListView: Does not seem to be applicable to the data structure, the list of Bs and Cs should be visible from the beginning.
To implement this type of view you need to implement two things.
ListView listView;
IArrayAdapter iArrayAdapter;
Initialize listView with id provided in xml.
Activity.this.runOnUiThread(new Runnable() {
public void run() {
iArrayAdapter = new IArrayAdapter(Activity.this,
R.layout.list_item, "list of items group it from Bean");
listView.setAdapter(iArrayAdapter);
iArrayAdapter.notifyDataSetChanged();
}
});
list_item is another layout which contaion type of display you need to display in list.
IArrayAdapter is class extending ArrayAdapter
public class IArrayAdapter extends ArrayAdapter<IBean> {
private final Activity context;
private final ArrayList<IBean> iBeans;
private int resourceId;
public InboxArrayAdapter(Activity context, int resourceId,
ArrayList<IBean> iBeans) {
super(context, resourceId, inboxBeans);
this.context = context;
this.iBeans = iBeans;
this.resourceId = resourceId;
}
/*
* TO update View
*
* #see android.widget.ArrayAdapter#getView(int, android.view.View,
* android.view.ViewGroup)
*/
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
if (rowView == null) {
LayoutInflater layoutInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowView = layoutInflater.inflate(resourceId, null);
final IBean iBean = iBeans.get(position);
final ImageView imageView = (ImageView) rowView
.findViewById(R.id.message);
final TextView rowTxt = (TextView) rowView
.findViewById(R.id.senderName);
final TextView rowTxt1 = (TextView) rowView
.findViewById(R.id.senderMessage);
final TextView rowTxt2 = (TextView) rowView
.findViewById(R.id.senderTime);
final CheckBox check = (CheckBox) rowView.findViewById(R.id.check);
.....set text here.....
return rowView;
}
}
imageView, rowtext, etc are part of layout list_item
ANd IBean is java bean class contain your 5 iTem in a list.
Any item you don't want left it blank.
Having a hard time figuring out the best way to go about this. What I've got going on is a gallery view loaded with images, with a text view just beneath it. I would like to fill the contents of the textview based upon which image is clicked. I followed the standard GalleryView tutorial where it has you create a custom ImageAdapter class which extends the BaseAdapter class. In doing so, I created an OnItemClickListener for the galleryview, and I assumed the next logical step would be to create a switch statement to figure out what to put in the text view.
So I eventually figured out that I should probably be itererating over the gallery items as opposed to the parameters passed to the onitemclicklistener() method. The problem is now, no matter what item is clicked, the output to the desired text view is always as if the last item was clicked. I commented out the 'case 2', and it then began to always take case 1. What would be causing the switch statement to 'default' to the last case coded even though I have not defined a default case?
Additionally, I'm seeing conflicting stuff regarding the switch statement in terms of looping. It should loop on its own, yes? If so I imagine it probably is, but since it always selects case 2, I'm not realizing that the output of the text should be changing? Is my switch statement all messed up? do I need to include some sort of loop? What am I doing wrong here?
Custom ImageAdapter class:
public class ImageAdapter extends BaseAdapter
{
private Context context;
private int itemBackground;
public ImageAdapter(Context c)
{
context = c;
//---setting the style---
TypedArray a = obtainStyledAttributes(R.styleable.Gallery1);
itemBackground = a.getResourceId(
R.styleable.Gallery1_android_galleryItemBackground, 0);
a.recycle();
}
//---returns the number of images---
public int getCount() {
return imageIDs.length;
}
//---returns the ID of an item---
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
//---returns an ImageView view---
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = new ImageView(context);
imageView.setImageResource(imageIDs[position]);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.setLayoutParams(new Gallery.LayoutParams(150, 120));
imageView.setBackgroundResource(itemBackground);
return imageView;
}
}
}
And here is the code I'm using to create the galleryview and the onitemclicklistener:
Gallery gallery = (Gallery) findViewById(R.id.top_gallery);
gallery.setAdapter(new ImageAdapter(this));
gallery.setOnItemClickListener(new OnItemClickListener()
{
public void onItemClick(AdapterView parent,
View v, int position, long id)
{
TextView tView = (TextView) findViewById(R.id.cat_desc);
switch(gallery.getSelectedItemPosition())
{
case 0:
tView.setText("Option1");
case 1:
tView.setText("Option2");
case 2:
tView.setText("Option3");
}
}
You're lacking break's in case statement and code gets executed in linear way. That's why the last is always selected.
You need break; in your case, else it will fall through. Try:
case 0 : tView.setText("Option1"); break;
You are missing the breaks;
switch(gallery.getSelectedItemPosition())
{
case 0:
tView.setText("Option1");
break;
case 1:
tView.setText("Option2");
break;
case 2:
tView.setText("Option3");
break;
}