I have a ListView displayed on my screen.
When I click on an item (using setOnItemClickListener), you can rename it.
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick() {}
When I hold on an item (using setOnItemLongClickListener), you can delete it.
listview.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick() {}
However, when i hold on an item, it displays the "rename" window and the "delete" window, as if both were triggered.
Any idea on how to prevent this?
Thanks a lot
Try this
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view,
int position, long id) {
return true; //<-- this should be TRUE, not FALSE
}
Input Events This returns a boolean to indicate whether you have consumed the event and it should not be carried further.
If it return true to indicate that you have handled the event and it should stop here.
If it return false if you have not handled it and the event should continue to any other on-click listeners.
You can use setTimeout and .bind to fix your problem with the shortest amount of logic:
var timeoutId = 0;
$('#myElement').mousedown(function() {
timeoutId = setTimeout(myFunction, 1000);
}).bind('mouseup mouseleave', function() {
clearTimeout(timeoutId);
});
Related
In my onBindViewHolder of my RecyclerView.Adapter<SearchAdapter.ViewHolder> when user clicks on cardview a button becomes visible. But when I'm scrolling recyclerview some other items buttons are shown as visible too. Why is this happening?
this is my code:
#Override
public void onBindViewHolder(final ViewHolder viewHolder, final int position) {
viewHolder.card.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (viewHolder.content_layout.getVisibility() == View.VISIBLE) {
viewHolder.content_layout.setVisibility(View.GONE);
viewHolder.address.setMaxLines(2);
viewHolder.attribute.setMaxLines(2);
} else {
viewHolder.content_layout.setVisibility(View.VISIBLE);
viewHolder.address.setMaxLines(8);
viewHolder.attribute.setMaxLines(8);
}
}
});
...
}
Once you start scrolling down the list your views get recycled. This means a previously inflated ViewHolder (some that gets created in onCreateViewHolder) is reused.
So what you have to do is to remember the clicked positions (e.g. via a SparseBooleanArray) and check in onBindViewHolder whether the view should be visible (previously clicked) or not.
You can find a basic usage example of the SparseBooleanArray in this StackOverflow post
The 'other' visible items buttons are the ones using the same viewholder that was modified in the callback. So because viewholders (and views) are recycled :
They should only store information that can be retrieved each time the viewholder is bound to a position.
Anything that may be changed in the views state should be refreshed in onBindViewHolder()
In your case you should store the 'is selected' somewhere else and reset the visibility and maxlines in onBindViewHolder() (not only in the callback)
Good idea is to make a class object with all data you need for one item in recycler view, also add there one boolean isItemWasClicked and inside onBindViewHolder() check this boolean and make buttons visible or not.
For example:
public class OneItemOfList{
int priceToDisplay;
String name;
String date;
boolean wasClicked;
}
public class YourAdapter extends RecyclerView.Adapter<OneItemOfList.ViewHolder> {
ArrayList<OneItemOfList> items;
...
#Override
public void onBindViewHolder(ViewHolder viewHolder, final int position) {
viewHolder.view.setText(items.get(position).name);
if (items.get(position).wasClicked)
viewHolder.button.setVisible(View.VISIBLE);
else
viewHolder.button.setVisible(View.GONE);
viewHolder.view2.setOnClickListener(...
OnClick(...){
items.get(position).wasClicked = !items.get(position).wasClicked;
});
}
...
}
create an array for example Boolean array, and when each position clicked, set true in same position of array. and in onBindViewHolder check if that array[position] is true set that item visible if.
I have a spinner and I want to detect when the user clicked on it.
When the user clicks it open, I want to call an endpoint and then update the spinner with new data.
But I couldn't figure out how to do this and results in infinite loop:
I call the API in here:
public View getDropDownView(int position, View convertView, ViewGroup parent) {
// Call API here
// Do render with old data.
}
when the API successes, I call the to update:
#Override
public void onSuccess(final Response response) {
Helper.update(...);
}
public void update(...) {
...
adapter.setItems(newData);
adapter.notifyDataSetChanged();
}
and then this triggers getDropDownView() again. I couldn't figure out what else is called after the user clicks open the spinner besides getDropDownView(). How can I solve this problem?
You can set Touch-listener on Spinner to detect click.
findViewById(R.id.spinner).setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Toast.makeText(MainActivity.this,"CallAPI",Toast.LENGTH_SHORT).show();
return false;
}
});
And return False from onTouch to behave normally.I hope It will work for you.
Have to ask for help. I'm new to developing for Android, and I have got a question on how to assign the onTouch event to child element ExpandableListView. I added elements dynamically (parent and child) made like this, is there some way to that onChildClick could continue to assign event onTouch?
Try returning false in the onChildClick method. Normally this means that the event has not been processed. If you return false, the event should be passed down.
elv.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
#Override
public boolean onChildClick(ExpandableListView parent, View v){
return false;
}
});
I am trying to implement a drag and drop in a ListView in android(Ice Cream Sandwich). So when the dragged object reaches the edge of the ListView, I am scrolling the ListView in the relevant direction. The problem is that when we scroll, sometimes the adapter creates new Views as necessary and these 'new' Views did not receive the ACTION_DRAG_STARTED event earlier and hence do not receive the DragEvent updates. Is there any way I can send the events to these views as well?
An easiest way to implement drag and drop in listview is you use this great library.
https://github.com/commonsguy/cwac-touchlist
it's worth trying.
Looking at the source for View, I see:
static final int DRAG_CAN_ACCEPT = 0x00000001;
int mPrivateFlags2;
boolean canAcceptDrag() {
return (mPrivateFlags2 & DRAG_CAN_ACCEPT) != 0;
}
mPrivateFlags2 is package-private and not exposed by the SDK. However, you should be able to change it in a subclass by doing:
try {
Field mPrivateFlags2 = this.getClass().getField("mPrivateFlags2");
int currentValue = mPrivateFlags2.getInt(this);
mPrivateFlags2.setInt(this, currentValue | 0x00000001);
} catch (Exception e) {
}
I have the same problem. I did not solved this recycling problem, but I found a possible workaround still using the Drag & Drop framework. The idea is to change of perspective: instead of using a OnDragListener on each View in the list, it can be used on the ListView directly.
Then the idea is to find on top of which item the finger is while doing the Drag & Drop, and to write the related display code in the ListAdapter of the ListView. The trick is then to find on top of which item view we are, and where the drop is done.
In order to do that, I set as an id to each view created by the adapter its ListView position - with View.setId(), so I can find it later using a combination of ListView.pointToPosition() and ListView.findViewById().
As a drag listener example (which is, I remind you, applied on the ListView), it can be something like that:
// Initalize your ListView
private ListView _myListView = new ListView(getContext());
// Start drag when long click on a ListView item
_myListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
view.startDrag(null, shadowBuilder, _myListView.getItemAtPosition(position), 0);
return true;
}
});
// Set the adapter and drag listener
_myListView.setOnDragListener(new MyListViewDragListener());
_myListView.setAdapter(new MyViewAdapter(getActivity()));
// Classes used above
private class MyViewAdapter extends ArrayAdapter<Object> {
public MyViewAdapter (Context context, List<TimedElement> objects) {
super(context, 0, objects);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View myView = convertView;
if (myView == null) {
// Instanciate your view
}
// Associates view and position in ListAdapter, needed for drag and drop
myView.setId(position);
return myView;
}
}
private class MyListViewDragListener implements View.OnDragListener {
#Override
public boolean onDrag(View v, DragEvent event) {
final int action = event.getAction();
switch(action) {
case DragEvent.ACTION_DRAG_STARTED:
return true;
case DragEvent.ACTION_DRAG_DROP:
// We drag the item on top of the one which is at itemPosition
int itemPosition = _myListView.pointToPosition((int)event.getX(), (int)event.getY());
// We can even get the view at itemPosition thanks to get/setid
View itemView = _myListView.findViewById(itemPosition );
/* If you try the same thing in ACTION_DRAG_LOCATION, itemView
* is sometimes null; if you need this view, just return if null.
* As the same event is then fired later, only process the event
* when itemView is not null.
* It can be more problematic in ACTION_DRAG_DROP but for now
* I never had itemView null in this event. */
// Handle the drop as you like
return true;
}
}
}
Now if you need to have a visual feedback when doing a drag and drop, there are several strategies. You can for instance have 2 instance variables in your activity named:
private boolean ongoingDrag = false; // To know if we are in a drag&drop state
private int dragPosition = 0; // You put the itemPosition variable here
When doing the drag and drop in MyListViewDragListener you modify these variables, and you use their state in MyViewAdapter. Of course do not forget to update the UI (in the event thread of course, use a Handler) with something like _myListView.getAdapter()).notifyDataSetChanged() or maybe _myListView.invalidate() method.
The problem is because listView.getPositionForView(view) returns -1 if the view is not visible when it is called. So relying on that will fail when you scroll the list. So, instead of setting a view.setOnLongClickListener() you can set a listView.setOnItemLongClickListener() on the list item which calls startDrag() on the item. onItemLongClick() gives you the position which you can pass to in the myLocalState parameter of startDrag(). Then you recover that in onDrag() using event.getLocalState() and casting it to an Integer. Like this...
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
position -= listView.getHeaderViewsCount();
DragShadowBuilder dragShadow = new View.DragShadowBuilder(view);
view.startDrag(null, dragShadow, position, 0);
return true;
}
});
Then in your OnDragListener...
#Override
public boolean onDrag(View eventView, DragEvent event) {
Integer dragViewPos = ((Integer) event.getLocalState());
int eventViewPos = listView.getPositionForView(eventView) - listView.getHeaderViewsCount();
...
}
I am working with Spinner, cursors and adapters.
I want to setup a click listener for the spinner so that once a user selects an item from the spinner it gets the current selected item and then carrys out some other tasks ( all this extra code is fine, its just 1 problem I am having).... It kind of works, however, once I declare the setOnItemSelectedListener callback, since the cursor has already been populated, the event is fired as soon as the app launches.
I guess I need a way to define the cursor without selecting an initial item so that the event doesnt fire (since an item will not be selected). Or is there another better way to achieve this?
Basically, as it stands, once the app loads the setOnItemSelectedListener function is firing because the cursor is being populated ( i think). Moreover, ignoreing the fact that the event is firing too soon, if I then select the -same- item in the spinner, it doesnt fire the event sincethe item didnt change. SHould I be using a different callback instead of setonitemslectedlistener? Here is the code I have so far.
c = db.getallrecents();
startManagingCursor(c);
busnumspinner = (Spinner) findViewById(R.id.Spinner01);
SimpleCursorAdapter spinneradapter = new SimpleCursorAdapter(this,
R.layout.lvlayout, c, spincol, spinto);
busnumspinner.setAdapter(spinneradapter);
busnumspinner.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
String spinnerString = null;
Cursor cc = (Cursor)(busnumspinner.getSelectedItem());
if (cc != null) {
spinnerString = cc.getString(
cc.getColumnIndex("busnum"));
text = spinnerString;
}
showDialog(DATE_DIALOG_ID);
}
#Override
public void onNothingSelected(AdapterView<?> parentView) {
// your code here
}
});
This has already been discussed in this question. Look there, though it has a similar answer like the one given by blindstuff.
EDIT:
If the onItemSelectedListener is not firing when you need it, then you probably need a onClickListener in eachtext item of the droplist and get in there the current position of the selected item of the spinner. The problem is that as it is said here spinner don't support this event, but maybe you can get it by doing something similar to the explained in this stackoverflow question. I haven't tried it so I'm not sure it will work.
Use a boolean flag to ignore the first time it gets selected by the system, its not a pretty solution, but i've struggled with this a couple of times, and never found a better solution.
you can add first item of spinner by default value like selectvalues and check its position in onitemselected listener, if it's zero position then dont enter in the loop greater than 0 then enter in the method
see the example
busnumspinner.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int
position, long id) {
if(position!=0)
{
String spinnerString = null;
Cursor cc = (Cursor)(busnumspinner.getSelectedItem());
if (cc != null) {
spinnerString = cc.getString(
cc.getColumnIndex("busnum"));
text = spinnerString;
}
}
So this is not run the default value
Try this:
Extend your SimpleCursorAdapter, override bindView() and set OnClickListener for the row view.
This will overcome both issues: You do not get the initial call, and you get each selection click (inc. re-selection)
Let me know if you need example code.
EDIT: Code example:
protected class NoteAdapter extends SimpleCursorAdapter {
// Constructor
public NoteAdapter(Context context, Cursor c) {
super(context, R.layout.etb_items_strip_list_item, c, fromNote, toNote);
}
// This is where the actual binding of a cursor to view happens
#Override
public void bindView(View row, Context context, Cursor cursor) {
super.bindView(row, context, cursor);
// Save id
Long id = cursor.getLong(cursor.getColumnIndex("_id"));
row.setTag(id);
// Set callback
row.setOnClickListener(row_OnClick);
}
// Callback: Item Click
OnClickListener row_OnClick = new OnClickListener(){
public void onClick(View v) {
Long id = (Long) v.getTag();
}
};
}