I have a custom ListView in which I have set an OnTouchListener for each list item. When the user touches the item, I use TransitionDrawable to change the background color of the item during MotionEvent.ACTION_DOWN and bring it back to normal during MotionEvent.ACTION_UP.
Now when I scroll this list, the item which is touched at the start of the scroll action changes background color. I want to avoid this behavior. So while scrolling I want to disable any change in background color. Is there a way to do this? Please see the code below:
public class ListItemOnTouchListener implements OnTouchListener {
#Override
public boolean onTouch(View v, MotionEvent event) {
Context mContext = getActivity().getApplicationContext();
Resources res = mContext.getResources();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
TransitionDrawable transitionDown = (TransitionDrawable) res
.getDrawable(R.drawable.row_background_transition_down);
v.setBackgroundDrawable(transitionDown);
transitionDown.startTransition(350);
Log.d(TAG, "ACTION_DOWN");
return true;
case MotionEvent.ACTION_UP:
TransitionDrawable transitionUp = (TransitionDrawable) res
.getDrawable(R.drawable.row_background_transition_up);
v.setBackgroundDrawable(transitionUp);
transitionUp.startTransition(1000);
// Get list view
ListView listView = getListView();
int position = listView.getPositionForView((LinearLayout) v.getParent());
listView.performItemClick(v, position, 0);
Log.d(TAG, "ACTION_UP");
return true;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "ACTION_MOVE");
break;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, "ACTION_CANCEL");
v.setBackgroundResource(R.drawable.row_background_normal);
break;
}
return false;
}
}
When the user starts scrolling you should get an ACTION_CANCEL. Catch this and change the color back.
Instead of implementing on touch, u can implement onListItemClick(will work same as on touch) and then on that method u can write the code to change the color of the list item touched/clicked.
Related
I have a problem.
I am trying to create an element in the recycle view, which, when you click and hold an item, expands the element and displays some of the data.
I do this using onLongClickListener, but when the user stops touching the button, the element is further expanded
What do I have to do to collapse an item when the user stops holding the item?
onTouchEvent does what you want:
public boolean onTouchEvent(MotionEvent event) {
int eventAction = event.getAction();
// you may need the x/y location
int x = (int)event.getX();
int y = (int)event.getY();
// put your code in here to handle the event
switch (eventAction) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_MOVE:
break;
}
// tell the View to redraw the Canvas
invalidate();
// tell the View that we handled the event
return true;
}
If you want to read more you can check this and this link.
I have a project which i'm required to develop Android game that display a 5*5 table and and image for each player which each one of them can move the image in place inside the 5*5 table.
ex:
Note : I need to know the exact coordinates (or anything relative) so i can save the position in array and move the image to that new place (eg : re-draw it on the new position).
Any ideas ?
Thanks in advance.
Just use a RelativeLayout with 5x5 ImageViews (set to not visible).
And on the images that the user can move to the place, use Drag and Drop.
In onDrag you set the visibility of the image to Gone.
For all ImageView (5x5 Table), you set the onDragListener.
After that, in the overwritten method OnDrop, you can receive the view that is dropped and can determine which drawable to show.
edit:
Oh well, in this case I would use GridView as said in the comments. And make usage of drag and drop. You don't need to attach a DragListener to every image then. You can simply let the GridView listen to the drop events and determine by the x and y where to drop.
Little example (just as a hint)
gameStoneView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
DragShadowBuilder shadowBuilder = new DragShadowBuilder(gameStoneView);
gameStoneView.startDrag(null, shadowBuilder, gameStoneView, 0);
if (dragListener != null) {
dragListener.onDragStart();
}
break;
default:
LOG.v("Motion event reorderIcon: DEFAULT - not action down");
}
return true;
}
});
gridView.setOnDragListener(new OnDragListener() {
#Override
public boolean onDrag(View v, DragEvent event) {
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_LOCATION:
currentY = event.getY();
currentX = event.getX();
break;
case DragEvent.ACTION_DROP:
final Point position = getPositionOfItem(currentX, currentY);
dropItemAt(position);
break;
case DragEvent.ACTION_DRAG_EXITED:
//BORDER DRAGEVENT: ACTION_DRAG_EXITED
viewDraggedOutSide = true;
break;
case DragEvent.ACTION_DRAG_ENDED:
//BORDER DRAGEVENT: ACTION_DRAG_ENDED
if (viewDraggedOutSideList) {
reinsertDraggedItem();
update();
}
viewDraggedOutSideList = false;
return true;
default:
return true;
}
}
});
In a Custom ListView extending Cursoradapter, I need both Listview and image button to get focussed. How to do it?
Implement your own OnTouchListener for ListView which conditional return values. If you return TRUE from onTouch, the system will assume that the onTouch was handled and it won't handle it by itself. If you return FALSE from onTouch, system will assume that the OnTouchListener did not handle the touch events and will do further processing. This way you can manage how the touch / click should work with ImageButton in a ListView.
I don't know what exactly your implementation is. But it may give you a little idea...
boolean pressedImageButton = false;
myListView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(action)
{
case MotionEvent.ACTION_DOWN:
float positionX = event.getRawX();
float positionY = event.getRawY();
if(some conditions with positionX and positionY)
pressedImageButton = true;
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
if(pressedImageButton)
myImageButton.performClick(); // or whatever action you want to perform on that ImageButton
pressedImageButton = false;
break;
}
}
});
I hope this helps. :)
I created a custom view which overrides onTouchListener in order to have differents images drown depending on the action performed by the user. (To change the background of the view when the user click on it for example).
I want to use this custom view in a ListView, so I created a custom adapter which displays all my views but the onItemClickListener of my ListView is never triggered.
What can I do ?
Here's the code from my Custom View:
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
setMode(MODE_SELECTED);
invalidate();
break;
case MotionEvent.ACTION_UP:
setMode(MODE_NONE);
invalidate();
break;
case MotionEvent.ACTION_CANCEL:
setMode(MODE_NONE);
invalidate();
break;
case MotionEvent.ACTION_OUTSIDE:
setMode(MODE_NONE);
invalidate();
break;
default:
break;
}
return true;
}
Ok, I found a solution : I use StateListDrawable and it avoids me to override the onTouch of my custom view !
How can I listen the move events after the LongPress is caled in my GestureDetector?
When the user LongClick he starts the selection mode, and can drag a square into the screen. But I noticed that the onScroll is not called after LongPress is consumed.
Tried to do fight this for a while, and for now the solution is:
Disable the longpress using setIsLongpressEnabled(isLongpressEnabled) on your gestureDetector
Here is my OnTouch method of my View:
public boolean onTouchEvent(MotionEvent event) {
if (mGestureDetector.onTouchEvent(event)== true)
{
//Fling or other gesture detected (not logpress because it is disabled)
}
else
{
//Manually handle the event.
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
//Remember the time and press position
Log.e("test","Action down");
}
if (event.getAction() == MotionEvent.ACTION_MOVE)
{
//Check if user is actually longpressing, not slow-moving
// if current position differs much then press positon then discard whole thing
// If position change is minimal then after 0.5s that is a longpress. You can now process your other gestures
Log.e("test","Action move");
}
if (event.getAction() == MotionEvent.ACTION_UP)
{
//Get the time and position and check what that was :)
Log.e("test","Action down");
}
}
return true;
}
My device returned ACTION_MOVE whenever I hold finger on the screen. If your doesnt, just check the state of some pressed flag after 0.5s using a timer or thread.
Hope that helps!
I have done this task by using the following concepts:
Suppose I have the Image View and on long press on it, image inside this image View would be drag-able and placed inside the another view(e.g. Relative Layout)
Set MyClickListner on Image View's setOnLongClickListener() method.
private final class MyClickListener implements View.OnLongClickListener {
// called when the item is long-clicked
#Override
public boolean onLongClick(View view) {
// TODO Auto-generated method stub
// create it from the object's tag
ClipData.Item item = new ClipData.Item((CharSequence)view.getTag());
String[] mimeTypes = { ClipDescription.MIMETYPE_TEXT_PLAIN };
ClipData data = new ClipData(view.getTag().toString(), mimeTypes, item);
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
view.startDrag( data, //data to be dragged
shadowBuilder, //drag shadow
view, //local data about the drag and drop operation
0 //no needed flags
);
// view.setVisibility(View.INVISIBLE);
return true;
}
}
Then set MyDragListner on Relative Layout(e.g. bigImageRelativeLayoutVw.setOnDragListener(new MyDragListener());)
class MyDragListener implements View.OnDragListener {
#Override
public boolean onDrag(View v, DragEvent event) {
int X=(int)event.getX();
int Y=(int)event.getY();
int touchX = 0,touchY=0;
// Handles each of the expected events
switch (event.getAction()) {
//signal for the start of a drag and drop operation.
case DragEvent.ACTION_DRAG_STARTED:
// do nothing
break;
//the drag point has entered the bounding box of the View
case DragEvent.ACTION_DRAG_ENTERED:
break;
//the user has moved the drag shadow outside the bounding box of the View
case DragEvent.ACTION_DRAG_EXITED:
// v.setBackground(normalShape); //change the shape of the view back to normal
break;
//drag shadow has been released,the drag point is within the bounding box of the View
case DragEvent.ACTION_DROP:
// if the view is the bottomlinear, we accept the drag item
if(v == bigImageRelativeLayoutVw) {
View view = (View) event.getLocalState();
touchX=X-viewCoords[0]-20;
touchY=Y-viewCoords[1]-20;
View view1=new View(getActivity());
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(30,30);
layoutParams.leftMargin =touchX;
layoutParams.topMargin = touchY;
view1.setBackgroundResource(R.drawable.heavy_damage);
view1.setLayoutParams(layoutParams);
RelativeLayout containView = (RelativeLayout) v;
containView.addView(view1);
view.setVisibility(View.VISIBLE);
} else {
View view = (View) event.getLocalState();
view.setVisibility(View.VISIBLE);
break;
}
break;
//the drag and drop operation has concluded.
case DragEvent.ACTION_DRAG_ENDED:
// v.setBackground(normalShape); //go back to normal shape
default:
break;
}
return true;
}
}