I'm having a problem with OnItemClickListener on a ListView, the OnItemClick overridden method is not triggered... Here's my code:
public void popupCatCategories(){
LayoutInflater layoutInflater = (LayoutInflater)getBaseContext().getSystemService(LAYOUT_INFLATER_SERVICE);
View popupCatCategoriesView = layoutInflater.inflate(R.layout.popup_cats_categories, null);
final PopupWindow popupWindow = new PopupWindow(popupCatCategoriesView, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
Button btnDismiss = (Button) popupCatCategoriesView.findViewById(R.id.dismiss);
btnDismiss.setOnClickListener(new Button.OnClickListener(){
public void onClick(View v) {
// TODO Auto-generated method stub
popupWindow.dismiss();
}
});
// listview to display image and text
ListView listCatCategories = (ListView) popupCatCategoriesView.findViewById(R.id.listCatCategories);
List<HashMap<String, String>> listCategories = new ArrayList<HashMap<String, String>>();
db.open();
Cursor catCategories = db.getAllCatCategoryList();
if (catCategories.moveToFirst())
{
do {
HashMap<String, String> hm = new HashMap<String, String>();
hm.put("catCategoryThumbnail", Integer.toString(catCategories.getInt(1)));
hm.put("catName", catCategories.getString(0));
listCategories.add(hm);
} while (catCategories.moveToNext());
}
db.close();
listCatCategories.setAdapter(new ItemListBaseAdapter(getApplicationContext(), listCategories));
Log.i("got it?", "wait for it...");
listCatCategories.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> a, View view, int position, long id) {
Log.i("got it?", "yea, got it!");
Toast.makeText(getBaseContext(), "got it", Toast.LENGTH_SHORT).show();
}
});
popupWindow.showAsDropDown(btnCats, 50, -330);
}
I'm simply adding some values in an ArrayList of HashMap, each HashMap contains 2 String variables, which are displayed in each row of the ListView. There is only an ImageView and a TextView inside a RelativeLayout for the custom xml layout of the ListView. It displayed fine, except that then I click on a row, nothing happens, it does not trigger the Log or anything. The Overridden method onItemClick is not triggered at all.
I've already tried to setClickable(true) or setItemsCanFocus(false) on the ListView, or setFocusable(false) and setFocusableInTouchMode(false) on the ImageView and TextView (even though its applicable for Checkboxes and Buttons right?).
Here's the custom xml for the ListView:
<?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="fill_parent" >
<ImageView
android:id="#+id/catCategoryThumbnail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:paddingRight="10dp"
android:paddingTop="10dp" />
<TextView
android:id="#+id/txtCatCategoryName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15dp"
android:focusable="false"
android:focusableInTouchMode="false" />
</RelativeLayout>
Anyway, I don't know what to do anymore, can anyone please help me?
If you need anymore information, please let me know. Thanks
The reason your view isn't accepting the event is because the TextView (which is focusable) is overriding it and taking all touch/click action for itself.
You just have to set these for the TextView:
android:focusable="false"
android:focusableInTouchMode="false"
Found an alternate solution: https://stackoverflow.com/a/6579192/1759005. It's working just as fine.
Related
What I'm trying to do is to have a listview item with a button in each list viewitem.
When the Buttton is being pressed I want a layout that is at gone state will be visible and expand with animation down, and if the layout is shown than when the same button is being preesed than the layout will slide up and be gone again.
In order to do so I've created the next layout for the listview item -
<?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="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/tilte_info">
<TextView
android:id="#+id/textView_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="15dp"
android:text="TextView"
android:textSize="20sp" />
<Button
android:id="#+id/button_open"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="25dp"
android:text="Open" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#5C83AF"
android:visibility="gone"
android:id="#+id/extend_info">
<TextView
android:id="#+id/textView_more_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="15dp"
android:text="TextView"
android:textSize="20sp" />
</LinearLayout>
</LinearLayout>
As you can see there are two layouts - one is tilte_info which is always shown and have the button in it, and the other one is extend_info which will be shown or hide by the button click.
Now I've used the next code in order to try and make it work -
public class MainActivity extends Activity {
ArrayList<Place> placesList = new ArrayList<Place>();
placeAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Place place1 = new Place("Place num 1", "some info on place 1");
Place place2 = new Place("Place num 2", "some info on place 2");
Place place3 = new Place("Place num 3", "some info on place 3");
placesList.add(place1);
placesList.add(place2);
placesList.add(place3);
ListView lv = (ListView) findViewById(R.id.listview_1);
adapter = new placeAdapter(this);
lv.setAdapter(adapter);
}
class placeAdapter extends ArrayAdapter<Place> implements OnClickListener{
public placeAdapter(Context context) {
super(context, -1, placesList);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView==null){
// use the LayoutInflater to inflate an XML layout file:
convertView=getLayoutInflater().inflate(R.layout.list_item, parent,false);
}
TextView textTitle = (TextView) convertView.findViewById(R.id.textView_title);
TextView textInfo = (TextView) convertView.findViewById(R.id.textView_more_info);
Button open = (Button) convertView.findViewById(R.id.button_open);
infoLayout = (View) convertView.findViewById(R.id.extend_info);
infoLayout.setVisibility(View.GONE);
open.setOnClickListener(this);
Place place = placesList.get(position);
textTitle.setText(place.getTitle());
textInfo.setText(place.getInfo());
return convertView;
}
#Override
public void onClick(View v) {
if(infoLayout.isShown()){
slide_up(MainActivity.this, infoLayout);
infoLayout.setVisibility(View.GONE);
}else{
infoLayout.setVisibility(View.VISIBLE);
slide_down(MainActivity.this, infoLayout);
}
}
}
public static void slide_down(Context ctx, View v){
Animation a = AnimationUtils.loadAnimation(ctx, R.anim.slide_down);
if(a != null){
a.reset();
if(v != null){
v.clearAnimation();
v.startAnimation(a);
}
}
}
public static void slide_up(Context ctx, View v){
Animation a = AnimationUtils.loadAnimation(ctx, R.anim.slide_up);
if(a != null){
a.reset();
if(v != null){
v.clearAnimation();
v.startAnimation(a);
}
}
}
}
The thing is that I tried to debug the code and it getting into the onclick function but nothing is happening - the layout that is gone not been shown.
I've chacked the animation code with simple textview outside the listview and it worked, but when im trying to use it in the listview item, it doesn't work.
Any ideas why?
Thanks for any kind of help
Use ExpandableListView. You have to extend the BaseExpandableListAdapter to your adapter and override methods. In this methods, override getGroupView to display the name of expandablegroup and override getChildView method to inflate the child view for list. After inflating the layout for child, set whatever animation you want on that view.
you shoud use expandableview for it...
basic example fot that is here... expandavlelistview example
I'm building an Android application using ListView. I have list view items as show below.
^ List Item Index 0
^ List Item Index 1
The xlm is as follows.
<?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"
android:padding="4dip" >
<ImageView
android:id="#+id/icon"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:src="#drawable/icon" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_weight="0.93"
android:orientation="vertical"
android:padding="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp" >
<!-- JFN bottom used to be 2, top 6 -->
<!-- Name Label -->
<TextView
android:id="#+id/name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="0dip"
android:paddingTop="0dip"
android:textColor="#43bd00"
android:textSize="16sp"
android:textStyle="bold" />
<!-- Email label -->
<TextView
android:id="#+id/email"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="0dip"
android:textColor="#acacac" />
<!-- Mobile number label -->
<TextView
android:id="#+id/mobile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="left"
android:text="Mobile: "
android:textColor="#5d5d5d"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:orientation="vertical" >
<ImageView
android:id="#+id/chat"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_marginRight="2dip"
android:gravity="right"
android:src="#drawable/chat" />
<ImageView
android:id="#+id/calendar"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_marginRight="2dip"
android:gravity="right"
android:src="#drawable/calendar" />
</LinearLayout>
</LinearLayout>
I'm trying to detect four different click events:
When the picture of the dog is clicked
When the middle section is clicked
When the chat button is clicked
When the calendar button is clicked
In addition, each of these clicks must be distinguishable based on which item in the ListView has been clicked.
I know how I can tell each ListItem apart: I can use the ListView.setOnItemClickListener as is shown below, which provides an id of the item in the list. But this does not tell me which of the four portions was clicked on.
ListView lv = getListView();
// Listview on item click listener
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// getting values from selected ListItem
Log.d("JFN","List item clicked with id: "+id);
}
});
I can also bind a different onClick function call to each of the four sections in the xml, but this doesn't let me know which of the list items was clicked.
android:onClick="imgClicked"
I don't think I can combine these two solutions, as it would introduce a race condition. Is there a proper way to accomplish detecting both which list item was clicked, and which part of that particular list item was clicked?
Further Info
The following code shows my creation of the ListView using the adapter.
// Retrieve string, convert to JSON, and extract contacts
String jsonData = jsonToStringFromAssetFolder("maemployees.json",this);
JSONObject jsonObj = new JSONObject(jsonData).getJSONObject(TAG_RESULTS);
int numContacts = jsonObj.getInt(TAG_NUM);
Log.d("JFN","Number of contacts stated: "+numContacts);
contacts = jsonObj.getJSONArray(TAG_CONTACTS);
Log.d("JFN","Number of contacts present: "+contacts.length());
// Loop over contacts
for( int i=0; i<contacts.length(); i++) {
// Extract this one
JSONObject c = contacts.getJSONObject(i);
// Extract strings
String first = (c.has(TAG_FIRST)) ? c.getString(TAG_FIRST) : "";
String last = (c.has(TAG_LAST)) ? c.getString(TAG_LAST) : "";
String city = (c.has(TAG_CITY)) ? c.getString(TAG_CITY) : "";
String state = (c.has(TAG_STATE)) ? c.getString(TAG_STATE) : "";
String country = (c.has(TAG_COUNTRY)) ? c.getString(TAG_COUNTRY) : "";
String costName = (c.has(TAG_COST_NAME)) ? c.getString(TAG_COST_NAME) : "";
// Temporary hash map for single contact
HashMap<String, String> contact = new HashMap<String, String>();
contact.put("name", first+" "+last);
contact.put("email", city+", "+state+", "+country);
contact.put("mobile", costName);
// Adding single contact to list
contactList.add(contact);
}
Log.d("JFN","Done looping contacts");
//Updating parsed JSON data into ListView
ListAdapter adapter = new SimpleAdapter(
MainActivity.this, contactList,
R.layout.list_item, new String[] { "name", "email",
"mobile" }, new int[] { R.id.name,
R.id.email, R.id.mobile });
setListAdapter(adapter);
Allright I was having a similar kind of problem but i was using a ViewPager with a ListFragment and a custom ListView Layout.
In the above case you are using just ImageViews, but just in case if you use controls like ImageButton, CheckBox ,Button etc then you would face problems discussed here and here.
This is simply because such controls can steal focus from the ListView and the complete list item cant be selected/clicked. so I would say that just using ImageViews is a smart move.
I am assuming that you are using an Adapter to set the content of your list. Inside that adapter you can assign onClickListener()s for each item like this:
public class MyListAdapter extends ArrayAdapter<String>{
.......
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView=inflator.inflate(R.layout.channel_list_item, null, true);
ImageView chat=(ImageView) rowView.findViewById(R.id.chat);
chat.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//do something
}
}
ImageView calendar=(ImageView) rowView.findViewById(R.id.calendar);
calendar.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//do something
}
}
.......
}
}
but remember that while using controls like ImageButton, CheckBox ,Button you need to assign property android:focusable="false" in the XML. and for the ImageButton you need to do this inside the getView() method:
final ImageButton imgBtn=(ImageButton) rowView.findViewById(R.id.imgBtn);
imgBtn.setFocusable(false);
imgBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//do your task here
}
});
or you can also use Nathaniel Waggoner's approach.
Hope I answered your question.
You must be setting the content of your list view in an Adapter, So inside the adapter, there is a method getView(). Inside that getView() define each of your view and then set onCLickListener inside those view.
For Ex:
dog.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//operation to be performed.
}
});
similarly apply onCLickListeners() to all other views.
If you don't want to set on click listeners for each item, the other option is to compare the view.getId() value of the view passed into on click, to the ids of the views, something like:
switch(view.getId()){
case(R.id.dog_image):
//do stuff
break;
case(R.id.other_image):
//do stuff
break;
}
Otherwise you can do this programatically by doing the following in onCreate:
.....
setContentView(myView);
ImageView dogImage = (ImageView) findViewById(R.id.dog_image);
dogImage.setOnClickListener(new View.OnClickListener {
#Override
public void onClick(View v) {
// do stuff...
}
})
....
I have a custom Listview with 1 Button on a row
I would like to add a button outside the Listview to set the visibility on button on all rows
How can i achieve this?
And i DONT wanna use notifyDataSetChanged that reload all data
Anyone got an idea of this??
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/notice_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:textSize="16dp" />
<TextView
android:id="#+id/notice_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/notice_title"
android:textSize="8dp" />
<ImageButton
android:id="#+id/btn_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/btn_delete"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:visibility="invisible" />
</RelativeLayout>
Adapter_notice.java
public class Adapter_notice extends ArrayAdapter<notice> {
private Context context;
private int listRow;
private notice[] notice;
public List<String> listTag = new ArrayList<String> ();
public Adapter_notice(Context context, int listRow, notice[] Rows) {
super(context, listRow, Rows);
this.listRow = listRow;
this.context = context;
this.notice = Rows;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row;
//Log.d("edittext", "items !empty="+listTag.contains(listTag.get(position)));
LayoutInflater inflater = LayoutInflater.from(context);
row = inflater.inflate(listRow,parent, false);
notice row_notice = notice[position];
TextView tv1 = (TextView) row.findViewById(R.id.notice_title);
tv1.setText(row_notice.gettitle());
TextView tv2 = (TextView) row.findViewById(R.id.notice_date);
tv2.setText("Date:"+row_notice.getdate());
ImageButton btn = (ImageButton) row.findViewById(R.id.btn_delete);
return row;
}
}
I have a custom Listview with 1 button on a row I would like to add a
button outside the Listview to set the visibility on button on all
rows How can i achieve this?
And i DONT wanna use notifyDataSetChanged that reload all data Anyone
got an idea of this??
Create layout that contains ListView and Button. ListView has set height to WRAP_CONTENT.
Then create onClickListener for Button and onClick() hide your ListView:
btn.setOnClickListener(new View.OnClickListener {
public void onClick(View v) {
if (listView.getVisibility() == ListView.VISIBLE) {
listView.setVisibility(ListView.INVISIBLE);
}
else {
listView.setVisibility(ListView.VISIBLE);
}
}
});
Note: Difference between INVISIBLE and GONE is that GONE property doesn't take place in layout.
in onClick() of the button outside the list, do something like
listview.setAdapter(changedAdapter)
Where changedAdapter will be a new set of adapter OR
adapter.setButtonVisibility(false);
listview.setAdapter(adapter).
Create a new method in your Adapter class which sets a boolean value based on which the getView will return view (if boolean is true, Button field will be made invisible)
public void setButtonVisibility(boolean hideButton){
this.hideButton = hideButton;
}
getView(){
...
if(hideButton){
//hide button
}
}
Use
ListView.setVisibility(View.GONE / View.VISIBLE / View.INVISIBLE);
Since you want to temporarily disable the visibility use View.INVISIBLE and View.VISIBLE
In your OnClickListener() of the decider button ,set the Adapter again for the list .
and keep a public Boolean variable outside the List to decide visibility of the specific button, by validating Boolean variable.
on button click event add
yourListView.setVisiblity(View.INVISIBLE);
to hide the list view
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
}
});
}
I am trying to build a simple sms app for which edit page lists all the saved smses. I gave 2 buttons in my layout for Edit and Delete but when I am clicking on them I am unable to get the rowid (row number from top) to retrieve the sms corresponding to that particular row.. Somebody please help me..my sms adapter is not not extending anything..Here's my class and xml files..
public class SMSEdit extends ListActivity{
private SMSDbAdapter mDbHelper;
//private Button editsmsbtn, deletesmsbtn;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.editsmslist);
mDbHelper = new SMSDbAdapter(this);
mDbHelper.open();
fillData();
}
public void fillData() {
Cursor smsCursor = mDbHelper.fetchAllNotes();
startManagingCursor(smsCursor);
// Create an array to specify the fields we want to display in the list (only TITLE)
String[] from = new String[]{SMSDbAdapter.KEY_TITLE,
SMSDbAdapter.KEY_BODY,
SMSDbAdapter.KEY_DATE,
SMSDbAdapter.KEY_TIME};
// and an array of the fields we want to bind those fields to (in this case just text1)
int[] to = new int[]{R.id.smseditlistTO,
R.id.smseditlistMessage,
R.id.smseditlistDay,
R.id.smseditlistTime};
// Now create a simple cursor adapter and set it to display
SimpleCursorAdapter smsadap =
new SimpleCursorAdapter(this, R.layout.smsrow, smsCursor, from, to);
setListAdapter(smsadap);
}
public void myEditClickHandler(View v)
{
//get the row the clicked button is in
LinearLayout vwParentRow = (LinearLayout)v.getParent();
Button btnChild = (Button)vwParentRow.getChildAt(4);
btnChild.setText("I've been clicked!");
ListAdapter pos = getListAdapter();
Intent intent = new Intent();
intent.setClass(SMSEdit.this, SMS.class);
// intent.putExtra(SMSDbAdapter.KEY_ROWID, id);
startActivity(intent);
finish();
}
public void myDeleteClickHandler(View v)
{
//get the row the clicked button is in
LinearLayout vwParentRow = (LinearLayout)v.getParent();
//TextView child = (TextView)vwParentRow.getChildAt(0);
Button btnChild = (Button)vwParentRow.getChildAt(5);
//btnChild.setText(child.getText());
btnChild.setText("I've been clicked!");
int c = Color.CYAN;
vwParentRow.setBackgroundColor(c);
vwParentRow.refreshDrawableState();
}
}
editsmslist.xml -- >>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ListView android:id="#+id/android:list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView android:id="#+id/android:empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="No Future SMS Yet" android:textSize="35px"/>
</LinearLayout>
smsrow.xml -- >>
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
android:id="#+id/ScrollView01"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:id="#+id/LinearLayout02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout android:id="#+id/LinearLayout03" android:layout_width="wrap_content" android:layout_height="wrap_content">
<TextView android:layout_height="wrap_content" android:layout_width="fill_parent" android:text="#string/smsdetailseditlist" android:id="#+id/smseditlistTO" android:paddingLeft="5px">
</TextView>
<TextView android:layout_height="wrap_content" android:text="#string/smsdetailseditlist" android:id="#+id/smseditlistMessage" android:paddingLeft="20px" android:maxLines="1" android:layout_width="wrap_content">
</TextView>
</LinearLayout>
<LinearLayout android:id="#+id/LinearLayout01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" android:paddingLeft="5px">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Date: "></TextView><TextView android:text="#string/smsdetailseditlist" android:id="#+id/smseditlistDay" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Time: " android:paddingLeft="5px"> </TextView><TextView android:text="#string/smsdetailseditlist" android:id="#+id/smseditlistTime" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingRight="10px"></TextView>
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="#+id/EditSMSButton" android:text="#string/editsms" android:onClick="#string/myEditClickHandler"></Button>
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="#+id/DeleteSMSButton" android:text="#string/deletesms" android:onClick="#string/myDeleteClickHandler"></Button>
</LinearLayout>
</LinearLayout>
</ScrollView>
Also Please suggest if there'a yn better way to implement this or make the layout look better...
You can extend a cursorAdapter like this...
public class exampleAdapter extends CursorAdapter
{
LayoutInflater inflater;
public exampleAdapter (Context context, Cursor c) {
super(context, c);
inflater = LayoutInflater.from(context);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
// TODO Auto-generated method stub
Button btn_del = (Button)view.findViewById(R.id.button1);
btn_del.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
SMSDbAdapter vb = new SMSDbAdapter(context);
vb.open();
String xyz = cursor.getString(0); //Persumably your ID
vb.Delete(Integer.parseInt(cursor.getString(0)));
Toast.makeText(context, xyz + " Deleted!", Toast.LENGTH_SHORT).show();
vb.close();
}
});
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return inflater.inflate(R.layout.smsrow, parent, false);
}
}
I had a similar problem with my ListView.
Assume you are filling a ListView dynamically. You have 5 rows (for example). The id of first row is 1 second is 2 and so on.
When you scroll whatever rows are visible to you, the id of the 1st row (that you currently see on screen) will always be 1. You need to control that by using mabye some another class (XYZ).
I simply used ArrayList<XYZ> and that worked.
You can override this method in your SMSAdapter:
public View getView(int position, View convertView, ViewGroup parent)
and then call the get(position) method that returns an ArrayList<XYZ>.
You should use ListView to display your messages.
Store the data retrieved from database in a Array of Strings say s1.
Then
private ArrayList<String> arr_sort = new ArrayList<String>();
And copy whole s1 into arr_sort by using add() method.
While setting adapter
lv.setAdapter(new ArrayAdapter<String>(DataAttach.this,
android.R.layout.simple_list_item_1, arr_sort));
where lv is the ListView refernce.
Then use this method for onClick
lv.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
String item = (String) lv.getItemAtPosition(position);
Toast.makeText(*.this,
"You selected - " + item + " ,Please wait...",
Toast.LENGTH_LONG).show();
Intent intent = new Intent(*.this, *.class);
*.this.startActivity(intent);
}
});
Hope this helps..