ListActivity with selectable Items - android

To improve usability for blind users, I need a ListActivity with an OnItemSelected method to add stuff like vibration or sounds when a specific listitem is selected.
Therefore I have extended the ListActivity class and added the following methods:
protected void onListItemSelected(ListView parent, View v, int position, long id) {
}
private AdapterView.OnItemSelectedListener mOnSelectedListener = new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
onListItemSelected((ListView)parent, v, position, id);
}
public void onNothingSelected(AdapterView<?> parent) {
// TODO Auto-generated method stub
}
};
Now, when I create an instance of my new Class SelectableListActivity and override the onListItemSelected method, still nothing happens. Any Ideas? Many thanks in advance!

Problem solved. I had to override onContentChanged() and assign my listener to the ListView.
public class MyListActivity extends ListActivity {
private Vibrator vibrator;
private ListView mList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
setContentView(R.layout.station_list);
// do some other stuff
}
#Override
public void onContentChanged() {
super.onContentChanged();
mList = (ListView)findViewById(android.R.id.list);
mList.setOnItemSelectedListener(mOnSelectedListener);
}
private AdapterView.OnItemSelectedListener mOnSelectedListener = new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView parent, View v, int position, long id) {
onListItemSelected((ListView)parent, v, position, id);
}
public void onNothingSelected(AdapterView parent) {
// nothing to do here...
}
};
protected void onListItemSelected(ListView parent, View v, int position, long id) {
vibrator.vibrate(100);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
vibrator.vibrate(100);
Cursor c = cursor;
c.moveToPosition(position);
Intent i = new Intent(this, SomeOtherActivity.class);
i.putExtra(StationsDbAdapter.KEY_ROWID, id);
startActivity(i);
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
int action = event.getAction();
int keyCode = event.getKeyCode();
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_DOWN:
if (action == KeyEvent.ACTION_DOWN) {
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN));
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_DOWN));
}
return true;
case KeyEvent.KEYCODE_VOLUME_UP:
if (action == KeyEvent.ACTION_DOWN) {
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP));
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_UP));
}
return true;
case KeyEvent.KEYCODE_MENU:
if (action == KeyEvent.ACTION_DOWN) {
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER));
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER));
}
return true;
default:
return super.dispatchKeyEvent(event);
}
}
}
This way I was able to create a ListView that is usable without the touchscreen and thus possible for e.g. blind people to interact with.

Related

OnItemSelectedListener Spinner Recreate loop - Android

I have a spinner and when an item is selected i want to recreate the activity. But when the activity is recreated it keeps constantly recreating because the new itemSelectedListener is triggered. I have fixed the bug but i am interested in why this is happening. Thank you in advance for any insights you offer.
sp_lang.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
recreate();
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
You can avoid the first event with a flag in the OnItemSelectedListener.
sp_lang.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
Boolean firstEventConsumed = false;
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (firstEventConsumed) {
recreate();
} else {
firstEventConsumed = true;
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
EDIT
I have found a solution but it is just a workaround. It is not a definitive solution.
It has a strange behaviour when you recreate the activity. When the activity is created for the first time, it doesn't call twice the onItemSelected, but when it is recreated it is called twice.
What I have done below is to control when the item is selected by the user (handling the touch event) and when it is done by the activity.
public class MainActivity extends AppCompatActivity {
private Boolean isUserAction = false;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// get the spinner
// create the adapter
spinner.setAdapter(spinnerAdapter);
spinner.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
isUserAction = true;
return false;
}
});
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
if (isUserAction) {
recreate();
}
}
#Override
public void onNothingSelected(AdapterView<?> adapterView) {
// do nothing
}
});
}
}

How to handle ListView Item LongPress gesture

i have small issues in event handling , i have List view custom adapter data , each row having date , title , price . when i click on row i need to display details page but when i long press on price , date or title i need to sort the list view. i need to use gesture for on Long Press. please refer below code what i have tried.
Custom Adapter View
public EventAdapterView(Context context, List<EventUtil> eventList) {
this.mContext = context;
this.mEventUtil = eventList;
mLayoutInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
imageLoader = new DrawableManager();
}
#SuppressLint("DefaultLocale")
#SuppressWarnings("deprecation")
#Override
public View getView(int position, View convertView, ViewGroup parent) {
mView = convertView;
EventUtil eventUtil = mEventUtil.get(position);
mView = mLayoutInflater.inflate(R.layout.row_event_adapter, null);
TextView eventTitleView = (TextView) mView
.findViewById(R.id.list_view_event_title);
TextView eventDescView = (TextView) mView
.findViewById(R.id.list_view_event_location);
TextView eventDateView = (TextView) mView
.findViewById(R.id.list_view_event_price);
// final MyGestureDetector myGestureDetector= new MyGestureDetector();
// new ImageFeach().execute(mEventUtil.getEvent_Image_Url());
eventTitleView.setText(eventUtil.getEvent_Title());
// event title sorting
eventTitleView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
new MyGestureDetector() {
public void onLongPress(MotionEvent event1) {
//if (event1.getAction() == MotionEvent.ACTION_DOWN) {
Collections.sort(mEventUtil,
new Comparator<EventUtil>() {
#Override
public int compare(EventUtil obje1,
EventUtil obje2) {
return obje1
.getEvent_Title()
.compareTo(
obje2.getEvent_Title());
}
});
notifyDataSetChanged();
//}
};
}.onLongPress(event);
return true;
}
});
// event location sorting
eventDescView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
new MyGestureDetector() {
public void onLongPress(MotionEvent event1) {
//if (event1.getAction() == MotionEvent.ACTION_DOWN) {
Collections.sort(mEventUtil,
new Comparator<EventUtil>() {
#Override
public int compare(EventUtil event1,
EventUtil event2) {
return event1
.getEvent_location()
.compareTo(
event2.getEvent_location());
}
});
notifyDataSetChanged();
//}
};
}.onLongPress(event);
return true;
}
});
// event price sorting
eventDateView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
new MyGestureDetector() {
public void onLongPress(MotionEvent event1) {
// if (event1.getAction() == MotionEvent.ACTION_DOWN) {
Collections.sort(mEventUtil,
new Comparator<EventUtil>() {
#Override
public int compare(EventUtil event1,
EventUtil event2) {
return event1
.getEvent_Price()
.compareTo(
event2.getEvent_Price());
}
});
notifyDataSetChanged();
//}
};
}.onLongPress(event);
return true;
}
});
// event date sorting
ImageView dateImageView = (ImageView) mView
.findViewById(R.id.list_view_event_date);
dateImageView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
new MyGestureDetector() {
public void onLongPress(MotionEvent event1) {
//if (event1.getAction() == MotionEvent.ACTION_DOWN) {
Collections.sort(mEventUtil,
new Comparator<EventUtil>() {
#Override
public int compare(EventUtil event1,
EventUtil event2) {
return event2
.getEvent_Date()
.compareTo(
event1.getEvent_Date());
}
});
notifyDataSetChanged();
//}
};
}.onLongPress(event);
return true;
}
});
MyGestureDetector Class
public class MyGestureDetector extends SimpleOnGestureListener {
#Override
public void onLongPress(MotionEvent e) {
super.onLongPress(e);
}
}
Help Me.. Thanks
I think, there's no need to use SimpleOnGestureListener.
In your Custom Adapter View:
First,
eventTitleView.setFocusable(false);
eventTitleView.setFocusableInTouchMode(false);
eventTitleView.setLongClickable(true);
eventDescView.setFocusable(false);
eventDescView.setFocusableInTouchMode(false);
eventDescView.setLongClickable(true);
eventDateView.setFocusable(false);
eventDateView.setFocusableInTouchMode(false);
eventDateView.setLongClickable(true);
Then,
just set setOnLongClickListener (View.OnLongClickListener l) on eventTitleView, eventDescView and eventDateView as,
eventTitleView.setOnItemLongClickListener(new OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
//do your sorting stuff here
}
});
eventDescView.setOnItemLongClickListener(new OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
//do your sorting stuff here
}
});
eventDateView.setOnItemLongClickListener(new OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
//do your sorting stuff here
}
});
Hope this helps you.
Why do you need to override onlongpress?
You know this function is available by default right?
just put the price , date or title on the same Layout and give each one OnLongPressListener with the action you want..:
EXAMPLE:
http://www.mikeplate.com/2010/01/21/show-a-context-menu-for-long-clicks-in-an-android-listview/
I have done this thro onLongClickListener. It's easy using this interface . You need to do
Class YourClass implements onLongClickListener{
public boolean onLongClick(View arg0){
// Event generated when user have long pressed the screen
return false; // If you do not want the event to keep occuring again and again
}
ListView.setOnItemLongClickListener(new OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
// YOUR SORTING CODE HERE
return false;
}
});

How to use onItemLongClick to show a context menu?

I tried to get answer here but didn't get any perfect answer.
I am trying to show context menu on onItemLongClick but no success as i am using both onItemClick and onItemLongClick
i am using onItemClick to start a new activity but no success on both.
Here is the code
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.all_contacts);
contactList = new ArrayList<HashMap<String,String>>();
new LoadAllContacts().execute();
registerForContextMenu(getListView());
ListView listView = getListView();
listView.setOnItemLongClickListener(new OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view,
int postion, long id) {
registerForContextMenu( view );
openContextMenu( view );
return true;
}
});
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int postion, long id) {
Intent intent = new Intent(AllContactsActivity.this, editContactActivity.class);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == 100)
{
Intent intent = getIntent();
finish();
startActivity(intent);
}
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.listview_menu, menu);
}
#Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.editContactMI:
Intent i = new Intent(getApplicationContext(), editContactActivity.class);
i.putExtra(TAG_ID, cId);
i.putExtra(TAG_NAME, cName);
i.putExtra(TAG_CONTACT_NO, cNumber);
startActivityForResult(i, 100);
cId = null;
cName = null;
cNumber = null;
break;
case R.id.deleteContactMI :
new DeleteContact().execute();
break;
case R.id.saveContactMI:
break;
default:
cId = null;
cName = null;
cNumber = null;
break;
}
return true;
}
I am trying to show context menu on onItemLongClick
To use the context menu system, you do not implement an OnItemLongClickListener. Instead, you call registerForContextMenu() (e.g., from onCreate() of the activity). Simply delete your OnItemLongClickListener from your code shown above, and you should have better luck.
Try this:
listView.setOnItemLongClickListener(this);
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
Cursor c_index = (Cursor) parent.getItemAtPosition(position);
detail_id = c_index.getInt(c_index.getColumnIndexOrThrow(DbAdapter.KEY_RID));
registerForContextMenu( parent );
openContextMenu( parent );
return true;
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
if (v.getId()==R.id.list) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_context, menu);
}
}
#Override
public boolean onContextItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.action_details:
//some code
return true;
case R.id.action_share:
//some code
return true;
case R.id.action_del:
//enter code here`
return true;
default:
return super.onContextItemSelected(item);
}
}

how to implement a long click listener on a listview

I want to add OnLongClickListener on my list view. Whenever the user long press the item in list some action should be performed, But my code does not catch this listener. Please let me know where I am going wrong. The similar code works for setOnItemClickListener very well.
Here is the code :
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView<?> arg0, View v,
int index, long arg3) {
// TODO Auto-generated method stub
Log.d("in onLongClick");
String str=listView.getItemAtPosition(index).toString();
Log.d("long click : " +str);
return true;
}
});
You have to set setOnItemLongClickListener() in the ListView:
lv.setOnItemLongClickListener(new OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
int pos, long id) {
// TODO Auto-generated method stub
Log.v("long clicked","pos: " + pos);
return true;
}
});
The XML for each item in the list (should you use a custom XML) must have android:longClickable="true" as well (or you can use the convenience method lv.setLongClickable(true);). This way you can have a list with only some items responding to longclick.
Hope this will help you.
If your ListView row item refers to a separate XML file, be sure to add android:longClickable="true" to that layout file in addition to setting setOnItemLongClickListener() to your ListView.
or try this code:
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView<?> arg0, View v,
int index, long arg3) {
Toast.makeText(list.this,myList.getItemAtPosition(index).toString(), Toast.LENGTH_LONG).show();
return false;
}
});
I think this above code will work on LongClicking the listview, not the individual items.
why not use registerForContextMenu(listView). and then get the callback in OnCreateContextMenu.
For most use cases this will work same.
In xml add
<ListView android:longClickable="true">
In java file
lv.setLongClickable(true)
try this setOnItemLongClickListener()
lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int pos, long l) {
//final String category = "Position at : "+pos;
final String category = ((TextView) view.findViewById(R.id.textView)).getText().toString();
Toast.makeText(getActivity(),""+category,Toast.LENGTH_LONG).show();
args = new Bundle();
args.putString("category", category);
return false;
}
});
this should work
ListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
int pos, long id) {
// TODO Auto-generated method stub
Toast.makeText(getContext(), "long clicked, "+"pos: " + pos, Toast.LENGTH_LONG).show();
return true;
}
});
also don't forget to in your xml android:longClickable="true" or if you have a custom view add this to your custom view class youCustomView.setLongClickable(true);
here is the output of the code above
I tried most of these answers and they were all failing for TextViews that had autolink enabled but also had to use long press in the same place!
I made a custom class that works.
public class TextViewLinkLongPressUrl extends TextView {
private boolean isLongClick = false;
public TextViewLinkLongPressUrl(Context context) {
super(context);
}
public TextViewLinkLongPressUrl(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TextViewLinkLongPressUrl(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public void setText(CharSequence text, BufferType type) {
super.setText(text, type);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP && isLongClick) {
isLongClick = false;
return false;
}
if (event.getAction() == MotionEvent.ACTION_UP) {
isLongClick = false;
}
if (event.getAction() == MotionEvent.ACTION_DOWN) {
isLongClick = false;
}
return super.onTouchEvent(event);
}
#Override
public boolean performLongClick() {
isLongClick = true;
return super.performLongClick();
}
}
This worked for me for cardView and will work the same for listview inside adapter calss, within onBindViewHolder() function
holder.cardView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
return false;
}
});
If you want to do it in the adapter, you can simply do this:
itemView.setOnLongClickListener(new View.OnLongClickListener()
{
#Override
public boolean onLongClick(View v) {
Toast.makeText(mContext, "Long pressed on item", Toast.LENGTH_SHORT).show();
}
});
listView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
return false;
}
});
Definitely does the trick.

How to set specific context menu depending on which item is long-pressed in a ListActivity?

I have a list activity, and I chose to manually add the first item which is "add new item...".
I have registered the context menu for the whole listview, using registerForContextMenu(getListView()); straight into the onCreate.
When the context menu is build, the system calls onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo). The View v is the listView, and I cannot find a way to know which item in the listview is being long-pressed.
I could create a xml layout, with a layout for the "add new item..." and add a listview after, which would be populated by the activity, and that would react to the context menu, but I'm sure there is a way to solve this problem without any xml layout.
I have tried to register each view inside my listview using registerForContextMenu, which works, however the listview doesn't respond to touch anymore.
Here is my activity code listing:
public class AMain extends ListActivity {
private List<String> pregList;
private List<Long> pregIds;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pregList = new ArrayList<String>();
pregIds = new ArrayList<Long>();
registerForContextMenu(getListView());
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
// TODO: hide the menu for the 1st item!!
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.context_menu, menu);
}
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
Logger.d("id = "+info.id);
switch (item.getItemId()) {
case R.id.menu_show:
showPregnancy((int) info.id);
return true;
case R.id.menu_edit:
editPregnancy((int) info.id);
return true;
case R.id.menu_delete:
//TODO: do the deletion
return true;
default:
return super.onContextItemSelected(item);
}
}
protected void onStart() {
super.onStart();
clearPregList();
loadPregList();
getListView().setAdapter(new PregnancyListAdapter(this));
}
void clearPregList() {
pregList.clear();
pregIds.clear();
}
void loadPregList() {
PregnanciesDbAdapter db = new PregnanciesDbAdapter(this);
db.open();
Cursor c = db.getPregnancies();
if (c != null) {
do {
pregList.add(c.getString(c.getColumnIndex(PregnanciesDbAdapter.KEY_PREG_NOM)));
pregIds.add(c.getLong(c.getColumnIndex(PregnanciesDbAdapter.KEY_PREG_ROWID)));
} while (c.moveToNext());
c.close();
}
db.close();
}
private class PregnancyListAdapter extends BaseAdapter {
private Context context;
public PregnancyListAdapter(Context ctx) {
context = ctx;
}
#Override
public int getCount() {
return pregList.size()+1;
}
#Override
public Object getItem(int position) {
if (position == 0) { // add button
return getString(R.string.addPreg);
} else {
return pregList.get(position-1);
}
}
#Override
public long getItemId(int position) {
if (position == 0) {
return -1;
}
return pregIds.get(position-1);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LinearLayout itemLayout;
itemLayout= (LinearLayout) LayoutInflater.from(context).inflate(R.layout.homelist_item_pregnancy, parent, false);
ImageView logo = (ImageView) itemLayout.findViewById(R.id.logo);
TextView pregName = (TextView) itemLayout.findViewById(R.id.pregName);
if (position == 0) {
itemLayout.setFocusable(false);
itemLayout.setFocusableInTouchMode(false);
pregName.setText(getString(R.string.addPreg));
} else {
logo.setVisibility(View.INVISIBLE);
pregName.setText(pregList.get(position-1));
}
itemLayout.setId(position);
return itemLayout;
}
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
if (position == 0) {
startActivity(prepareIntent(AShowPregnancy.class, 0));
} else {
showPregnancy(position-1);
}
}
void showPregnancy(int pregId) {
startActivity(prepareIntent(AShowPregnancy.class, pregId));
}
void editPregnancy(int pregId) {
startActivity(prepareIntent(ANewPregnancy.class, pregId));
}
Intent prepareIntent(Class<?> className, int pregId) {
Intent i = new Intent(this, className);
if (pregId > 0) {
PregnanciesDbAdapter db = new PregnanciesDbAdapter(this);
db.open();
Pregnancy p = db.load(pregIds.get(pregId));
db.close();
i.putExtra(C.EXTRA_PREGNANCY, p);
}
return i;
}
}
Thanks for reading. Hope you can help.
Oh, god, again. I found out myself how to do it, and it was easier than easy.
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
// info.position is the position in the ListView
I hate myself :)

Categories

Resources