| Author |
Message |
plusminus Site Admin


Joined: 14 Nov 2007 Posts: 2660 Location: College Park, MD
|
Posted: Fri Nov 23, 2007 4:39 pm Post subject: Iconified TextList - The making of |
|
|
What you will learn: You will learn how to create your own ListAdapter: IconifiedListAdapter
Problems/Questions: Write it right below...
Difficulty: 1.5 of 5
What it will look like:
Description:
The app (screenshot above) is created with the following simple code. So that is what we finally want to reach:
| Java: | IconifiedTextListAdapter itla = new IconifiedTextListAdapter(this);
// Add four items
itla.addItem(new IconifiedText(
"Surf Web", getResources().getDrawable(R.drawable.favicon)));
itla.addItem(new IconifiedText(
"Report Bug", getResources().getDrawable(R.drawable.bug)));
itla.addItem(new IconifiedText(
"Speak Spanish", getResources().getDrawable(R.drawable.locale)));
itla.addItem(new IconifiedText(
"Vidoop", getResources().getDrawable(R.drawable.vidoop)));
// Display it
setListAdapter(itla); |
We simply create an: IconifiedTextListAdapter, throw some String+Drawable into and 'display it. To use such awesome simple code, we need to do some work.
1. Lets start with the very Base: The IconifiedText.java which is a pretty small class, which only contains a simply constructor and some getters & setters. It is only a class that combines a String and a Drawable(Icon), nothing special!
| Java: | public class IconifiedText{
private String mText = "";
private Drawable mIcon;
private boolean mSelectable = true;
public IconifiedText(String text, Drawable bullet) {
mIcon = bullet;
mText = text;
}
// ...
} |
2. Now we take a look at the IconifiedTextListAdapter.java which consists of about 50 Lines of Code, but does not much. It basically is a storage for a list of IconifiedTexts, to which you can "add(IconifiedText);", and that passes through some functions to the elements of the IconifiedText-List, like 'getItem(int position)' or 'isSelectable(int position)'.
Being an (specialized) Adapter , the second thing to provide a function through which one can access the views (all the things) it contains:
| Java: | /** @param convertView The old view to overwrite, if one is passed
* @returns a IconifiedTextView that holds wraps around an IconifiedText */
public View getView(int position, View convertView, ViewGroup parent) {
IconifiedTextView btv;
if (convertView == null) {
btv = new IconifiedTextView(mContext, mItems.get(position));
} else { // Reuse/Overwrite the View passed
// We are assuming(!) that it is castable!
btv = (IconifiedTextView) convertView;
btv.setText(mItems.get(position).getText());
btv.setIcon(mItems.get(position).getIcon());
}
return btv;
} |
That was probably also not too hard to understand (if so, ask for explanation below).
3.The IconifiedTextView is also not too hard to understand.
It extends LinearLayout.
Lets remember, that GUIs in Android are nested. ( A view, can contain a View, can contain a View, can contain a View, can contain a View, can contain a View...)
So it will be no problem, that our IconifiedTextView itself consists of two more Views, aIconView and a TextView.
The IconifiedTextView does it own setup in the Constructor:
| Java: | public IconifiedTextView(Context context, IconifiedText aIconifiedText) {
super(context);
/* First Icon and the Text to the right (horizontal),
* not above and below (vertical) */
this.setOrientation(HORIZONTAL);
mIcon = new ImageView(context);
mIcon.setImageDrawable(aIconifiedText.getIcon());
// left, top, right, bottom
mIcon.setPadding(0, 2, 5, 0); // 2px up, 5px to the right
/* At first, add the Icon to ourself
* (! we are extending LinearLayout) */
addView(mIcon, new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
mText = new TextView(context);
mText.setText(aIconifiedText.getText());
/* Now the text (after the icon) */
addView(mText, new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
} |
So thats it =). You successfully created an IconifiedTextList(Adapter)
The full source:
Icons (res/drawable/*.png) used in Demo App
'src/your_package_structure/TestLayout.java'
| Java: | /* $Id: TestLayout.java 57 2007-11-21 18:31:52Z steven $
*
* Copyright 2007 Steven Osborn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.anddev.android.testproject;
import android.app.ListActivity;
import android.os.Bundle;
public class TestLayout extends ListActivity {
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
IconifiedTextListAdapter itla = new IconifiedTextListAdapter(this);
// Add four items
itla.addItem(new IconifiedText(
"Surf Web", getResources().getDrawable(R.drawable.favicon)));
itla.addItem(new IconifiedText(
"Report Bug", getResources().getDrawable(R.drawable.bug)));
itla.addItem(new IconifiedText(
"Speak Spanish", getResources().getDrawable(R.drawable.locale)));
itla.addItem(new IconifiedText(
"Vidoop", getResources().getDrawable(R.drawable.vidoop)));
// Display it
setListAdapter(itla);
}
} |
'src/your_package_structure/IconifiedText.java'
| Java: | /*
* Copyright 2007 Steven Osborn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org. anddev. android. testproject;
import android. graphics. drawable. Drawable;
/** @author Steven Osborn - http://steven.bitsetters.com */
public class IconifiedText implements Comparable<IconifiedText> {
private String mText = "";
private Drawable mIcon;
private boolean mSelectable = true;
public IconifiedText (String text, Drawable bullet ) {
mIcon = bullet;
mText = text;
}
public boolean isSelectable () {
return mSelectable;
}
public void setSelectable (boolean selectable ) {
mSelectable = selectable;
}
public String getText () {
return mText;
}
public void setText (String text ) {
mText = text;
}
public void setIcon (Drawable icon ) {
mIcon = icon;
}
public Drawable getIcon () {
return mIcon;
}
/** Make IconifiedText comparable by its name */
@Override
public int compareTo (IconifiedText other ) {
if(this. mText != null)
return this. mText. compareTo(other. getText());
else
throw new IllegalArgumentException();
}
}
|
'src/your_package_structure/IconifiedTextView.java'
| Java: | /* $Id: BulletedTextView.java 57 2007-11-21 18:31:52Z steven $
*
* Copyright 2007 Steven Osborn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.anddev.android.testproject;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class IconifiedTextView extends LinearLayout {
private TextView mText;
private ImageView mIcon;
public IconifiedTextView(Context context, IconifiedText aIconifiedText) {
super(context);
/* First Icon and the Text to the right (horizontal),
* not above and below (vertical) */
this.setOrientation(HORIZONTAL);
mIcon = new ImageView(context);
mIcon.setImageDrawable(aIconifiedText.getIcon());
// left, top, right, bottom
mIcon.setPadding(0, 2, 5, 0); // 5px to the right
/* At first, add the Icon to ourself
* (! we are extending LinearLayout) */
addView(mIcon, new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
mText = new TextView(context);
mText.setText(aIconifiedText.getText());
/* Now the text (after the icon) */
addView(mText, new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
public void setText(String words) {
mText.setText(words);
}
public void setIcon(Drawable bullet) {
mIcon.setImageDrawable(bullet);
}
} |
'src/your_package_structure/IconifiedTextListAdapter.java'
| Java: | /* $Id: BulletedTextListAdapter.java 57 2007-11-21 18:31:52Z steven $
*
* Copyright 2007 Steven Osborn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org. anddev. android. testproject;
import java. util. ArrayList;
import java. util. List;
import android. content. Context;
import android. view. View;
import android. view. ViewGroup;
import android. widget. BaseAdapter;
/** @author Steven Osborn - http://steven.bitsetters.com */
public class IconifiedTextListAdapter extends BaseAdapter {
/** Remember our context so we can use it when constructing views. */
private Context mContext;
private List<IconifiedText> mItems = new ArrayList<IconifiedText> ();
public IconifiedTextListAdapter (Context context ) {
mContext = context;
}
public void addItem (IconifiedText it ) { mItems. add(it ); }
public void setListItems (List<IconifiedText> lit ) { mItems = lit; }
/** @return The number of items in the */
public int getCount () { return mItems. size(); }
public Object getItem (int position ) { return mItems. get(position ); }
public boolean areAllItemsSelectable () { return false; }
public boolean isSelectable (int position ) {
try{
return mItems. get(position ). isSelectable();
}catch (IndexOutOfBoundsException aioobe ){
return super. isSelectable(position );
}
}
/** Use the array index as a unique id. */
public long getItemId (int position ) {
return position;
}
/** @param convertView The old view to overwrite, if one is passed
* @returns a IconifiedTextView that holds wraps around an IconifiedText */
public View getView (int position, View convertView, ViewGroup parent ) {
IconifiedTextView btv;
if (convertView == null) {
btv = new IconifiedTextView (mContext, mItems. get(position ));
} else { // Reuse/Overwrite the View passed
// We are assuming(!) that it is castable!
btv = (IconifiedTextView ) convertView;
btv. setText(mItems. get(position ). getText());
btv. setIcon(mItems. get(position ). getIcon());
}
return btv;
}
} |
Regards,
plusminus _________________
Download my apps  Please remember, that this board is give & take 
| Android Development Community / Tutorials
Last edited by plusminus on Fri Dec 28, 2007 2:44 pm; edited 4 times in total |
|
| Back to top |
|
 |
|
|
 |
lordhong Developer

Joined: 22 Nov 2007 Posts: 41 Location: New York
|
Posted: Wed Nov 28, 2007 5:11 am Post subject: |
|
|
this is great! based on your code, i build a list w/ 3 views on one item:
checkbox, icon, and string
and it looks great!
there's one problem for the checkbox, i have some of them pre-selected/checked, but on application start, the ones that should have been checked are not displayed as checked. when i scroll down the list, and then come back up the list, they show up as checked. looks like somewhere i'm missing something like invalidate() after making the checkbox checked?
here's the code snippet:
| Java: |
// basically have 3 views for one ImageItem
// the isChecked determines checkbox's initial state, checked or not checked
public ImageItemView(Context context, String title, Drawable drawable, boolean isChecked) {
super(context);
this.setOrientation(HORIZONTAL);
checkbox = new CheckBox(context);
checkbox.setChecked(isChecked);
// missing something invalidate() here??
addView(checkbox, new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
image = new ImageView(context);
image.setImageDrawable(drawable);
// left, top, right, bottom
image.setPadding(0, 2, 5, 2);
addView(image, new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
text = new TextView(context);
text.setText(title);
addView(text, new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
|
in the activity class (main entry point), i init. the list adpater for ImageItem:
| Java: |
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
ImageItemArrayAdapter adapter = new ImageItemArrayAdapter(this);
Resources res = this.getResources();
// checked
adapter.addItem(new ImageItem("Home", res.getDrawable(R.drawable.sliderhouse), true));
// not checked
adapter.addItem(new ImageItem("Bar", res.getDrawable(R.drawable.bar), false));
// not checked
adapter.addItem(new ImageItem("Book Store", res.getDrawable(R.drawable.bookstore), false));
// checked
adapter.addItem(new ImageItem("Cafe", res.getDrawable(R.drawable.cafe), true));
setListAdapter(adapter);
...
|
please help, not sure where went wrong... |
|
| Back to top |
|
 |
plusminus Site Admin


Joined: 14 Nov 2007 Posts: 2660 Location: College Park, MD
|
Posted: Wed Nov 28, 2007 10:06 am Post subject: |
|
|
Hey lordhong,
Nice upgrade =)
You could try to loop through all Views at the end of the onCreate()-method and invalidate(); them. Like:
| Java: | // Brain to Code - NOT TESTED
public void onCreate (Bundle icicle ) {
super. onCreate(icicle );
ImageItemArrayAdapter adapter = new ImageItemArrayAdapter (this);
Resources res = this. getResources();
// add one items
adapter. addItem(new ImageItem ("Home", res. getDrawable(R. drawable. sliderhouse), true));
// add some more items...
// ...
setListAdapter (adapter );
for(int i = 0; i < adapter. getCount(); i++ ){
adapter. getView(i, null, null). invalidate();
}
} |
Let us know if it worked.
I'll have a closer look at it, when I'm back home from university.
Regards,
plusminus _________________
Download my apps  Please remember, that this board is give & take 
| Android Development Community / Tutorials |
|
| Back to top |
|
 |
lordhong Developer

Joined: 22 Nov 2007 Posts: 41 Location: New York
|
Posted: Fri Nov 30, 2007 4:31 am Post subject: |
|
|
unfortunately this does not work... i guess the invalidate does not cause the checkboxes to re-paint... |
|
| Back to top |
|
 |
plusminus Site Admin


Joined: 14 Nov 2007 Posts: 2660 Location: College Park, MD
|
Posted: Fri Nov 30, 2007 7:56 am Post subject: |
|
|
hmhmhm...
This sucks. It has to work, I should do some code... later
Regards,
plusminus _________________
Download my apps  Please remember, that this board is give & take 
| Android Development Community / Tutorials |
|
| Back to top |
|
 |
Soul_Est Freshman

Joined: 29 Nov 2007 Posts: 2
|
Posted: Mon Dec 10, 2007 3:06 pm Post subject: A little clarification |
|
|
I'd first like to say thanks for setting up these wonderful forums plusminus! They have helped me immensely when it came to understanding how to read and understand Java and other OOP languages altogether. I was planning on producing a pretty advanced media player for the platform but needed to figure out how to do the basics. The tutorials on the Google's website and Sun's website only thought me so much. I tried Steve Osborn's website, but alas I got page loading problems due to the Opera browser's rendering engine (and it had a nice simple tabs example tutorial too). When I come to anddev.org, I'm amazed at how much I understand the code just by reading through it a few times. Due to the tutorial "Iconified TextList - The Making Of" and others, I can now proceed with producing that media player...and produce a tutorial for a more advanced media player hopefully in about a month.
I was reading this piece of code and eventhough I can understand some of it, I'm having trouble understanding how convertView and btv actually work to the ends that this program is going to achieve. Would anyone be able to help me out on this?
| Java: | /** @param convertView The old view to overwrite, if one is passed
* @returns a IconifiedTextView that holds wraps around an IconifiedText */
public View getView(int position, View convertView, ViewGroup parent) {
IconifiedTextView btv;
if (convertView == null) {
btv = new IconifiedTextView(mContext, mItems.get(position));
} else { // Reuse/Overwrite the View passed
// We are assuming(!) that it is castable!
btv = (IconifiedTextView) convertView;
btv.setText(mItems.get(position).getText());
btv.setIcon(mItems.get(position).getIcon());
}
return btv;
} |
P.S.:Thanks again for setting up these forums plusminus! You have produced an indispensable resource for all levels of Java developers trying to produce applications for the platform. |
|
| Back to top |
|
 |
|
|
 |
plusminus Site Admin


Joined: 14 Nov 2007 Posts: 2660 Location: College Park, MD
|
Posted: Mon Dec 10, 2007 7:59 pm Post subject: |
|
|
Hello Soul_Est,
the following is a valid (simplified) replacement for the original one.
| Java: |
/** @param convertView The old view to overwrite, if one is passed
* @returns a IconifiedTextView that holds wraps around an IconifiedText */
public View getView(int position, View convertView, ViewGroup parent) {
return new IconifiedTextView(mContext, mItems.get(position));
} |
I (or better Steven Osborn) designed this, to be a more "good-style" solution.
In some case there is probably no need for new created Views, as an "old" one (convertView) can be reused.
Regards,
plusminus _________________
Download my apps  Please remember, that this board is give & take 
| Android Development Community / Tutorials |
|
| Back to top |
|
 |
GodsMoon Developer

Joined: 10 Dec 2007 Posts: 26
|
Posted: Tue Dec 11, 2007 11:49 pm Post subject: mSelectable = false |
|
|
First: Thanks for posting this. It is exactly what I was looking for.
I'm planning on having buttons in my list and don't want the actual rows selectable. However, I do want the buttons associated with the other data on the same row. (If you can think of a better way to do this let me know)
My question is this: when I declare mSelectable as false
| Java: | private boolean mSelectable = false; |
I get the following error: An error has occurred in process <my-package>.java.lang.IndexOutOfBoundsException
When I press UP on the 5-way pad. Also, pressing down does not select the other buttons on the screen.
Is this a problem with focus? Or what am I doing wrong?
Thank for you help |
|
| Back to top |
|
 |
plusminus Site Admin


Joined: 14 Nov 2007 Posts: 2660 Location: College Park, MD
|
Posted: Tue Dec 11, 2007 11:54 pm Post subject: |
|
|
Hello GodsMoon,
digg into the debugger. On which line is the exception thrown
I will have a look at my source tomorrow evening, because tomorrow there is a test at university
Regards,
plusminus _________________
Download my apps  Please remember, that this board is give & take 
| Android Development Community / Tutorials |
|
| Back to top |
|
 |
plusminus Site Admin


Joined: 14 Nov 2007 Posts: 2660 Location: College Park, MD
|
|
| Back to top |
|
 |
GodsMoon Developer

Joined: 10 Dec 2007 Posts: 26
|
Posted: Thu Dec 13, 2007 9:13 pm Post subject: kinda works... |
|
|
Thanks! know I don't get the error.
However, that makes everything unselectable. Even the other buttons outside the List Adapter, well at least, they are not selectable with the 5-way pad. As soon as I click any of the buttons with the mouse Everything is selectable again even items in the list that are explicitly set to not be selectable.
Almost as if the list adapter sets the selectable for the whole activity and clicking any of the buttons with the mouse sets it to true.
Any ideas? Could this be a bug?
thanks again. |
|
| Back to top |
|
 |
udi Freshman

Joined: 14 Dec 2007 Posts: 6 Location: Austin TX
|
Posted: Fri Dec 14, 2007 10:21 pm Post subject: cut and paste error |
|
|
very nice tutorial, thank you.
minor nit: the method IsSelectable() on IconifiedText seems to be a cut and paste from IconifiedTextListAdapter. |
|
| Back to top |
|
 |
plusminus Site Admin


Joined: 14 Nov 2007 Posts: 2660 Location: College Park, MD
|
Posted: Fri Dec 14, 2007 11:53 pm Post subject: |
|
|
yes, I replaced the issue from 3 posts above one the right && on the wrong position
Thx for mentioning
Fixed
Best Regards,
plusminus _________________
Download my apps  Please remember, that this board is give & take 
| Android Development Community / Tutorials |
|
| Back to top |
|
 |
udi Freshman

Joined: 14 Dec 2007 Posts: 6 Location: Austin TX
|
Posted: Mon Dec 17, 2007 10:50 pm Post subject: |
|
|
| plusminus wrote: | hmhmhm...
This sucks. It has to work, I should do some code... later
Regards,
plusminus |
thnx again for the helpful tutorial.
it seems that if you accumulated IconifiedTextView rather than IconifiedText in the list of the adapter it would make the code somewhat simpler. you can call the constructor of IconifiedTextView in addItem(IconfiedText it) as follows:
| Java: | public void addItem(IconifiedText it) {
_items.add(new IconifiedTextView(_context, it));
} |
that would reduce getView to:
| Java: | public View getView(int position, View convertView, ViewGroup parent) {
return _items.get(position);
} |
/udi |
|
| Back to top |
|
 |
adnan1146 Freshman

Joined: 09 Jan 2008 Posts: 4
|
Posted: Thu Jan 10, 2008 11:38 am Post subject: |
|
|
| plusminus wrote: | Hey lordhong,
Nice upgrade =)
You could try to loop through all Views at the end of the onCreate()-method and invalidate(); them. Like:
| Java: | // Brain to Code - NOT TESTED
public void onCreate (Bundle icicle ) {
super. onCreate(icicle );
ImageItemArrayAdapter adapter = new ImageItemArrayAdapter (this);
Resources res = this. getResources();
// add one items
adapter. addItem(new ImageItem ("Home", res. getDrawable(R. drawable. sliderhouse), true));
// add some more items...
// ...
setListAdapter (adapter );
for(int i = 0; i < adapter. getCount(); i++ ){
adapter. getView(i, null, null). invalidate();
}
} |
Let us know if it worked.
I'll have a closer look at it, when I'm back home from university.
Regards,
plusminus |
Hi plusminus
I have also modified the iconified list to have few checkboxes,text views and imagesviews, but I am facing the similar problem of list refresh after performing some action. If you could help in this regard, and write some code to refresh the list.
I also tried the code you written before using invalidate(); |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You can download files in this forum
|
© 2007, Android Development Community
All rights reserved.
Powered by phpBB.
|