Lesson 5 List-Based Widgets:: Lists, Grids, and Scroll Views
Lesson 5 List-Based Widgets:: Lists, Grids, and Scroll Views
List-Based Widgets:
Lists, Grids, and Scroll Views
Victor Matos
Cleveland State University
Portions of this page are reproduced from work created and shared by Google and used according to terms
described in the Creative Commons 3.0 Attribution License.
List-Based Widgets
GUI Design for Selection Making
• RadioButtons and CheckButtons are widgets suitable for selecting options
offered by a small set of choices. They are intuitive and uncomplicated;
however they occupy a permanent space
on the GUI (which is not a problem when
only a few of them are shown)
• When the set of values to choose from is large, other Android List-Based
Widgets are more appropriate.
5-2
List-Based Widgets
Showing a large set of choices on the GUI
DATA
Raw data Formatted
& bound
data
DATA
ADAPTER
5-4
List-Based App = ListView + Data + DataAdapter
ArrayAdapter (A Data Beautifier)
• An ArrayAdapter<T> accepts for input an array (or ArrayList) of objects
of some arbitrary type T.
5-5
List-Based App = ListView + Data + DataAdapter
Output: ‘Pretty’ GUI
textviews…
Array Adapter
object n.toString()
5-6
List-Based App = ListView + Data + DataAdapter
Using the ArrayAdapter<String> Class
String[] items = { "Data-0", "Data-1", "Data-2", "Data-3",
"Data-4", "Data-5", "Data-6", "Data-7" };
Parameters:
1. The current activity’s context (this)
2. The TextView layout indicating how an individual row should be
written ( android.R.id.simple_list_item_1 ).
3. The actual data source (array or Java.List containing items to be
shown).
5-7
Using ListActivity + ArrayAdapter
Example1A: ListView showing a simple list (plain text)
Assume a large collection of input data items is held in a String[] array.
Each row of the ListView must show a line of text taken from the array.
In our example, when the user makes a selection, you must display on a
TextView the selected item and its position in the list.
5-8
Using ListActivity + ArrayAdapter
Example1A: Layout
<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"
android:orientation="vertical">
Pay attention to the use of predefined
Android components:
<TextView @android:id/list
android:id="@+id/txtMsg"
android:layout_width="match_parent" @android:id/empty
android:layout_height="wrap_content"
android:background="#ffffff00" See Appendix A for a description of
android:text="Using ListViews..."
android:textSize="16sp" /> @android:id/list
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
Android’s built-in list layout
android:layout_height="match_parent" >
</ListView>
<TextView
android:id="@android:id/empty" Used for empty lists
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffff0000"
android:text="empty list" />
</LinearLayout>
5-9
Using ListActivity + ArrayAdapter
Example1A: MainActivity ( using a ListActivity ! )
package csu.matos;
CAUTION:
import ... A ListActivity is not a “plain”
Activity. It is bound to a built-in
public class ListViewDemo extends ListActivity { ListView called @android:id/list
TextView txtMsg;
...
<ListView Fragment already defined in
android:id="@android:id/list" Layout: activity_main.xml
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
...
5 - 10
Using ListActivity + ArrayAdapter
Example1A: MainActivity ( using a ListActivity ! )
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
List
setContentView(R.layout.activity_main);
adapter
setListAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
items));
5 - 11
Using ListActivity + ArrayAdapter
Example1A: MainActivity ( using a ListActivity ! )
Selection seen
by the listener
Background
flashes blue to
acknowledge
the users’s
selection
1. Open the AndroidManifest.xml file. Under the <Application> tag look for
the clause android:theme="@style/AppTheme"
5 - 15
Using Activity + ArrayAdapter
Example1B: Using Activity & ArrayAdapter
• You may use a common Activity class instead of a ListActivity.
• The Layout below uses a ListView identified as @+id/my_list (instead
of @android:id/list used in the previous Example1).
<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"
android:orientation="vertical" >
<TextView
android:id="@+id/txtMsg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff00"
android:text="Using ListViews..."
android:textSize="16sp" />
<ListView
android:id="@+id/my_list"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</LinearLayout>
5 - 16
Using Activity + ArrayAdapter
Example1B: Instead of using a ListActivity (as we did on the previous
example) we now employ a regular Android Activity. Observe that you
must ‘wired-up’ the ListView to a Java proxy, and later bind it to an Adapter.
Example 1B – MainActivity 1 of 2
public class ListViewDemo2 extends Activity {
String[] items = { "Data-0", "Data-1", "Data-2", "Data-3",
"Data-4", "Data-5", "Data-6", "Data-7" };
ListView myListView;
TextView txtMsg;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myListView = (ListView) findViewById(R.id.my_list);
txtMsg.setText(text);
}
});
To provide a listener to the ListView control add the fragment above to the
onCreate method.
5 - 18
Using Activity + ArrayAdapter
Example 1B – MainActivity 2 of 2
5 - 19
Using Activity + ArrayAdapter
Example1C: Custom ListView
You may want to modify the ListView control to use your
own GUI design. For instance, you may replace
android.R.layout.simple_list_item_1 with
R.layout.my_custom_text.
Where my_custom_text is the Layout specification listed below (held in the
res/layout folder). It defines how each row is to be shown.
Note: As of SDK4.0 a TextView could also include an image (For example .setDrawableLeft(some_image) )
5 - 20
Using Activity + ArrayAdapter
Example1C: Custom ListView
You may also create the ArrayAdapter with more
parameters. For instance, the following statement:
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
getApplication(),
R.layout.my_custom_line3,
R.id.my_custom_textview3,
data );
Defines a custom list and textview layout to show the
contents of the data array.
<!-- my_custom_line3 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="6dp" >
<TextView
android:id="@+id/my_custom_textview3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#220000ff"
android:padding="1dp"
android:textColor="#ffff0000"
android:textSize="35sp" />
</LinearLayout> 5 - 21
Using android.R.layout.simple_list_item_2
22
The Spinner Widget
• Spinners have the same functionality of a ListView but take less screen
space.
5 - 23
Example2: Using the Spinner Widget
Example 2. A list of options named ‘Data-0’, ‘Data-1’, ‘Data-2’ and so on, should
be displayed when the user taps on the ‘down-arrow’ portion of the spinner.
3. Selected
value
1. Click Drop-
down button
<TextView
android:id="@+id/txtMsg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff00"
android:text="@string/hello_world" />
<Spinner
android:id="@+id/spinner1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
5 - 25
Using the Spinner Widget
Example2: Spinner Demo - MainActivity 1 of 2
public class MainActivity extends Activity
implements AdapterView.OnItemSelectedListener{
// GUI objects
TextView txtMsg;
Spinner spinner;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtMsg = (TextView) findViewById(R.id.txtMsg);
5 - 26
Using the Spinner Widget
Example2: Spinner Demo - MainActivity 2 of 2
}
// next two methods implement the spinner's listener
@Override
public void onItemSelected(AdapterView<?> parent, View v, int position,
long id) {
// echo on the textbox the user's selection
txtMsg.setText(items[position]);
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO do nothing – needed by the interface
5 - 27
The GridView Widget
GridView
GridView is a ViewGroup that
displays items in a
two-dimensional, scrollable grid.
5 - 28
The GridView Widget
GridView: Useful Properties
Some properties used to determine the number of columns and their sizes:
• android:numColumns
indicates how many columns to show. When used with option “auto_fit”,
Android determines the number of columns based on available space and
the properties listed below.
• android:columnWidth
column width in dips.
• android:stretchMode
indicates how to modify image size when there is available space not
taken up by columns or spacing .
5 - 29
The GridView Widget
GridView: Fitting the View to the Screen
Suppose the screen is 320 (dip) pixels wide, and we have
The user would see three columns taking 310 pixels (three columns of 100
pixels and two separators of 5 pixels).
5 - 30
The GridView Widget
Example3A: GridView Demo - Layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="2dp"
tools:context=".MainActivity" >
<TextView
android:id="@+id/txtMsg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ff0000ff"
android:textSize="24sp"
android:textStyle="bold"
android:textColor="#ffffffff"
android:padding="2dip" />
<GridView
android:id="@+id/grid"
android:background="#77ffff00"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:verticalSpacing="5dip"
android:horizontalSpacing="5dip"
android:numColumns="auto_fit"
android:columnWidth="100dip"
android:stretchMode="spacingWidth" />
</LinearLayout>
5 31
- 31
The GridView Widget
Example3A: GridView Demo – MainActivity 1 of 2
TextView txtMsg;
5 - 32
The GridView Widget
Example3A: GridView Demo – MainActivity 2 of 2
GridView grid = (GridView) findViewById(R.id.grid);
grid.setAdapter(adapter);
grid.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> container, View v,
int position, long id) {
txtMsg.setText(items[position]);
}
});
}//onCreate
}// class
5 - 33
The AutoComplete TextView Widget
AutoComplete TextView
• An AutoComplete box is a more specialized version of the EditText view.
• Characters typed so far are compared with the beginning of words held in
a user-supplied list of suggested values.
• The user can choose from the suggestion list or complete typing the
word.
5 - 34
The AutoComplete TextView Widget
Example 4.
A list of selected
words beginning
with “wor” or “set”
Tap to select
is being watched.
this option
If any of these
prefixes (3 letters)
are entered the
TextWatcher
mechanism shows
an option list.
5 - 35
The AutoComplete TextView Widget
Example4: AutoComplete Demo - Layout
<RelativeLayout 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" >
<TextView
android:id="@+id/txtMsg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#ffffffff"
android:background="#ff0000ff" >
</TextView>
<AutoCompleteTextView
android:id="@+id/autoCompleteTextView1"
android:hint="type here..."
android:completionThreshold="3" Wait 3 chars to work
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/txtMsg"
android:layout_marginTop="15dp"
android:ems="10" />
</RelativeLayout> 5 - 36
The AutoComplete TextView Widget
Example4: AutoComplete Demo – MainActivity 1 of 2
TextView txtMsg;
AutoCompleteTextView txtAutoComplete;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
5 - 37
The AutoComplete TextView Widget
Example4: AutoComplete Demo – MainActivity 2 of 2
txtAutoComplete.setAdapter(new ArrayAdapter<String>(
this,
android.R.layout.simple_list_item_single_choice,
items));
}//onCreate
}//class
5 38
- 38
The HorizontalScrollView Widget
5 - 40
The HorizontalScrollView Widget
Example5: How to make a thumbnail ?
• Option-1. The 100x100 thumbnails shown below were made visiting the
site: http://makeathumbnail.com
• Option-2. Upload individual images to the Android_Asset_Studio_Tool
http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html
5 - 41
The HorizontalScrollView Widget
Example5: Populating The HorizontalScrollView Widget
1. Our HorizontalScrollView will expose a list of frames, each containing an
icon and a caption below the icon.
3. After the current frame is filled with data, it will be added to the growing
set of views hosted by the scrollViewgroup container (scrollViewgroup is
nested inside the horizontal scroller).
5 - 42
The HorizontalScrollView Widget
Example5: HorizontalScrollView Demo – Layout 1 of 2
<?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="wrap_content"
android:background="#ffffffff"
android:orientation="vertical"
android:padding="2dp" >
<TextView
android:id="@+id/txtMsg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ff00ff00"
android:text="scroll and click to select ..."
android:textAppearance="?android:attr/textAppearanceLarge" />
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#44aaaaaa" >
<LinearLayout
android:id="@+id/viewgroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dip" >
</LinearLayout>
</HorizontalScrollView> 5 - 43
The HorizontalScrollView Widget
Example5: HorizontalScrollView Demo – Layout 2 of 2
<ImageView
android:id="@+id/imageSelected"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="2" />
</LinearLayout>
5 - 44
The HorizontalScrollView Widget
Example5: Layout: frame_icon_caption.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="wrap_content"
android:orientation="vertical" >
<ImageView
android:id="@+id/icon"
android:layout_width="80dp"
android:layout_height="80dp"
android:paddingLeft="2dp"
android:paddingRight="2dp"
android:paddingTop="2dp"
android:src="@drawable/ic_launcher" />
<TextView
android:id="@+id/caption"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#55ffff00"
android:textSize="20sp" />
</LinearLayout>
This layout will be used by an inflater to dynamically create new views. These views will
be added to the linear layout contained inside the HorizontalScrollerView. 5 - 45
The HorizontalScrollView Widget
Example5: App’s Structure - Eclipse’s Package Explorer
5 - 46
The HorizontalScrollView Widget
Example5: HorizontalScrollView Demo – MainActivity 1 of 3
public class MainActivity extends Activity {
//GUI controls
TextView txtMsg;
ViewGroup scrollViewgroup;
//each frame in the HorizontalScrollView has [icon, caption]
ImageView icon;
TextView caption;
//frame-captions
String[] items = { "Data-1", "Data-2", "Data-3", "Data-4", "Data-5",
"Data-3", "Data-7", "Data-8", "Data-9", "Data-10", "Data-11",
"Data-12", "Data-13", "Data-14", "Data-15" };
//frame-icons ( 100X100 thumbnails )
Integer[] thumbnails = { R.drawable.pic01_small, R.drawable.pic02_small,
R.drawable.pic03_small, R.drawable.pic04_small,
R.drawable.pic05_small, R.drawable.pic06_small,
R.drawable.pic07_small, R.drawable.pic08_small,
R.drawable.pic09_small, R.drawable.pic10_small,
R.drawable.pic11_small, R.drawable.pic12_small,
R.drawable.pic13_small, R.drawable.pic14_small,
R.drawable.pic15_small };
//large images to be shown (individually) in an ImageView
Integer[] largeImages = { R.drawable.pic01_large,
R.drawable.pic02_large, R.drawable.pic03_large,
R.drawable.pic04_large, R.drawable.pic05_large,
R.drawable.pic06_large, R.drawable.pic07_large,
R.drawable.pic08_large, R.drawable.pic09_large,
R.drawable.pic10_large, R.drawable.pic11_large,
R.drawable.pic12_large, R.drawable.pic13_large,
5 - 47
R.drawable.pic14_large, R.drawable.pic15_large };
The HorizontalScrollView Widget
Example5: HorizontalScrollView Demo – MainActivity 2 of 3
//large image frame for displaying high-quality selected image
ImageView imageSelected;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//bind GUI controls to Java classes
txtMsg = (TextView) findViewById(R.id.txtMsg);
imageSelected = (ImageView) findViewById(R.id.imageSelected);
// this layout goes inside the HorizontalScrollView
scrollViewgroup = (ViewGroup) findViewById(R.id.viewgroup);
5 - 49
Image-Based GridViews (again…)
<TextView
android:id="@+id/txtSoloMsg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ff0000ff" />
<ImageView
android:id="@+id/imgSoloPhoto"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_gravity="center|fill"
android:layout_weight="2" />
<Button
android:id="@+id/btnSoloBack"
android:layout_width="100dip"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Back" />
</LinearLayout>
5 - 52
Using The GridView Widget to Show Images
Example6: App’s Structure – Eclipse’s Package Explorer
5 - 53
Using The GridView Widget to Show Images
Example6: MainActivity 1 of 3
public class MainActivity extends Activity implements OnItemClickListener {
//GUI control bound to screen1 (holding GidView)
GridView gridview;
//GUI controls bound to screen2 (holding single ImageView)
TextView txtSoloMsg;
ImageView imgSoloPhoto;
Button btnSoloBack;
// initialize array of smallImages (100x75 thumbnails)
Integer[] smallImages = { R.drawable.pic01_small,
R.drawable.pic02_small, R.drawable.pic03_small,
R.drawable.pic04_small, R.drawable.pic05_small,
R.drawable.pic06_small, R.drawable.pic07_small,
R.drawable.pic08_small, R.drawable.pic09_small,
R.drawable.pic10_small, R.drawable.pic11_small,
R.drawable.pic12_small, R.drawable.pic13_small,
R.drawable.pic14_small, R.drawable.pic15_small };
//initialize array of high-resolution images (1024x768)
Integer[] largeImages = { R.drawable.pic01_large,
R.drawable.pic02_large, R.drawable.pic03_large,
R.drawable.pic04_large, R.drawable.pic05_large,
R.drawable.pic06_large, R.drawable.pic07_large,
R.drawable.pic08_large, R.drawable.pic09_large,
R.drawable.pic10_large, R.drawable.pic11_large,
R.drawable.pic12_large, R.drawable.pic13_large,
R.drawable.pic14_large, R.drawable.pic15_large };
imgSoloPhoto.setImageResource( largeImages[position] );
5 - 55
Using The GridView Widget to Show Images
Example6: MainActivity 3 of 3
btnSoloBack.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// redraw the main screen showing the GridView
onCreate(myOriginalMemoryBundle);
}
});
}// showBigScreen
5 - 56
Using The GridView Widget to Show Images
Example6: Custom Adapter - MyImageAdapter 1 of 2
// This custom adapter populates the GridView with a visual
// representation of each thumbnail in the input data set.
// It also implements a method -getView()- to access
// individual cells in the GridView.
ImageView imageView;
} else {
imageView = (ImageView) convertView;
}
imageView.setImageResource(smallImages[position]);
return imageView;
}
}//MyImageAdapter
5 - 58
Using The GridView Widget to Show Images
Results generated by Example6 running on different devices
STEPS
1. Modify the layout activity_main.xml. Change the tag <GridView … to
<ListView. Leave the rest unchanged.
2. In the main Java class, replace each reference to the GridView type with ListView.
The new statements should be:
ListView gridview;
...
gridview = (ListView) findViewById(R.id.gridview);
3. In the custom Image adapter make the following change to indicate the new
imageView should be added to a ListView (instead than a GridView)
imageView.setLayoutParams(new ListView
.LayoutParams(100, 75) );
4. Keep the rest of the adapter code unchanged. 5 - 60
Using The GridView Widget to Show Images
Example6B:
An Experiment - Changing from GridView to ListView
The new app
should display the
following screens.
5 - 61
Using The Spinner Widget (again…)
This is a simple variation of the
previous example.
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ff0000ff"
android:text="Car selector"
android:textColor="#ffffffff"
android:textSize="20sp"
android:textStyle="bold" />
<Spinner
android:id="@+id/spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dip" />
</LinearLayout>
5 - 63
Using The Spinner Widget (again…)
Example7: Spinner Demo2 - Layout2 (solo_picture)
<?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:padding="3dp"
android:orientation="vertical" >
<TextView
android:id="@+id/txtSoloMsg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textColor="#FFFFFFFF"
android:padding="3dp"
android:background="#ff0000ff" />
<ImageView
android:id="@+id/imgSoloPhoto"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_gravity="center|fill"
android:layout_weight="2" />
<Button
android:id="@+id/btnBack"
android:layout_width="100dip"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Back" />
</LinearLayout>
5 - 64
Using The Spinner Widget (again…)
Example7: Spinner Demo2 - MainActivity 1 of 3
public class MainActivity extends Activity implements
AdapterView.OnItemSelectedListener {
// GUI controls in the main screen
Spinner spinner;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myStateInfo = savedInstanceState;
setContentView(R.layout.activity_main);
5 - 65
Using The Spinner Widget (again…)
Example7: Spinner Demo2 - MainActivity 2 of 3
spinner = (Spinner) findViewById(R.id.spinner);
spinner.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_dropdown_item,
items));
spinner.setOnItemSelectedListener(this);
}// onCreate
// display screen showing image of the selected car
private void showBigImage(int position) {
// show the selected picture as a single frame
setContentView(R.layout.solo_picture);
txtSoloMsg = (TextView) findViewById(R.id.txtSoloMsg);
imageSelectedCar = (ImageView) findViewById(R.id.imgSoloPhoto);
txtSoloMsg.setText("Car selected: car-" + position);
imageSelectedCar.setImageResource(carImageArray[position]);
5 - 66
Using The Spinner Widget (again…)
Example7: Spinner Demo2 - MainActivity 3 of 3
@Override
public void onNothingSelected(AdapterView<?> parent) {
// DO NOTHING - needed by the interface
}
5 - 67
ListView’s Recycler
68
Custom-made ListViews
Example8: Defining your own ListViews
• Android provides several predefined row layouts for displaying simple
lists (such as:
android.R.layout.simple_list_item_1,
android.R.layout.simple_list_item_2, etc ).
• In those cases, you should create your own subclass of a Data Adapter.
5 - 69
Custom-made ListViews
Example8: Create your own DataAdapter
In order to customize a Data Adapter, you need to:
1. Create a class extending the concrete ArrayAdapter class
2. Override its getView(), and
3. Construct (inflate) your rows yourself.
For each data
element supplied by
the adapter, the
method getView()
public class MyCustomAdapter extends ArrayAdapter{ returns its ‘visible’
View.
// class variables go here ...
public MyCustomAdapter(...) { }
}//MyCustomAdapter
5 - 70
Custom-made ListViews
Example8: Designing Custom-Rows
In our example each UI row will show an icon (on the left side) and text
following the icon to its right side.
Custom row
Icon Text
5 - 71
Custom-made ListViews
Example8: Designing Custom-Rows
5 - 72
Custom-made ListViews
Example8: Custom ListView Demo - App’s Structure
5 - 73
Custom-made ListViews
Example8: Layout1 – activity_main.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:padding="3dp"
android:orientation="vertical" >
<TextView
android:id="@+id/txtMsg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ff0000ff"
android:text="Your selection is ..."
android:textColor="#ffffffff"
android:textSize="24sp"
android:textStyle="bold" />
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</LinearLayout>
5 - 74
Custom-made ListViews
Example8: Layout2 – custom_row_icon_label.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="wrap_content"
android:orientation="horizontal" >
<ImageView
android:id="@+id/icon"
android:layout_width="100dp"
android:layout_height="75dp"
android:layout_marginRight="3dp"
android:src="@drawable/ic_launcher" />
<TextView
android:id="@+id/label"
android:layout_width="match_parent"
android:layout_height="75dp"
android:background="#22ffff00"
android:textSize="20sp" />
</LinearLayout>
5 - 75
Custom-made ListViews
Example8: Custom ListView Demo – MainActivity 1 of 3
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtMsg = (TextView) findViewById(R.id.txtMsg);
5 - 76
Custom-made ListViews
Example8: Custom ListView Demo – MainActivity 2 of 3
// the arguments of the custom adapter are:
// activityContex, layout-to-be-inflated, labels, icons
CustomIconLabelAdapter adapter = new CustomIconLabelAdapter(
this,
R.layout.custom_row_icon_label,
items,
thumbnails);
// bind intrinsic ListView to custom adapter
setListAdapter(adapter);
}//onCreate
}//class
5 - 77
Custom-made ListViews
Example8: Custom ListView Demo – MainActivity 3 of 3
class CustomIconLabelAdapter extends ArrayAdapter <String> {
Context context;
Integer[] thumbnails;
String[] items;
public CustomIconLabelAdapter( Context context, int layoutToBeInflated,
String[] items, Integer[] thumbnails) {
super(context, R.layout.custom_row_icon_label, items);
this.context = context;
this.thumbnails = thumbnails;
this.items = items;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
View row = inflater.inflate(R.layout.custom_row_icon_label, null);
TextView label = (TextView) row.findViewById(R.id.label);
ImageView icon = (ImageView) row.findViewById(R.id.icon);
label.setText(items[position]);
icon.setImageResource(thumbnails[position]);
return (row);
}
}// CustomAdapter 5 - 78
Custom-made ListViews
Example8: The LayoutInflater Class
5 - 81
Appendix A: Custom List supported by a BaseAdapter
Click
on
Click image
on
row
5 - 82
Appendix A: Custom List – ViewHolder Pattern
The figure below is from “Performance Tips for Android’s ListView” by Lucas Rocha
http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/ [Dec, 2014].
It shows a set of rows presented to the user inside a ListView container.
The strategy of reusing these scrapviews is known as the ViewHolder Design Pattern.
It cuts down on the number of times you have to inflate a row-layout and then get
access to its internal widgets by calling the ‘findViewById()’ method.
When reusing the scrapviews (made available as ‘convertView’) all you need to do is
move the appropriate data to the internal widgets and set their onClick listeners.
5 - 83
Appendix A: Custom List – activity_main.xml
Layout activity_main.xml shows a ViewList.
<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"
android:orientation="vertical"
android:padding="16dp" >
<ListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
5 - 84
Appendix A: Custom List – list_row_gui.xml (1)
Layout list_gui_row.xml shows a custom-made row holding two lines of text and two
images.
<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"
android:orientation="horizontal"
android:padding="16dp" >
<ImageView
android:id="@+id/rowImageView1"
android:layout_width="50dp"
android:layout_height="50dp"
android:contentDescription="@string/image_left"
android:src="@drawable/ic_pic_left" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="20dp"
android:layout_weight="2"
android:orientation="vertical" >
<TextView
android:id="@+id/rowTextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text1"
android:textAppearance="?android:attr/textAppearanceLarge" />
5 - 85
Appendix A: Custom List – list_row_gui.xml (2)
Layout list_gui_row.xml shows a custom-made row holding two lines of text and two
images.
<TextView
android:id="@+id/rowTextView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text2"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
<ImageView
android:id="@+id/rowImageView2"
android:layout_width="50dp"
android:layout_height="50dp"
android:contentDescription="@string/image_right"
android:src="@drawable/ic_launcher" />
</LinearLayout>
5 - 86
Appendix A: Custom List – MainActivity.java
The main activity exposes a ListView. A custom adapter is tied to the ListView. The
adapter gets a reference to a test ‘database’ and the custom row layout.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}//onCreate
5 - 87
Appendix A: Custom List – CustomBaseAdapter.java (1)
The getView method in this extended BaseAdapter inflates a supplied row layout, gets
access to its internal widgets, fills them with data and set listeners on some of them.
public class CustomBaseAdapter extends BaseAdapter {
Context context;
int layoutToBeInflated;
List<DATABASE.DbRecord> dbList;
@Override
public int getCount() {
return dbList.size();
}
@Override
public DATABASE.DbRecord getItem(int position) {
return dbList.get(position);
}
5 - 88
Appendix A: Custom List – CustomBaseAdapter.java (2)
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
5 - 89
Appendix A: Custom List – CustomBaseAdapter.java (3)
// plumbing - provide access to each widget in the inflated layout
// (two images & two lines of text)
holder = new MyViewHolder();
holder.textview1 = (TextView) row.findViewById(R.id.rowTextView1);
holder.textview2 = (TextView) row.findViewById(R.id.rowTextView2);
holder.imageview1 = (ImageView) row.findViewById(R.id.rowImageView1);
holder.imageview2 = (ImageView) row.findViewById(R.id.rowImageView2);
} else {
// row was already created- no need to inflate and invoke findViewById
// getTag() returns the object originally stored in this view
holder = (MyViewHolder) row.getTag();
}
// enter(or restore) data that goes in this frame (from database 'position')
DATABASE.DbRecord dbRec = getItem(position);
holder.textview1.setText(dbRec.text1);
holder.textview2.setText(dbRec.text2);
holder.imageview1.setImageResource(dbRec.img1);
holder.imageview2.setImageResource(R.drawable.ic_launcher);
5 - 90
Appendix A: Custom List – CustomBaseAdapter.java (4)
// EXTRA: individual listeners go here - if you need only a single
// listener for the entire row, put it into ActivityMain.
return row;
}// getView
5 - 91
Appendix A: Custom List – CustomBaseAdapter.java (5)
// A humble POJO holding references to GUI widgets that are part of rows
// shown by the list. They have already been made and their IDs are known,
// therefore there is no need to issue 'findViewById' calls again.
}// CustomMadeListener
5 - 92
Appendix A: Custom List – DATABASE.java (1)
public class DATABASE { // TEST DATABASE
public String[] text1array = { "data-item1-01", "data-item1-02",
"data-item1-03", "data-item1-04", "data-item1-05", "data-item1-06",
"data-item1-07", "data-item1-08", "data-item1-09", "data-item1-10",
"data-item1-11", "data-item1-12", "data-item1-13", "data-item1-14",
"data-item1-15" };
public String[] text2array = { "data-item2-01", "data-item2-02",
"data-item2-03", "data-item2-04", "data-item2-05", "data-item2-06",
"data-item2-07", "data-item2-08", "data-item2-09", "data-item2-10",
"data-item2-11", "data-item2-12", "data-item2-13", "data-item2-14",
"data-item2-15" };
public Integer[] icon1array = { csu.matos.custom2.R.drawable.pic01_small,
csu.matos.custom2.R.drawable.pic02_small,
csu.matos.custom2.R.drawable.pic03_small,
csu.matos.custom2.R.drawable.pic04_small,
csu.matos.custom2.R.drawable.pic05_small,
csu.matos.custom2.R.drawable.pic06_small,
csu.matos.custom2.R.drawable.pic07_small,
csu.matos.custom2.R.drawable.pic08_small,
csu.matos.custom2.R.drawable.pic09_small,
csu.matos.custom2.R.drawable.pic10_small,
csu.matos.custom2.R.drawable.pic11_small,
csu.matos.custom2.R.drawable.pic12_small,
csu.matos.custom2.R.drawable.pic13_small,
csu.matos.custom2.R.drawable.pic14_small,
csu.matos.custom2.R.drawable.pic15_small, };
5 - 93
Appendix A: Custom List – DATABASE.java (2)
public class DbRecord {
public String text1;
public String text2;
public Integer img1;
}// DATABASE
5 - 94
Appendix B: Different type of views in a list
In adapter implementation: set the number of
different views, set type for each view and inflate
the correct layout for the specific view type.
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public int getItemViewType(int position) {
if (messages.get(position).getUsername().equals("me"))
return 1;
else
return 0;
}
if (getItemViewType(i) == 0)
view = ((Activity)context).getLayoutInflater().inflate(R.layout.left_item_view,
viewGroup, false);
else
view = ((Activity)context).getLayoutInflater().inflate(R.layout.right_item_view,
viewGroup, false);
5 - 95