Android - Custom ListAdapter look more fancier
In this tutorial, we will update the layout of our ListView rows, so they show both the name and address of the restaurant, plus an icon indicating the type. Along the way, we will need to create our own custom ListAdapter to handle our row views and a RestaurantHolder to populate a row from a
restaurant.
The above code use hard-wire in the android.R.layout.simple_list_item_1 layout for now, and we get our Activity and model from LunchList itself.
Next we need to change our adapter data member to be a RestaurantAdapter, both where it is declared and where it is instantiated in onCreate(). Make these changes, then rebuild and reinstall the application and confirm it works as it did at the end of the previous tutorial.
For the type, we will use three icons, one for each specific type (sit down, take-out, delivery).
Note : You can use whatever icons you wish
The Icon will be located on : res/drawable/
To achieve this look, we use a nested pair of LinearLayout containers. Use the following XML as the basis for LunchList/res/layout/row.xml:
Modify RestaurantAdapter to look like the following:
To do this, add the following static inner class to LunchList:
Change getView() to look like the following:
By Mohd Zulkamal
NOTE : – If You have Found this post Helpful, I will appreciate if you can Share it on Facebook, Twitter and Other Social Media Sites. Thanks =)
restaurant.
Note : Please follow the Android Tutorial Post Here Before You Step On This Post.
Create a Stub Custom Adapter
Create a stub implementation of a RestaurantAdapter that will be where we put our logic for creating our own custom rows. That can look like this, implemented as an inner class of LunchList:class RestaurantAdapter extends ArrayAdapter<Restaurant> {
RestaurantAdapter() {
super(LunchList.this,
android.R.layout.simple_list_item_1,model);
}
}
The above code use hard-wire in the android.R.layout.simple_list_item_1 layout for now, and we get our Activity and model from LunchList itself.
Next we need to change our adapter data member to be a RestaurantAdapter, both where it is declared and where it is instantiated in onCreate(). Make these changes, then rebuild and reinstall the application and confirm it works as it did at the end of the previous tutorial.
Design The List Row
Design a row that incorporates all three of our model elements: name, address, and type.For the type, we will use three icons, one for each specific type (sit down, take-out, delivery).
Note : You can use whatever icons you wish
The Icon will be located on : res/drawable/
NOTE: If your project has no res/drawable/ directory, but does have res/drawable-ldpi/ and others with similar suffixes, rename res/drawablemdpi/ to res/drawable/ directory for use in this project, and delete the other res/drawable-* directories.
Example Custom List
To achieve this look, we use a nested pair of LinearLayout containers. Use the following XML as the basis for LunchList/res/layout/row.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"Some of the unusual attributes applied in this layout include:
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="4dip"
>
<ImageView android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_marginRight="4dip"
/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical"
android:textStyle="bold"
android:singleLine="true"
android:ellipsize="end"
/>
<TextView android:id="@+id/address"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical"
android:singleLine="true"
android:ellipsize="end"
/>
</LinearLayout>
</LinearLayout>
- android:padding, which arranges for some whitespace to be put outside the actual widget contents but still be considered part of the widget (or container) itself when calculating its size
- android:textStyle, where we can indicate that some text is in bold or italics
- android:singleLine, which, if true, indicates that text should not word-wrap if it extends past one line
- android:ellipsize, which indicates where text should be truncated and ellipsized if it is too long for the available space
Override getView()
Next, we need to use this layout ourselves in our RestaurantAdapter. To do this, we need to override getView() and inflate the layout as needed for rows.Modify RestaurantAdapter to look like the following:
class RestaurantAdapter extends ArrayAdapter<Restaurant> {
RestaurantAdapter() {
super(LunchList.this,
android.R.layout.simple_list_item_1,model);
}
public View getView(int position, View convertView,
ViewGroup parent) {
View row=convertView;
if (row==null) {
LayoutInflater inflater=getLayoutInflater();
row=inflater.inflate(R.layout.row, null);
}
Restaurant r=model.get(position);
((TextView)row.findViewById(R.id.title)).setText(r.getName());
((TextView)row.findViewById(R.id.address)).setText(r.getAddress());
ImageView icon=(ImageView)row.findViewById(R.id.icon);
if (r.getType().equals("sit_down")) {
icon.setImageResource(R.drawable.ball_red);
}
else if (r.getType().equals("take_out")) {
icon.setImageResource(R.drawable.ball_yellow);
}
else {
icon.setImageResource(R.drawable.ball_green);
}
return(row);
}
}
Create a RestaurantHolder
To improve performance and encapsulation, we should move the logic that populates a row from a restaurant into a separate class, one that can cache the TextView and ImageView widgets.To do this, add the following static inner class to LunchList:
static class RestaurantHolder {
private TextView name=null;
private TextView address=null;
private ImageView icon=null;
RestaurantHolder(View row) {
name=(TextView)row.findViewById(R.id.title);
address=(TextView)row.findViewById(R.id.address);
icon=(ImageView)row.findViewById(R.id.icon);
}
void populateFrom(Restaurant r) {
name.setText(r.getName());
address.setText(r.getAddress());
if (r.getType().equals("sit_down")) {
icon.setImageResource(R.drawable.ball_red);
}
else if (r.getType().equals("take_out")) {
icon.setImageResource(R.drawable.ball_yellow);
}
else {
icon.setImageResource(R.drawable.ball_green);
}
}
}
Recycle Rows via RestaurantHolder
To take advantage of the new RestaurantHolder, we need to modify getView() in RestaurantAdapter. Following the holder pattern, we need to create a RestaurantHolder when we inflate a new row, cache that wrapper in the row via setTag(), then get it back later via getTag().Change getView() to look like the following:
public View getView(int position, View convertView,
ViewGroup parent) {
View row=convertView;
RestaurantHolder holder=null;
if (row==null) {
LayoutInflater inflater=getLayoutInflater();
row=inflater.inflate(R.layout.row, parent, false);
holder=new RestaurantHolder(row);
row.setTag(holder);
}
else {
holder=(RestaurantHolder)row.getTag();
}
holder.populateFrom(model.get(position));
return(row);
}
LunchList Class (Full Code)
package apt.tutorial;Rebuild and reinstall the application, then try adding several restaurants and confirm that, when the list is scrolled, everything appears as it should,the name, address, and icon all change.
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.LayoutInflater;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RadioGroup;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class LunchList extends Activity {
List<Restaurant> model=new ArrayList<Restaurant>();
RestaurantAdapter adapter=null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button save=(Button)findViewById(R.id.save);
save.setOnClickListener(onSave);
ListView list=(ListView)findViewById(R.id.restaurants);
adapter=new RestaurantAdapter();
list.setAdapter(adapter);
}
private View.OnClickListener onSave=new View.OnClickListener() {
public void onClick(View v) {
Restaurant r=new Restaurant();
EditText name=(EditText)findViewById(R.id.name);
EditText address=(EditText)findViewById(R.id.addr);
r.setName(name.getText().toString());
r.setAddress(address.getText().toString());
RadioGroup types=(RadioGroup)findViewById(R.id.types);
switch (types.getCheckedRadioButtonId()) {
case R.id.sit_down:
r.setType("sit_down");break;
case R.id.take_out:
r.setType("take_out");break;
case R.id.delivery:
r.setType("delivery");break;
}
adapter.add(r);
}
};
class RestaurantAdapter extends ArrayAdapter<Restaurant> {
RestaurantAdapter() {
super(LunchList.this, R.layout.row, model);
}
public View getView(int position, View convertView,
ViewGroup parent) {
View row=convertView;
RestaurantHolder holder=null;
if (row==null) {
LayoutInflater inflater=getLayoutInflater();
row=inflater.inflate(R.layout.row, parent, false);
holder=new RestaurantHolder(row);
row.setTag(holder);
}
else {
holder=(RestaurantHolder)row.getTag();
}
holder.populateFrom(model.get(position));
return(row);
}
}
static class RestaurantHolder {
private TextView name=null;
private TextView address=null;
private ImageView icon=null;
RestaurantHolder(View row) {
name=(TextView)row.findViewById(R.id.title);
address=(TextView)row.findViewById(R.id.address);
icon=(ImageView)row.findViewById(R.id.icon);
}
void populateFrom(Restaurant r) {
name.setText(r.getName());
address.setText(r.getAddress());
if (r.getType().equals("sit_down")) {
icon.setImageResource(R.drawable.ball_red);
}
else if (r.getType().equals("take_out")) {
icon.setImageResource(R.drawable.ball_yellow);
}
else {
icon.setImageResource(R.drawable.ball_green);
}
}
}
}
By Mohd Zulkamal
NOTE : – If You have Found this post Helpful, I will appreciate if you can Share it on Facebook, Twitter and Other Social Media Sites. Thanks =)