I need help on how to change my code below to use my own XML list view. The items 'label', 'title', & 'discription' in my cursor needs to be inflated into itemLabel, itemTitle, & itemDiscription of the xml. Any help would be appreciated: I know how to do this from a simple array. The activity I created to get the data from a database works great - I just dont know how to use/display a custom lisView w/multilines. THNX!
REVISED: I managed to get the data to display from the database using my own custom XML file. The issue I have now is all three columns are returned in each TextView. ie: columns 'title', 'label', 'description' from the db all inflate into a single TextView as one continuous line. I cant figure out how to break it up into the correct TextViews; title = R.id.listTitle, label = R.id.label, and description should inflate into R.id.caption. Help!
The ListView Activity:(REVISED):
public class List_AC extends ListActivity {
private ArrayList<String> results = new ArrayList<String>();
File dbfile = new File("/mnt/sdcard/XXX/XXX/dB/XXX.db");
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbfile, null);
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
openAndQueryDatabase();
displayResultList();
}
private void displayResultList() {
AC_Adapter adapter = new AC_Adapter(getApplicationContext(),R.layout.list_item, results, results, results);
setListAdapter(adapter);
}
private void openAndQueryDatabase() {
try {
Cursor c = db.rawQuery("SELECT label, title, discription FROM AC_list", null);
if (c != null) {
if (c.moveToFirst()) {
do {
String i1 = c.getString(c.getColumnIndex("label"));
String i2 = c.getString(c.getColumnIndex("title"));
String i3 = c.getString(c.getColumnIndex("discription"));
results.add(i1 + i2 + i3);
} while (c.moveToNext());
}
}
} catch (SQLiteException se) {
Log.e(getClass().getSimpleName(),
"Could not create or Open the database");
} finally {
if (db != null)
db.close();
}
}
}
ADDED ADAPTER(AC_Adapter.java):
public class AC_Adapter extends ArrayAdapter<String> {
static List<String> Title = new ArrayList<String>();
static List<String> Label = new ArrayList<String>();
static List<String> Description = new ArrayList<String>();
Context myContext;
public AC_Adapter (Context context, int resource, List<String> aTitle, List<String> aLabel, List<String> aDescription){
super(context, resource, aTitle);
myContext = context;
Title= aTitle;
Label= aLabel;
Description = aDescription;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) myContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.list_item, null);
}
TextView tv_label = (TextView) v.findViewById(R.id.label);
TextView tv_title = (TextView) v.findViewById(R.id.listTitle);
TextView tv_decription = (TextView) v.findViewById(R.id.caption);
if (tv_label != null) {
tv_label.setText(Label.get(position));
}
if (tv_title != null) {
tv_title.setText(Title.get(position));
}
if (tv_decription != null) {
tv_decription.setText(Description.get(position));
}
return v;
}
}
This is the XML that needs to be created (list_view.xml) in the onCreate:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="30dip"
android:padding="4dip"
android:background="#drawable/gradient" >
<ImageButton
android:id="#+id/homeBtn"
android:src="#drawable/ic_menu_icon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:background="#null" />
<TextView
android:id="#+id/titleBarTitle"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="18sp" />
<ImageButton
android:id="#+id/toolBtn"
android:src="#drawable/ic_menu_list"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:background="#null" />
</RelativeLayout>
<ListView
android:id="#+id/listItems"
android:layout_height="wrap_content"
android:layout_width="fill_parent" />
</LinearLayout>
and the list item (list_item.xml):
<?xml version="1.0" encoding="utf-8"?>
<TextView
android:id="#+id/itemLabel"
style="#style/listAcronym" />
<TextView
android:id="#+id/itemTitle"
style="#style/listTitle" />
<TextView
android:id="#+id/itemDiscription"
style="#style/listDiscription"/>
<ImageView
style="#style/listNextIcon" />
The basic process is to create a Custom Adapter which will contain the layout R.layout.list_item
Thus, you replace this line setListAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, results));
in your code
by
setListAdapter(new CustomAdapter(this,R.layout.list_item, results));
Now you need to create a CustomAdapter which extends ArrayAdapter or BaseAdapter and override the getView method to inflate R.layout.list_item
Please refer to this excellent tutorial by Mark Murphy
Custom ListView Adapter
If you do have any other doubts after trying this, please post it over here.
Everything is fine, just add a class extends from ArrayAdapter and do something like this:
public class CustomAdapter extends ArrayAdapter<String>
{
List<String> Title= new ArrayList<String>();
List<String> Label= new ArrayList<String>();
Context myContext;
public CustomAdapter (Context context, int resource,
int textviewresourceid,
List<String> aTitle,
List<String> aLabel)
{
super(context, resource,textviewresourceid,aType);
myContext = context;
Title= aTitle;
Label= aLabel;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
if (v == null)
{
LayoutInflater vi = (LayoutInflater)myContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.list_view, null);
}
TextView tv_title = (TextView) v.findViewById(R.id.id_tv_Title);
TextView tv_Label= (TextView) v.findViewById(R.id.id_tv_Label);
if(tv_title != null)
{
tv_title.setText(Title.get(position));
}
if(tv_Label != null)
{
tv_Label.setText(Label.get(position));
}
return v;
}
And then use this adapter like:
CustomAdapter adapter = new CustomAdapter(getAppContext(),R.layout.list_view,Textview Title Id,your lists...);
setListAdapter(adapter);
Something like this.... Hope it helps...
I have the correct anwser HERE along with the correct code.
Related
i want to combine two LinearLayout, both have different TextView arrangement in them, in a single ListView. so the final look should be like below:
and i run it with my code, but the app wouldn't start. below are my code.
Activity class:
public class MainActivity extends Activity {
// Create list of items
String[] publicModeItems = {
"AAAAA",
"BBBBB"
};
String[] publicModeParameters = {
"YES",
"NO"
};
String[] publicModeResetExe = {
"CCCCC",
"DDDDD"
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
populateListView();
}
private void populateListView() {
CustomList adapter1 = new CustomList(this, publicModeItems, publicModeParameters);
// Build adapter
ArrayAdapter<String> adapter2 = new ArrayAdapter<String>(
this, // context for the activity
R.layout.text_view_test, // layout to use (create)
publicModeResetExe); // items to display
// Configure the list view
ListView list = (ListView) findViewById(R.id.PublicModeListView);
list.setAdapter(adapter1);
list.setAdapter(adapter2);
}
private class CustomList extends ArrayAdapter<String> {
private final Activity context;
private final String[] publicModeItems;
private final String[] publicModeParameters;
public CustomList(Activity context,
String[] publicModeItems,
String[] publicModeParameters) {
super(context, R.layout.text_views_1, publicModeItems);
this.context = context;
this.publicModeItems = publicModeItems;
this.publicModeParameters = publicModeParameters;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater layoutinflater = context.getLayoutInflater();
View rowView = layoutinflater.inflate(R.layout.text_views_1, null, true);
TextView txtPublicModeItems = (TextView) rowView.findViewById(R.id.PublicModeItems);
TextView txtPublicModeParameters = (TextView) rowView.findViewById(R.id.PublicModeParameters);
txtPublicModeItems.setText(publicModeItems[position]);
txtPublicModeParameters.setText(publicModeParameters[position]);
return rowView;
}
}
}
text_views_1 xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/PublicModeLayoutForTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/PublicModeItems"
android:layout_width="200sp"
android:layout_height="wrap_content"
android:textColor="#drawable/text_color_change" />
<TextView
android:id="#+id/PublicModeOpenBracket"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="["
android:textColor="#drawable/text_color_change" />
<TextView
android:id="#+id/PublicModeParameters"
android:layout_width="100sp"
android:layout_height="wrap_content"
android:gravity="end"
android:textColor="#drawable/text_color_change" />
<TextView
android:id="#+id/PublicModeCloseBracket"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="]"
android:textColor="#drawable/text_color_change" />
</LinearLayout>
text_view_test xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="#drawable/text_color_change" >
</TextView>
activity_main xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/PublicModeListViewLayout01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/black"
android:baselineAligned="true"
android:orientation="vertical"
tools:context="com.example.mycalendar.MainActivity" >
<LinearLayout
android:id="#+id/PublicModeListViewLayout02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#drawable/custom_border"
android:padding="5dp" >
<ListView
android:id="#+id/PublicModeListView"
android:layout_width="308dp"
android:layout_height="wrap_content"
android:choiceMode="singleChoice"
android:listSelector="#color/yellow"
android:smoothScrollbar="true" >
</ListView>
</LinearLayout>
</LinearLayout>
Problem : I just run my code just now, and only 'CCCCC' and 'DDDDD' is showing. so do you have any idea on this?
You should inherit your list adapter from BaseAdapter rather than ArrayAdapter.
Rewrite adapter's getView() method to inflate layout according position, like below.
public View getView(int position, View convertView, ViewGroup parent) {
...
View rootView = null;
if (position == 0 || position == 1) {
rootView = layoutinflater.inflate(R.layout.text_views_1, null, true);
} else {
rootView = layoutinflater.inflate(R.layout.text_views, null, true);
}
...
return rootView;
}
You set the list adapter twice
list.setAdapter(adapter1);
list.setAdapter(adapter2);
in this case the current adapter is the second, not them both.
Use ListView with SimpleAdapter or a custom adapter and that will solve all your problems, check out this for SimpleAdapter tutorial to learn a the basics and this tutorial to learn how you can make multiple views instead of just 1. This tutorial is about creating custom adapter
BTW, I have few comments on your code and xml layout
First, there is no need for 2 TextViews for your bracket, you can easily add them programmatically to the String[] or even to YES/NO TextView.
Second, You're not using a ViewHolder in your CustomList adapter and this is not a good practice as every time you scroll your list, it creates new view although it can use already existing one.
I already solve this problem. but it seems not so convenient to use this method.
public class PublicModeActivity extends Activity {
// Create list of items
String[] publicModeItems = {
"AAAAA",
"BBBBB"
};
String[] publicModeParameters = {
"YES",
"NO"
String[] publicModeResEx = {
"",
"",
"CCCCC",
"DDDDD"
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
populateListView();
}
private void populateListView() {
CustomList adapter = new CustomList(this, publicModeItems, publicModeParameters, publicModeResEx);
// Configure the list view
ListView list = (ListView) findViewById(R.id.PublicModeListView);
list.setAdapter(adapter);
}
private class CustomList extends BaseAdapter {
private final Activity context;
private final String[] publicModeItems;
private final String[] publicModeParameters;
private final String[] publicModeResEx;
public CustomList(Activity context,
String[] publicModeItems,
String[] publicModeParameters,
String[] publicModeResEx) {
super();
this.context = context;
this.publicModeItems = publicModeItems;
this.publicModeParameters = publicModeParameters;
this.publicModeResEx = publicModeResEx;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater layoutinflater = context.getLayoutInflater();
View rowView = null;
Log.i("PublicModeActivity", "" + position);
if (position < 2) {
rowView = layoutinflater.inflate(R.layout.text_views_1, null, true);
TextView txtPublicModeItems = (TextView) rowView.findViewById(R.id.PublicModeItems);
TextView txtPublicModeParameters = (TextView) rowView.findViewById(R.id.PublicModeParameters);
txtPublicModeItems.setText(publicModeItems[position]);
txtPublicModeParameters.setText(publicModeParameters[position]);
} else {
rowView = layoutinflater.inflate(R.layout.text_view_test, null, true);
TextView txtPublicModeResEx = (TextView) rowView.findViewById(R.id.PublicModeResEx);
txtPublicModeResEx.setText(publicModeResEx[position]);
}
return rowView;
}
#Override
public int getCount() {
return 4;
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
}
}
I need to put that blank string "", to match the number of row with the upper layout (text_views_1) even-though those blank string are use in different layout. so it is not so convenient especially when you want to display so many data. If someone here have much simpler method than this. feel free to share with me/us. i'm eager to learn. thank you!
I have a custom row item xml and a Activity xml which has a button, a textbox and a listview. Can anybody give me a very simple example on how this is done? I know i will need a adapter (what it extends i dont know) and update it from the button
I have tried getting the list view updated from the button with the editview text but cant get the adapter code to be hit. I am looking at base adapters now but cant help but feel this shouldn't be complicated and need so many override methods.
Activity class
public class InvitePlayers_Activity extends Activity {
ListViewAdapter emailAdapter = null;
ImageView imgView_mail;
ImageView imgView_confirm;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE); //remove title bar
setContentView(R.layout.activity_inviteplayers);
//Generate list View from ArrayList
displayListView();
}
private void displayListView() {
//assign controls
final ListView listView = (ListView) findViewById(R.id.listView_invitePlayers);
imgView_mail = (ImageView)findViewById(R.id.imgView_mail);
//Test data
ArrayList<String> inviteNew = new ArrayList<String>();
final ArrayList<ArrayList<String>> inviteList = new ArrayList<ArrayList<String>>();
emailAdapter = new ListViewAdapter(this,inviteList);
listView.setAdapter(emailAdapter);
// Assign adapter to ListView
listView.setTextFilterEnabled(true);
//Edit listeners
imgView_mail.setOnClickListener(new View.OnClickListener() {
public void onClick(View view)
{
//variables
final String enteredMail = "testListViewEntry";
final ArrayList<ArrayList<String>> inviteList = new ArrayList<ArrayList<String>>();
ArrayList<String> invite = new ArrayList<String>();
invite.add(0, enteredMail);//add first email
invite.add(1,"icon_invitestatussent.png"); //add first status icon
inviteList.add(invite);
emailAdapter.notifyDataSetChanged();
listView.setAdapter(emailAdapter);
}
});
}
}
Adapter class
public class ListViewAdapter extends BaseAdapter {
private Activity context;
ArrayList<ArrayList<String>> inviteDetails = new ArrayList<ArrayList<String>>();
public ListViewAdapter(Activity context, ArrayList<ArrayList<String>> inviteDetails ) {
this.inviteDetails = inviteDetails;
this.context = context;
}
#Override
public int getCount() {
return 0;
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
public View getView(int position, View view, ViewGroup parent){
//Inflater
LayoutInflater inflater = context.getLayoutInflater();
//get row view
if (view == null) {
LayoutInflater mInflater = (LayoutInflater)
context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
view = mInflater.inflate(R.layout.list_item_email, null);
}
//assign controls
final TextView textView_playerEmail = (TextView) view.findViewById(R.id.textView_playerEmail);
ImageView imgView_inviteStatus = (ImageView) view.findViewById(R.id.imgView_inviteStatus);
//Assign control values that are dynamic
textView_playerEmail.setText(inviteDetails.get(position).get(0));
imgView_inviteStatus.setImageResource(R.drawable.icon_invitestatussent);
return view;
}
public ArrayList<ArrayList<String>> addInvite(ArrayList<String> inviteDetails, ArrayList<ArrayList<String>> currentInvites)
{
currentInvites.add(inviteDetails);
return currentInvites;
}
#Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
}
}
Custom row xml
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dp"
android:textSize="16sp"
android:id="#+id/textView_playerEmail"
android:textColor="#color/white"
android:text="item1">
</TextView>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imgView_inviteStatus" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imgView_remove"
android:src="#drawable/btn_cancel" />
Activity layout
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:weightSum="1"
android:gravity="left|center">
<ImageView
android:layout_width="45dp"
android:layout_height="34dp"
android:id="#+id/imgView_mail"
android:src="#drawable/btn_mail"
android:layout_weight="0.22"
android:padding="3dp" />
</LinearLayout>
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/listView_invitePlayers"
android:layout_gravity="center_horizontal" />
</LinearLayout>
<ImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:id="#+id/btn_confirm"
android:src="#drawable/btn_confirm"
android:clickable="false"
android:adjustViewBounds="true"
android:layout_gravity="center_horizontal"
android:padding="2dp"
android:layout_weight="1" />
</LinearLayout>
From reading the description of the question I think you need to set custom adapter to show the elements in you listview. This is how you set the custom adapter for the listview:
public class Notes_list extends BaseAdapter
{
private Context mContext;
private ArrayList<String> id;
private ArrayList<String> firstName;
private ArrayList<String> lastName;
public Notes_list(Context c, ArrayList<String> id,ArrayList<String> fname, ArrayList<String> lname)
{
this.mContext = c;
this.id = id;
this.firstName = fname;
this.lastName = lname;
}
public int getCount() {
return id.size();
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int pos, View child, ViewGroup arg2) {
Holder mHolder;
LayoutInflater layoutInflater;
if (child == null) {
layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
child = layoutInflater.inflate(R.layout.custom_row, null);
mHolder = new Holder();
// mHolder.txt_id = (TextView) child.findViewById(R.id.txt_id);
mHolder.txt_fName = (TextView) child.findViewById(R.id.txt_fName);
mHolder.txt_lName = (TextView) child.findViewById(R.id.txt_lName);
child.setTag(mHolder);
} else
{
mHolder = (Holder) child.getTag();
}
// mHolder.txt_id.setText(id.get(pos));
mHolder.txt_fName.setText(firstName.get(pos));
mHolder.txt_lName.setText(lastName.get(pos));
return child;
}
public class Holder
{
// TextView txt_id;
TextView txt_fName;
TextView txt_lName;
}
}
now in your main activity where you have to call the list enter code like this:
private ListView userList;
private ArrayList<Employee> itemsList = new ArrayList<modelName>();
userList = (ListView) findViewById(R.id.List);
UserList disadpt = new UserList(MainActivity.this, itemsList);
userList.setAdapter(disadpt);
Hope it helps...
In my app, I am creating a dynamic list of items using
shopsNameList = new ArrayList<String>();
// Create The Adapter
ArrayAdapter<String> arrayAdapter =
new ArrayAdapter<String>(ShopsListActivity.this, android.R.layout.simple_list_item_1, shopsNameList);
I would like to have a text and an image in each element of the list, not a simple text.
I defined a listviewitem.xml layout
<?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" >
<ImageView
android:id="#+id/listitemimage"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="#raw/shop" />
<TextView
android:id="#+id/textview"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="Test" />
</LinearLayout>
and tried
ArrayAdapter<String> arrayAdapter =
new ArrayAdapter<String>(ShopsListActivity.this, R.layout.listviewitem, shopsNameList);
but my app crashes when I enter the list.
I am inside an activity creted with
super.onCreate(saveInstanceState);
setContentView(R.layout.shopslist);
// Get the reference of ListView
ListView shopsList=(ListView)findViewById(R.id.listShops);
shopsNameList = new ArrayList<String>();
shopElements = new ArrayList<ShopElement>();
You need to create custom adapter for your ListView:
public class CustomAdapter extends ArrayAdapter<String>{
Context context;
public CustomAdapter(Context context, List< String > objects)
{
super( context, R.layout.listviewitem, objects );
this.context = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ShopListHolder holder = null;
if(convertView == null)
{
LayoutInflater inflater = LayoutInflater.from( context );
convertView = inflater.inflate(R.layout.listviewitem, parent, false);
holder = new ShopListHolder();
holder.imgIcon = (ImageView)convertView.findViewById(R.id.listitemimage);
holder.txtTitle = (TextView)convertView.findViewById(R.id.textview);
convertView.setTag(holder);
}
else
{
holder = (ShopListHolder )convertView.getTag();
}
holder.txtTitle.setText(getItem( position ));
return convertView;
}
class ShopListHolder
{
ImageView imgIcon;
TextView txtTitle;
}
}
I'm wondering why having a ListView's layout_height="wrap_content" messes up Spinners at the end of the list. I ran through different ways of fixing it below. I'm hoping someone can explain the behaviour, or point out what android knowledge i'm lacking about drawing of views / ui events.
1) The problem visually can be seen here.
2) After changing the ListItem property
android:descendantFocusability="afterDescendants"
I get better behaviour but something is still going on. It simply seems like the items inside the list are not receiving the events, so that property change made sense to me.
Here is a video of how the spinners behave after updating that property.
All works fine except when I actually select an item.
3) After setting the ListView's layout_height="match_parent" the problem seems to go away after selecting an item. See here for that video.
The Activity:
public class SelectorActivity extends Activity {
public static final String TAG = SelectorActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v(TAG, "onCreate");
setContentView(R.layout.activity_selector);
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ListView contents = (ListView) findViewById(R.id.list_view);
contents.addHeaderView(new TestView(this));
contents.addFooterView(new View(this));
SimpleBaseAdapter listAdapter = new SimpleBaseAdapter(this);
// LOW RANGE
LinearLayout lowRange = (LinearLayout) inflater.inflate(R.layout.list_item_edit, null);
TextView lowRangeText = (TextView) lowRange.findViewById(R.id.text);
EditText lowRangeEditText = (EditText) lowRange.findViewById(android.R.id.edit);
// HIGH RANGE
LinearLayout highRange = (LinearLayout) inflater.inflate(R.layout.list_item_edit, null);
TextView highRangeText = (TextView) highRange.findViewById(R.id.text);
EditText highRangeEditText = (EditText) highRange.findViewById(android.R.id.edit);
// UNITS
LinearLayout units = (LinearLayout) inflater.inflate(R.layout.list_item_units, null);
TextView unitsText = (TextView) units.findViewById(android.R.id.text1);
// SPINNERS
LinearLayout spinners = (LinearLayout) inflater.inflate(R.layout.list_item_spinners, null);
Spinner spinner1 = (Spinner) spinners.findViewById(R.id.spinner1);
Spinner spinner2 = (Spinner) spinners.findViewById(R.id.spinner2);
Spinner spinner3 = (Spinner) spinners.findViewById(R.id.spinner3);
DebugAdapterViewListeners.set(spinner1, "spinner1");
// VIEW SETUP
lowRangeText.setText("text1");
highRangeText.setText("text2");
unitsText.setText("text3");
// SPINNER SETUP
String[] massUnits1 = new String[]{"one","two"};
String[] massUnits2 = new String[]{"three","four"};
String[] timeUnits = new String[]{"five","six"};
ArrayAdapter<String> adapt1 = new ArrayAdapter<String>(this, R.layout.spinner_list_item_centered);
ArrayAdapter<String> adapt2 = new ArrayAdapter<String>(this, R.layout.spinner_list_item_centered);
ArrayAdapter<String> adapt3 = new ArrayAdapter<String>(this, R.layout.spinner_list_item_centered);
adapt1.addAll(massUnits1);
adapt2.addAll(massUnits2);
adapt3.addAll(timeUnits);
spinner1.setAdapter(adapt1);
spinner2.setAdapter(adapt2);
spinner3.setAdapter(adapt3);
listAdapter.addView(lowRange);
listAdapter.addView(highRange);
listAdapter.addView(units);
listAdapter.addView(spinners);
contents.setAdapter(listAdapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.selector, menu);
return false;
}
}
Here is the SimpleBaseAdapter class:
public class SimpleBaseAdapter extends BaseAdapter {
private ArrayList<View> views;
private Context context;
public SimpleBaseAdapter(Context context) {
this.context = context;
this.views = new ArrayList<View>();
}
public void addView(View view) {
this.views.add(view);
}
#Override
public int getCount() {
return views.size();
}
#Override
public Object getItem(int position) {
View view = views.get(position);
if (view instanceof AbsListView) {
return ((AbsListView)view).getItemAtPosition(position);
} else if (view instanceof AbsSpinner) {
return ((AbsSpinner)view).getItemAtPosition(position);
} else {
return null;
}
}
#Override
public long getItemId(int position) {
View view = views.get(position);
if (view instanceof AbsListView) {
return ((AbsListView)view).getItemIdAtPosition(position);
} else if (view instanceof AbsSpinner) {
return ((AbsSpinner)view).getItemIdAtPosition(position);
} else {
return 0;
}
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
return views.get(position);
}
}
Activity 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:background="#color/green_1"
android:orientation="vertical"
>
<ListView
android:id="#+id/list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:headerDividersEnabled="true"
android:footerDividersEnabled="true"
android:dividerHeight="0.5sp"
android:divider="#color/black"
android:clipToPadding="false"
android:layout_marginTop="18sp"
android:layout_marginBottom="18sp"
/>
</LinearLayout>
Edit list item layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="#dimen/row_padding"
android:background="#android:color/white"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/text"
android:layout_weight="50"
android:gravity="top"
android:textSize="#dimen/font_size_standard"
android:textColor="#drawable/selector_row_item_detail_text"
/>
<EditText
android:layout_width="0dip"
android:layout_height="wrap_content"
android:id="#android:id/edit"
android:layout_weight="50"
android:inputType="number"
android:gravity="right"
/>
</LinearLayout>
The spinner row item layout:
<?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:id="#+id/spinner_container"
android:orientation="horizontal"
android:background="#android:color/white"
android:paddingTop="#dimen/header_row_padding_vertical"
>
<Spinner
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="33"
android:id="#+id/spinner1"
android:gravity="center"
android:spinnerMode="dropdown"
/>
<Spinner
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="33"
android:id="#+id/spinner2"
android:gravity="center"
android:spinnerMode="dialog"
/>
<Spinner
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="33"
android:id="#+id/spinner3"
android:gravity="center"
android:spinnerMode="dialog"
/>
</LinearLayout>
The problem that you were facing was the basic behaviour of Spinner, so a modified Spinner is needed. This is code for the spinner whose initial ie. by default the visualisation is "Select Item" (if the prompt declared in the .xml like android:prompt="#string/Select Item") & the dropdown views are the same size of the original spinner. The limitation of this modified spinner is that it does not display the prompt if the items are empty.
Make a new class named NoDefaultSpinner.java & in that copy paste this code
public class NoDefaultSpinner extends Spinner {
public NoDefaultSpinner(Context context) {
super(context);
}
public NoDefaultSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NoDefaultSpinner(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void setAdapter(SpinnerAdapter orig ) {
final SpinnerAdapter adapter = newProxy(orig);
super.setAdapter(adapter);
try {
final Method m = AdapterView.class.getDeclaredMethod(
"setNextSelectedPositionInt",int.class);
m.setAccessible(true);
m.invoke(this,-1);
final Method n = AdapterView.class.getDeclaredMethod(
"setSelectedPositionInt",int.class);
n.setAccessible(true);
n.invoke(this,-1);
}
catch( Exception e ) {
throw new RuntimeException(e);
}
}
protected SpinnerAdapter newProxy(SpinnerAdapter obj) {
return (SpinnerAdapter) java.lang.reflect.Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
new Class[]{SpinnerAdapter.class},
new SpinnerAdapterProxy(obj));
}
/**
* Intercepts getView() to display the prompt if position < 0
*/
protected class SpinnerAdapterProxy implements InvocationHandler {
protected SpinnerAdapter obj;
protected Method getView;
protected SpinnerAdapterProxy(SpinnerAdapter obj) {
this.obj = obj;
try {
this.getView = SpinnerAdapter.class.getMethod(
"getView",int.class,View.class,ViewGroup.class);
}
catch( Exception e ) {
throw new RuntimeException(e);
}
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
try {
return m.equals(getView) &&
(Integer)(args[0])<0 ?
getView((Integer)args[0],(View)args[1],(ViewGroup)args[2]) :
m.invoke(obj, args);
}
catch (InvocationTargetException e) {
throw e.getTargetException();
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
protected View getView(int position, View convertView, ViewGroup parent)
throws IllegalAccessException {
if( position<0 ) {
final TextView v =
(TextView) ((LayoutInflater)getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE)).inflate(
android.R.layout.simple_spinner_item,parent,false);
v.setText(getPrompt());
return v;
}
return obj.getView(position,convertView,parent);
}
}
}
In spinner row item layout change the type of spinner to <com.example.appname.NoDefaultSpinner like this
<com.example.appname.NoDefaultSpinner
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="33"
android:id="#+id/spinner1"
android:gravity="center"
android:spinnerMode="dropdown"
/>
<com.example.appname.NoDefaultSpinner
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="33"
android:id="#+id/spinner2"
android:gravity="center"
android:spinnerMode="dialog"
/>
<com.example.appname.NoDefaultSpinner
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="33"
android:id="#+id/spinner3"
android:gravity="center"
android:spinnerMode="dialog"
/>
The Activity : Change the type of Spinner to NoDefaultSpinner like this
public class SelectorActivity extends Activity {
public static final String TAG = SelectorActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v(TAG, "onCreate");
setContentView(R.layout.activity_selector);
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ListView contents = (ListView) findViewById(R.id.list_view);
contents.addHeaderView(new TestView(this));
contents.addFooterView(new View(this));
SimpleBaseAdapter listAdapter = new SimpleBaseAdapter(this);
// LOW RANGE
LinearLayout lowRange = (LinearLayout) inflater.inflate(R.layout.list_item_edit, null);
TextView lowRangeText = (TextView) lowRange.findViewById(R.id.text);
EditText lowRangeEditText = (EditText) lowRange.findViewById(android.R.id.edit);
// HIGH RANGE
LinearLayout highRange = (LinearLayout) inflater.inflate(R.layout.list_item_edit, null);
TextView highRangeText = (TextView) highRange.findViewById(R.id.text);
EditText highRangeEditText = (EditText) highRange.findViewById(android.R.id.edit);
// UNITS
LinearLayout units = (LinearLayout) inflater.inflate(R.layout.list_item_units, null);
TextView unitsText = (TextView) units.findViewById(android.R.id.text1);
// SPINNERS
LinearLayout spinners = (LinearLayout) inflater.inflate(R.layout.list_item_spinners, null);
NoDefaultSpinner spinner1 = (NoDefaultSpinner) spinners.findViewById(R.id.spinner1);
NoDefaultSpinner spinner2 = (NoDefaultSpinner) spinners.findViewById(R.id.spinner2);
NoDefaultSpinner spinner3 = (NoDefaultSpinner) spinners.findViewById(R.id.spinner3);
DebugAdapterViewListeners.set(spinner1, "spinner1");
// VIEW SETUP
lowRangeText.setText("text1");
highRangeText.setText("text2");
unitsText.setText("text3");
// SPINNER SETUP
String[] massUnits1 = new String[]{"one","two"};
String[] massUnits2 = new String[]{"three","four"};
String[] timeUnits = new String[]{"five","six"};
ArrayAdapter<String> adapt1 = new ArrayAdapter<String>(this, R.layout.spinner_list_item_centered);
ArrayAdapter<String> adapt2 = new ArrayAdapter<String>(this, R.layout.spinner_list_item_centered);
ArrayAdapter<String> adapt3 = new ArrayAdapter<String>(this, R.layout.spinner_list_item_centered);
adapt1.addAll(massUnits1);
adapt2.addAll(massUnits2);
adapt3.addAll(timeUnits);
spinner1.setAdapter(adapt1);
spinner2.setAdapter(adapt2);
spinner3.setAdapter(adapt3);
listAdapter.addView(lowRange);
listAdapter.addView(highRange);
listAdapter.addView(units);
listAdapter.addView(spinners);
contents.setAdapter(listAdapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.selector, menu);
return false;
}
This solution relies on reflection to call the AdapterView.setNextSelectedPositionInt() and AdapterView.setSelectedPositionInt(), & runs successfully on API 4 to API 19.
You should extend SpinnerAdapter rather than BaseAdapter. It has getDropdownView() as well as getView() and i believe it handles some special cases internally itself. I am extending this adapter in a similar layout on android 4.2 and I don't see the issues you have.
I would hazzard a guess that a difference in how getDropdownView() handles attaching the view to the root would account for this difference but I haven't looked into the code to check this
I have two list, that need to be processed and displayed, I have used the following technique -
I get the data from 2 sources, process it and have 2 Custom Adapters, that take the data and place it in the relvant View.
However I only can view one list (the one at the top of in the view xml) - and not the other one,
Can someone please help me fix this prob. Its driving me insane.
Main Activity code belwo:
public class TestList extends Activity {
private final static String TAG = "ListSample";
private List<String> items;
private List<String> items2;
private CustomTeamListAdapter m_adapter;
private CustomTeamListAdapterTwo t_adapter;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
items = new ArrayList<String>();
for (int i = 0; i < 20; i++) {
items.add(i + "|||>>");
}
ListView list = (ListView) findViewById(R.id.customlist);
this.m_adapter = new CustomTeamListAdapter(this, R.layout.listitem,
(ArrayList<String>) items);
list.setAdapter(m_adapter);
/******************************************************************************/
items2 = new ArrayList<String>();
for (int i = 0; i < 20; i++) {
items2.add(i + ">>----");
}
ListView list_two = (ListView) findViewById(R.id.customlisttwo);
this.t_adapter = new CustomTeamListAdapterTwo(this, R.layout.listitem,
(ArrayList<String>) items2);
list_two.setAdapter(t_adapter);
}
private class CustomTeamListAdapter extends ArrayAdapter<String> {
private ArrayList<String> items;
public CustomTeamListAdapter(Context context, int textViewResourceId,
ArrayList<String> items) {
super(context, textViewResourceId, items);
this.items = items;
}
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.listitem, null);
String o = items.get(position);
if (o != null) {
TextView tt = (TextView) v.findViewById(R.id.sampletext);
tt.setText(o + "FirstSet");
tt.setId(position);
}
return v;
}
}
private class CustomTeamListAdapterTwo extends ArrayAdapter<String> {
private ArrayList<String> items;
public CustomTeamListAdapterTwo(Context context, int textViewResourceId,
ArrayList<String> items) {
super(context, textViewResourceId, items);
this.items = items;
}
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.listitem, null);
String o = items.get(position);
if (o != null) {
TextView tt = (TextView) v.findViewById(R.id.sampletext);
tt.setText(o + "SecondSet");
tt.setId(position);
}
return v;
}
}
}
Main layout XML below
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView android:id="#+id/customlisttwo"
android:layout_width="fill_parent" android:layout_height="wrap_content" />
<TextView android:id="#+id/randomtext" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:background="#CCCCCC"
android:text="Random Text" />
<ListView android:id="#+id/customlist" android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Item Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView android:id="#+id/customlisttwo"
android:layout_width="fill_parent" android:layout_height="wrap_content" />
<TextView android:id="#+id/randomtext" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:background="#CCCCCC"
android:text="Random Text" />
<ListView android:id="#+id/customlist" android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Thanks in advance for your thoughts
Try using Merge Adapter by Mark Murphy https://github.com/commonsguy/cwac-merge. You cant have two list views in the same activity. You can add that text view between the two layouts.