OnTouchEvent for RecylerView AND its items - java

Briefly to say, I have a RecyclerView (a ViewGroup) which should response to TouchEvent, while I also suppose that its item can response individually to TouchEvent.
However, that seems to be impossible for me. For example, if I make both in onTouchEvent() method, then if the item(child view) return a true when ACTION_DOWN, then ViewGroup cannot catch it, whereas if false, the child self cannot response to ACTION_MOVE or ACTION_UP.
I also turned to addOnItemTouchListener() onInterceptTouchEvent(), but none works.

The question is not clear. But based on my understanding, you want to get the click event for entire view and also for each item at the same time.
Get click event for entire view
recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
// this will be called multiple times for single click - for MotionEvent.ACTION_DOWN, MotionEvent.ACTION_UP, and MotionEvent.ACTION_MOVE
// So restricting the call only for ACTION_DOWN,
if(e.getAction() == MotionEvent.ACTION_DOWN) {
Toast.makeText(mContext, "Clicked view", Toast.LENGTH_LONG).show();
}
return false;
}
#Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {}
#Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
});
and to get the click event for each item, add click listener in onBindViewHolder function
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
holder.item.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(mContext, "Clicked Item", Toast.LENGTH_LONG).show();
}
});
}

Instead of touch listener you can also use click listener on any element of recycler view row...

Related

Drag a view onLongClick and start activity onClick

I'm banging my head with this problem which probably is simple but since I'm new to this topic I somehow haven't been able to figure it out yet.
I've successfully implemented dragging a view with onTouch method. I've also successfully implemented onLongClick and onClick methods. But both of these functionalities were implemented separately.
The problem, like the title says is when I want to join these functionalities. I want the onTouch method to be called when a user long clicks a view and I want a new activity to start when a user clicks a view.
Here is the pseudo code:
public class Website extends AppCompatActivity implements View.OnTouchListener{
TextView longpress;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_website);
longpress = (TextView) findViewById(R.id.longpress);
longpress.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view){
//I don't really know how to do this part
onTouch(View view, Motion Event event);
return true;
}
});
longpress.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
//Code for new activity comes here (I know how to do this part)
}
});
}
public boolean onTouch(View view, MotionEvent event) {
switch(event.getAction(){
case MotionEvent.ACTION_DOWN:
//Save initial coordinates of view <-- view.getX(), view.getY()
break;
case MotionEvent.ACTION_MOVE:
//Calculate dX and dY and setX and Y of the view (move view)
break;
case MotionEvent.ACTION_UP:
//If view is certain distance away from initial points do something
break;
}
}
}
Like I said, onTouch works on itself if I don't try to call it from onLongClick method. If I try to call onTouch(View view, MotionEvent event) from onLongClick method the problem occurs because onLongClick only receives one out of two arguments onTouch method should receive (onLongClick only receives view argument but it should also receive event argument).
Maybe I'm trying to do this in a totally wrong way but I have been looking at some documentation e.g. https://developer.android.com/training/gestures/ but still won't get an idea what to do.
(I would like to have a similar functionality to notifications on android phones)
So I've come to a solution which might or might not be a good one but for now it serves my functionality. If someone has a better solution and thinks mine is bad in some way please say so.
Here is the code:
boolean flag;
public boolean onTouch(View view, MotionEvent event){
int action = event.getAction() & MotionEvent.ACTION_MASK;
if(action == MotionEvent.ACTION_DOWN){
//do something on a down press
flag = true;
return true;
}
if(action == MotionEvent.ACTION_UP && flag == true){
//do something if we move finger away from screen we
//didn't move the view first
return true;
}
if(action == MotionEvent.ACTION_UP && flag == false){
//do something if we move finger away from screen and we moved
//the view before we moved the finger away from screen
}
if(action == MotionEvent.ACTION_MOVE){
//do something when moving the view
flag = false;
}

On hold event trigger the on click event

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);
});

How to detect if the Spinner is click open on Android

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.

AlertDialog appearing twice

When showTimeDialog() is called, dialog appears twice. When I click 'ok', there is another dialog waiting.
public void showTimeDialog(){
final TimePicker timePicker = new TimePicker(this);
timePicker.setIs24HourView(true);
timePicker.setCurrentHour(20);
timePicker.setCurrentMinute(15);
timeDialog=new AlertDialog.Builder(this)
.setTitle("Test")
.setPositiveButton(android.R.string.ok, new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Log.d("Picker", timePicker.getCurrentHour() + ":"
+ timePicker.getCurrentMinute());
dialog.dismiss();
}
})
.setNegativeButton(android.R.string.cancel,
new OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
Log.d("Picker", "Cancelled!");
dialog.dismiss();
}
}).setView(timePicker).show();
}
In onCreate(), I have:
editText_time.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View arg0, MotionEvent arg1) {
showTimeDialog();
return false;
}
});
This looks like in the code you are calling showTimeDialog() method you expect it to not return unless dialog is dismissed. If it is so (your question is not complete so I am partially guessing), then this is wrong as dialogs are asynchronous.
EDIT
It works fine as your dialog IS fired twice. It's because you are doing this in onTouch() then first dialog is started then you touch the screen (as this triggers touch event ACTION_DOWN) and then you release the finger which triggers ACTION_UP. To avoid this, you may want to add condition to your code, and I'd suggest reacting on ACTION_UP, like this:
public boolean onTouch(View v, MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
showTimeDialog();
}
}
Are you certain it's being called only once? Have you done any log output? My guess is that because you are calling the method in onTouch, the method is being called more times than you think.
onTouch(View, MotionEvent) is not only called when the view is touched. There are a number of times it is called with a single press, and you can check the MotionEvent docs to see all of the possible actions which invoke this method.
Probably what is happening is the showTimeDialog() method is being opened when ACTION_DOWN event occurs, then again when a ACTION_UP or ACTION_CANCEL event occurs because your dialog is now blocking the view. Try changing your onTouch method as follows:
public boolean onTouch(View arg0, MotionEvent arg1) {
if (arg1.getActionMasked() == MotionEvent.ACTION_UP)
showTimeDialog();
return false;
}

Adding a Button on a View

I am going nuts over this.
I did not find any working solution (tried a few from stackoverflow)
Scenario (this is an actual screenshot what is already done):
I have a Activity that has a View as his Attribute.
This view adds another view via View.addView(myView).
I now want to add a Button to myView (to be specific: after MotionEvent.ACTION_UP the button should appear in the right lower corner (this will start the robot to drive the track))
Here is a shortcut of my code:
public class ModeRouting extends View {
public ModeRouting(Context context) {
super(context);
Button asuroStartButton = new Button(context) //does not work
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int actionevent = event.getAction();
if (actionevent == MotionEvent.ACTION_UP
|| actionevent == MotionEvent.ACTION_CANCEL) {
asuroStartButton.visible=true;
view.add(asuroStartButton);
}
return true;
}
}
and my Activity:
//in constructor
contentView = (FrameLayout) findViewById(R.id.content);
onClickListenerFacade(routingMode, route);
//this removes all views from stack and places the new one on the view
private void onClickListenerFacade(View v, final View target) {
v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
contentView.removeAllViews();
contentView.setBackgroundColor(0xff000000);
contentView.addView(target);
modeSelectorAnimation();
}
});
}
I tried to create a button in my mainactivity.xml and instantiate in my mainactivity.
I am missing some point in here but i am not sure which.
Since my view is purely dynamic (no layout.xml) i dont think i should use a layout.xml (maybe thats my mind-blockage) but instead set the button attributes dynamically too.
Any hint is appreciated!
You want to extend ViewGroup rather than just a View (LinearLayout, RelativeLayout, FrameLayout, etc) - they handle child views for you.
I think maybe you need to refresh the whole view/activity. Try to do this in the onResume methode, maybe this helps. But as you don't use a layout.xml, I'm not sure if this helps you much..
#Override
protected void onResume(){
super.onResume();
setContentView(R.layout.activity_main);
}

Categories