Is there a site where I can find the inner workings of the BaseExpandableListAdapter? I read the API and I still don't understand how it loops through the whole array that is supplied to provide the view. I'm having problems with my own implementation. I can't create a whole list of expandable lists without using ExpandableListActivity, even though both are the same. It's supposed to retrieve strings from the database and create an expandablelistview out of each one, and add all the created expandablelists to a linearlayout inside main.xml. What happens is that only the expandablelistview for the first string is shown. Here's the snippet
Main Class:
public class MainActivity extends Activity implements OnClickListener {
DBAdapter groupTable = new DBAdapter(this);
ExpandableListView groupLabel;
GroupAdapter adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
groupTable.open();
adapter = new GroupAdapter(groupTable.getAllGroups());
retrieveExpandables(adapter);
groupTable.close();
Button addGroupButton = (Button)findViewById(R.id.addGroup);
addGroupButton.setOnClickListener(this);
}
public void retrieveExpandables(GroupAdapter adapter) {
LinearLayout layout = (LinearLayout)findViewById(R.id.grouplist);
LinearLayout groupLayout =
(LinearLayout)getLayoutInflater().inflate(R.layout.grouplistview, null);
ExpandableListView groupExpandableList =
(ExpandableListView)groupLayout.findViewById(R.id.groupLabel);
groupExpandableList.setAdapter(adapter);
layout.addView(groupLayout);
}
BaseExpandableListAdapter class:
#Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
if (convertView instanceof ViewGroup)
return (ViewGroup) convertView;
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
ViewGroup item = (ViewGroup)inflater.inflate(R.layout.grouplisttext, null);
TextView groupLabel = (TextView)item.findViewById(R.id.groupLabel);
groupLabel.setText(groups[groupPosition].name);
groupLabel.setVisibility(View.VISIBLE);
Log.d("A1", "This part repeating");
return item;
}
XML file for the TextView that will be the expandable list title
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:id="#+id/groups"
android:layout_height="wrap_content">
<TextView android:id="#+id/groupLabel"
android:textSize="24sp"
android:text="asdf"
android:textStyle="bold"
android:layout_width="fill_parent"
android:layout_weight="1"
android:layout_height="40dip"
android:layout_marginLeft="45dip"
android:gravity="center_vertical" />
</LinearLayout>
XML file for the ExpandableListView
<?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:id="#+id/groups"
android:layout_height="wrap_content">
<ExpandableListView android:id="#+id/groupLabel"
android:textSize="24sp"
android:textStyle="bold"
android:layout_width="fill_parent"
android:layout_weight="1"
android:layout_height="40dip" />
</LinearLayout>
Sorry if I posted too much code, I tried removing as much unnecessary information as possible.
I found out where the problem went wrong. Apparently I got the LinearLayout and the ScrollView inside the main.xml interchanged, and the method for getViewGroup class was wrong. It's all good now
Related
I created a custom adapter with an xml with root layout as linear Layout. When i tried to change the root to RelativeLayout to add a button at the right end, each time i inflate the adapter by pressing the button the app stops working
This is my xml with the relative layout that isn't working when run
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/laybackground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="#dimen/list_item_height"
android:background="#color/tan_background"
android:orientation="horizontal">
<ImageView
android:id="#+id/theImage"
android:layout_width="#dimen/list_item_height"
android:layout_height="#dimen/list_item_height"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_toRightOf="#id/theImage">
<TextView
android:id="#+id/mokWord"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginTop="16dp"
tools:text="mok"
android:textColor="#android:color/white"/>
<TextView
android:id="#+id/engWord"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
tools:text="eng"
android:textColor="#android:color/white"/>
</LinearLayout>
</RelativeLayout>
And this is my Adapter
public class WordAdapterClass extends ArrayAdapter<MokAndEngClass> {
public int col=0;
public WordAdapterClass(Activity context, #NonNull List<MokAndEngClass> objects,int backroundColor) {
super(context, 0, objects);
col=backroundColor;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
View v = convertView;
if(v==null)
{
LayoutInflater lv = LayoutInflater.from(getContext());
v=lv.inflate(R.layout.englishandmoaki,parent,false);
}
MokAndEngClass listItem = getItem(position);
if(listItem!=null){
TextView writtenInMok = (TextView)v.findViewById(R.id.mokWord);
TextView writtenInEng =v.findViewById(R.id.engWord);
ImageView realtedImage =v.findViewById(R.id.theImage);
LinearLayout theTextLayout =(LinearLayout) v.findViewById(R.id.laybackground);
writtenInEng.setText(listItem.getEngWord());
writtenInMok.setText(listItem.getMokWord());
if(listItem.putAnImage()==0)
realtedImage.setVisibility(View.GONE);
else
realtedImage.setBackgroundResource(listItem.putAnImage());
theTextLayout.setBackgroundColor(theTextLayout.getResources().getColor(col));
}
return v;
}
}
The problem is you have changed the layout type from LinearLayout to RelativeLayout without changing the code in the getView() method to reflect that change--you are still trying to cast the root view to an LinearLayout!
Change this line of code:
LinearLayout theTextLayout =(LinearLayout) v.findViewById(R.id.laybackground);
to
RelativLayout theTextLayout =(RelativeLayout) v.findViewById(R.id.laybackground);
and everything should work as before.
Please Note:
When you post a question in the future on SO and you are reporting an issue, please make it clear that "isn't working" actually means "getting an error" and you should post the stack trace from the logcat. This issue would have been clear-up in 10 seconds by the SO community.
I've created something similar to a listview via a xml file containing an ImageView and TextView and using the LayoutInflater.
It seems I've done this in quite an unorthodox way, as I can't figure out how to actually style the listview (ideally I want to define the size as there's other content to be put on the same interface)
I've tried styling the LinearLayout inself, and putting the LinearLayout within a parent LinearLayout, including a ListView within the said file named 'list', trying to define a setContentView within the class which extends ListActivity.
I would love just to be able to include the custom listview control into a LinearLayout just like any other control, rather than the control being the entire UI.
public class ImageActivity extends ArrayAdapter<PlaceStore> {
private final Context context;
private final List<PlaceStore> places;
public ImageActivity(Context context, List<PlaceStore> places) {
super(context, R.layout.image_text_row, places);
this.context = context;
this.places = places;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.image_text_row, parent, false);
TextView textView = (TextView) rowView.findViewById(R.id.label);
ImageView imageView = (ImageView) rowView.findViewById(R.id.logo);
textView.setText(places.get(position).getName());
return rowView;
}
public class FavouriteActivity extends ListActivity{
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.favourite);
FavouriteData data = new FavouriteData(this);
List<PlaceStore> pS = data.returnFileData();
setListAdapter(new ImageActivity(this, pS));
}
R.layout.image_text_row
<?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="fill_parent"
android:padding="5dp" android:background="#drawable/background_type" >
<ImageView
android:id="#+id/logo"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="20dp"
android:layout_marginTop="5dp"
android:src="#drawable/androidmarker" >
</ImageView>
<TextView
android:id="#+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#+id/label"
android:textSize="20sp" >
</TextView>
</LinearLayout>
I connent an addevent.java with addevent.xml is content a listview, the listview take its element from another XML file "item.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="fill_parent"
android:orientation="vertical" >
<Button
android:id="#+id/d"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:drawablePadding="0dip"
android:drawableRight="#drawable/icon_name" />
<EditText
android:id="#+id/en"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toLeftOf="#+id/d" >
</EditText>
</LinearLayout>
now I need to findviewbyId not from basic xml file but form another "item.xml"
I tried LayoutInflater as this, code but it isn't work:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addevent);
myList = (ListView) findViewById(R.id.MyList);
myList.setItemsCanFocus(true);
myAdapter = new MyAdapter();
myList.setAdapter(myAdapter);
final LayoutInflater factory = getLayoutInflater();
final View textEntryView = factory.inflate(R.layout.item, null);
tvDisplayDate = (EditText)textEntryView.findViewById(R.id.editd);
btnChangeDate=(Button)textEntryView.findViewById(R.id.d);
any help please
Try this View view = LayoutInflater.from(getApplication()).inflate(R.layout.item, null);
How you can see, static from() method takes 1 argument(Context) and you obtains LayoutInflater from given Context, in your case it will be your Activity where you want to inflate View.
Hope it helps!
From insinde your MyAdapter class you can override the getView method (that's the one that produces the item renderers on demand).
After recycling / inflating the proper layout for the current item (say convertView), you can access all of its children using the findViewById method called on the convertView:
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
// initialize, inflate convertView from your layout if needed;
tvDisplayDate = (EditText)convertView.findViewById(R.id.editd);
// populate convertView with the item's details
}
I am developing an android application which contains a ListAtivity class and get it is data as follow :
ArrayAdapter<Item> ara=new MyArrayAdapter(this,_items);
setListAdapter(ara);
And I defined MyArrayAdapter :
....
public MyArrayAdapter(Activity context, List<BirthdayContact> list) {
super(context,R.layout.list_row,0,list);
//super(context, R.layout.birthday_list, list);
this.context = context;
this.list = list;
}
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
if (convertView == null) {
LayoutInflater inflator = context.getLayoutInflater();
view = inflator.inflate(R.layout.birthday_list_row, null);
final ViewHolder viewHolder = new ViewHolder();
viewHolder._cName= (TextView) view.findViewById(R.id.contact_name);
viewHolder._cImage = (ImageView) view.findViewById(R.id.contact_image);
viewHolder._cbirthDay=(TextView)view.findViewById(R.id.contact_birthday_remained);
view.setTag(viewHolder);
}
......
But the problem with this way is that you cant only assign each row`s template and you cant have other widget on list view which are not part of list of data. I mean I want to have a say a TextView which shows messages to user, and below that I show the list of rows.
Can you help me please?
If you want a different layout than a simple ListView you have the option of setting the content view to a layout file like this:
setContentView(R.layout.layout_with_diferrent_views); // call this on the onCreate() method
where R.layout.layout_with_different_views could be a xml layout like this:
<?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="fill_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
<ListView
android:id="#android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
Because you extends ListActivity you must have in the layout a ListView element with the id #android:id/list. Of course you can have a more complex layout than the one above as long as you have a ListView element with the id #android:id/list
You should consider using a listHeader : lv.addHeaderView(findViewById(R.id.header));
This has to be done in your onCreate method in your activity, and you must provide a widget with the id header.
If you want other components in activity.Then better consider Normal Activity instead ListActivity.
I have an Activity that retrieves data from a web service. This data is presented in a ListView via an ArrayAdapter which inflates a RelativeLayout with three TextViews inside, nothing fancy and it work fine.
Now I want to implement a Details Activity that should be called when a user clicks an item in the ListView, sounds easy but I can't for the life of me get the onItemClickListener to work on my ArrayAdapter.
This is my main Activity:
public class Schema extends Activity {
private ArrayList<Lesson> lessons = new ArrayList<Lesson>();
private static final String TAG = "Schema";
ListView lstLessons;
Integer lessonId;
// called when the activity is first created.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// can we use the custom titlebar?
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
// set the view
setContentView(R.layout.main);
// set the title
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.titlebar);
// listview called lstLessons
lstLessons = (ListView)findViewById(R.id.lstLessons);
// load the schema
new loadSchema().execute();
// set the click listeners
lstLessons.setOnItemClickListener(selectLesson);
}// onCreate
// declare an OnItemClickListener for the AdapterArray (this doesn't work)
private OnItemClickListener selectLesson = new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View v, int i, long l) {
Log.v(TAG, "onItemClick fired!");
}
};
private class loadSchema extends AsyncTask<Void, Void, Void> {
private ProgressDialog progressDialog;
// ui calling possible
protected void onPreExecute() {
progressDialog = ProgressDialog.show(Schema.this,"", "Please wait...", true);
}
// no ui from this one
#Override
protected Void doInBackground(Void... arg0) {
// get some JSON, this works fine
}
#Override
protected void onPostExecute(Void result) {
progressDialog.dismiss();
// apply to list adapter
lstLessons.setAdapter(new LessonListAdapter(Schema.this, R.layout.list_item, lessons));
}
My ArrayAdapter code:
// custom ArrayAdapter for Lessons
private class LessonListAdapter extends ArrayAdapter<Lesson> {
private ArrayList<Lesson> lessons;
public LessonListAdapter(Context context, int textViewResourceId, ArrayList<Lesson> items) {
super(context, textViewResourceId, items);
this.lessons = items;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.list_item, null);
}
Lesson o = lessons.get(position);
TextView tt = (TextView) v.findViewById(R.id.titletext);
TextView bt = (TextView) v.findViewById(R.id.timestarttext);
TextView rt = (TextView) v.findViewById(R.id.roomtext);
v.setClickable(true);
v.setFocusable(true);
tt.setText(o.title);
bt.setText(o.fmt_time_start);
rt.setText(o.room);
return v;
}
}// LessonListAdapter
The main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="#+id/main"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent" android:layout_width="fill_parent"
android:screenOrientation="portrait"
>
<!-- student name -->
<TextView
android:id="#+id/schema_view_student"
android:text="Name" android:padding="4dip"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:gravity="center_vertical|center_horizontal"
style="#style/schema_view_student"
/>
<!-- date for schema -->
<TextView
android:id="#+id/schema_view_title"
android:layout_height="wrap_content"
android:layout_margin="0dip"
style="#style/schema_view_day"
android:gravity="center_vertical|center_horizontal"
android:layout_below="#+id/schema_view_student"
android:text="Date" android:padding="6dip"
android:layout_width="fill_parent"
/>
<!-- horizontal line -->
<View
android:layout_width="fill_parent"
android:layout_height="1dip"
android:background="#55000000"
android:layout_below="#+id/schema_view_title"
/>
<!-- list of lessons -->
<ListView
android:id="#+id/lstLessons"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_below="#+id/schema_view_title"
/>
</RelativeLayout>
The list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="60px"
android:padding="12dip">
<TextView
android:id="#+id/timestarttext"
android:text="09:45"
style="#style/LessonTimeStartText"
android:layout_width="60dip"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_height="fill_parent" android:gravity="center_vertical|right" android:paddingRight="6dip"/>
<TextView
android:id="#+id/titletext"
android:text="Test"
style="#style/LessonTitleText"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_toRightOf="#+id/timestarttext"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true" android:gravity="center_vertical|center_horizontal"/>
<TextView
android:id="#+id/roomtext"
android:text="123"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
style="#style/LessonRoomText"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:gravity="center_vertical" />
</RelativeLayout>
Been messing with this for the last couple of hours and I can't seem to get my head around what the problem is. My problem looks very similar to this question, but I'm not extending ListActivity, so I still don't know where my onListClickItem() should go.
UPDATE: Now I've puzzled with this for several days and still can't find the issue.
Should I rewrite the activity, this time extending ListActivity instead of Activity? Because it provides the onItemClick method itself and is probably easier to overwrite.
Or, should I bind a listener directly in each getView() in my ArrayAdapter? I believe I have read this is bad practice (I should do as I tried and failed in my post).
Found the bug - it seems to be this issue. Adding android:focusable="false" to each of the list_item.xml elements solved the issue, and the onclick is now triggered with the original code.
I've encountered the same issue and tried your fix but couldn't get it to work. What worked for me was adding android:descendantFocusability="blocksDescendants" to the <RelativeLayout> from the item layout xml, list_item.xml in your case. This allows onItemClick() to be called.
What worked for me :
1) Adding android:descendantFocusability="blocksDescendants" to Relative Layout tag.
The result is shown below :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants" >
2) Adding android:focusable="false" to every element in in list_item.xml
example :
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:focusable="false" />
Once I had a similar problem. Every list item had a text view and a checkbox, and just because the checkbox, the whole listitem wasn't 'enabled' to fire the event. I solved it by making a little trick inside the adapter when I was getting the view.
Just before returning the view I put:
v.setOnClickListener(listener);
(The object listener is an onItemClickListener I gave to the Adapter's constructor).
But I have to tell you, the problem is because the platform, it is a bug.
I had the same problem and I tried to solve it by adding
android:focusableInTouchMode="false"
android:clickable="false"
android:focusable="false"
to my item.xml but it still doesn't work !!! Infact I found the issue in the relative layout witch contains
android:focusableInTouchMode="true" android:focusable="true"
And when I removed it All things is ok
protected void onPostExecute(Void result) {
progressDialog.dismiss(); stLessons.setAdapter(new LessonListAdapter(Schema.this, R.layout.list_item, lessons));
//add this
ListView lv = getListView(); lv.setOnItemClickListener(new ListView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> a, View v, int i, long l) {
//do stuff
}
});
}