Drag and drop imagebuttons having issues with onDrag - java

I am developing an android app where the user can purchase buildings that are imagebuttons that implement the drag and drop api. My issue is that when the user buys two buildings, say colonyHutOne and colonyHutTwo, there is an issue with the x and y coordinates being saved in the onDrag. In my onDrag I pass in which building number in the onDragListener so i know what building i am dealing with in the onDrag class. This way i can save the coordinates to the appropriate building. The problem is that no matter what building number i pass into the onDrag, the most recently created building is the one that takes the coordinates. In the onDrag, it receives building number two every time even when its the first building that is being dragged (which is building number one). I have no idea if this has something to do with context that is passed to the onDrag or if it is because the onDragListeners are declared before the drag is made so it just takes the last created imagebutton. I have no idea how to get past this issue. Please help.
Here is the code for setting the on Drag listener of both buildings:
findViewById(R.id.topHalf).setOnDragListener(new ColonyHutDrag(getApplicationContext(), 1));
findViewById(R.id.bottomHalf).setOnDragListener(new ColonyHutDrag(getApplicationContext(), 1));
FrameLayout.LayoutParams param1 = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
newColonyHutFrame.addView(newColonyHutOne, param1);
findViewById(R.id.topHalf).setOnDragListener(new ColonyHutDrag(getApplicationContext(), 2));
findViewById(R.id.bottomHalf).setOnDragListener(new ColonyHutDrag(getApplicationContext(), 2));
FrameLayout.LayoutParams param1 = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
newColonyHutFrame.addView(newColonyHutTwo, param1);
Here is the onDrag class:
public class ColonyHutDrag implements OnDragListener
{
SharedPreferences prefs;
Context passedContext;
Database data;
int buildingNum = 0;
public ColonyHutDrag(Context applicationContext, int num)
{
passedContext = applicationContext;
buildingNum = num;
}//end constructor
#Override
public boolean onDrag(View v, DragEvent event)
{
float x = 0, y = 0;
switch(event.getAction())
{
case DragEvent.ACTION_DRAG_STARTED:
//drag has started
break;
case DragEvent.ACTION_DRAG_ENTERED:
//being dragged
break;
case DragEvent.ACTION_DRAG_EXITED:
//stop drag
break;
case DragEvent.ACTION_DRAG_LOCATION:
//find drag location
break;
case DragEvent.ACTION_DROP:
if (v == v.findViewById(R.id.bottomHalf))
{
//find position where dropped
x = event.getX();
y = event.getY();
//save the coordinates that the building was dropped at
data = new Database(passedContext);
data.open();
if (buildingNum == 1)
{
data.colonyHutOneXEntry(x);
data.colonyHutOneYEntry(y);
Toast.makeText(passedContext, "Going in1 -> x: " + x + " y: " + y, Toast.LENGTH_SHORT).show();
}//end if
else if (buildingNum == 2)
{
data.colonyHutTwoXEntry(x);
data.colonyHutTwoYEntry(y);
Toast.makeText(passedContext, "Going in2 -> x: " + x + " y: " + y, Toast.LENGTH_SHORT).show();
}//end else if
data.close();
//use this to fix building loadup glitch
View view = (View) event.getLocalState();
ViewGroup group = (ViewGroup) view.getParent();
group.removeView(view);
FrameLayout contain = (FrameLayout) v;
contain.addView(view);
view.setX(x - (view.getWidth()/2));
view.setY(y - (view.getHeight()/2));
view.setVisibility(View.VISIBLE);
}//end if
else
{
View view = (View) event.getLocalState();
view.setVisibility(View.VISIBLE);
}//end else
break;
default:
break;
}//end switch
return true;
}//end onDrag function
}//end ColonyHutOneDrag class
Here is the onTouchlistener for the drag and drop:
public class BuildingsClick implements OnTouchListener
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
ClipData.Item item = new ClipData.Item((CharSequence)v.getTag());
String[] mimeTypes = { ClipDescription.MIMETYPE_TEXT_PLAIN };
ClipData data = new ClipData(v.getTag().toString(), mimeTypes, item);
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(v);
v.startDrag(data, shadowBuilder, v, 0);
v.setVisibility(View.INVISIBLE);
return false;
}//end onTouch function
}//end BuildingsClick class
I really appreciate any help. I have no idea how to fix the problem. It is almost like since the second building is being dealt with, then the first one can no longer be referenced.
Thanks guys.
Edit:
Code in BuildingsClick class
//find which building is being dragged
if (v.getTag() == "NewColonyHutOne")
{
ColonyHutDrag.setType(ColonyHutOneDrag.getType());
}//end if
else if (v.getTag() == "NewColonyHutTwo")
{
ColonyHutDrag.setType(ColonyHutTwoDrag.getType());
}//end if
Code for ColonyHutOneDrag class:
public class ColonyHutOneDrag extends ColonyHut
{
#Override
public int getType()
{
return 1;
}//end getType
}//end ColonyHutOneDrag
The code for the ColonyHutTwoDrag class is the same as the first one but returns 2.
This is the getType in ColonyHutDrag:
public void setType(int type)
{
buildingNum = type;
}//end setType

You are incorrectly as assigning the OnDragListeners again.
You can't
findViewById(R.id.topHalf).setOnDragListener(new ColonyHutDrag(getApplicationContext(), 1));
findViewById(R.id.bottomHalf).setOnDragListener(new ColonyHutDrag(getApplicationContext(), 1));
FrameLayout.LayoutParams param1 = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
and then
findViewById(R.id.topHalf).setOnDragListener(new ColonyHutDrag(getApplicationContext(), 2));
findViewById(R.id.bottomHalf).setOnDragListener(new ColonyHutDrag(getApplicationContext(), 2));
FrameLayout.LayoutParams param1 = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
The reason is because your second call overwrites your first, and you never listen for hut type of 1 to be dragged, because you passed which hut you are listening for in your constructor.
The solution to this is to change your assignment of the listener, like so:
findViewById(R.id.topHalf).setOnDragListener(new ColonyHutDrag(getApplicationContext()));
findViewById(R.id.bottomHalf).setOnDragListener(new ColonyHutDrag(getApplicationContext());
FrameLayout.LayoutParams param1 = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
We're going to make an abstract class ColonyHut, and define public int getType();.
Get rid of your constructor for ColonyHutListener as well, we won't need that. Then you're going to make a class called ColonyHutOne, if you don't already have one. With that class, you're going to want to extend ColonyHut, and define getType() like so:
public int getType()
{
return 1;
}
Then we'll define a function in your ColonyHutDrag class, called setType() like so:
public void setType(int type)
{
buildingNum = type;
}
After that you're going to want to get the ColonyHutOne as a ColonyHut, like so ColonyHut currentlySelectedHut = view.getHutFromView() in your onTouchListener, and call colonyHutDrag.setType(currentlySelectedHut.getType()) before v.startDrag() and it should work. Do the same for ColonyHutTwo, except obviously then you should make getType() return 2.
I'll leave defining view.getHutFromView(), and making colonyHutDrag visible in your BuildingsClick class. After all EVERYTHING can't be a free-be :-).

Related

AndroidStudio MotionEvent: detect only ACTION_UP on a second view, starting ACTION_DOWN on first view

Solved it by using emandt's suggestion. My personal Solution added below.
I'm using Android Studio for this.
I searched for solutions but couldn't find anything resembling this.
I want to know on which ImageView an UP action occurs while starting the DOWN action on a different ImageView (to eventually be able to drag one image over the other and make it snap to the same position by getting the position of the image I dragged over).
My example has two ImageViews with the id imageView (left) and imageView2(right).
In my example I'm not dragging anything yet, I just want to touch the left image, see "Action was down" in the log and lift the finger over the right image showing "Action was up2".
I don't know if this is easily possible.
As far as I can tell from testing, the MotionEvent.ACTION_UP only fires for an ImageView when you also pressed down on it beforehand. So when I release on top of imageView2 it only shows "Action was up" from the left image.
I wondered if it was possible by playing with return false, since the return value tells if an ActionEvent is consumed so I thought if the UP event of imageView returns false, maybe it does trigger the UP event of imageView2 but no. (Either complete misunderstanding on my part or it doesn't recognise UP on the second because it didn't start with a DOWN and MotionEvents probably always have to start with a DOWN).
public class MainActivity extends Activity {
ImageView imageView;
ImageView imageView2;
String DEBUG_TAG = "action";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = findViewById(R.id.imageView);
imageView2 = findViewById(R.id.imageView2);
imageView.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
//int action = MotionEventCompat.getActionMasked(event);
int action = event.getActionMasked();
switch(action) {
case (MotionEvent.ACTION_DOWN) :
Log.d(DEBUG_TAG,"Action was DOWN"+v.toString());
return true;
case (MotionEvent.ACTION_MOVE) :
//Log.d(DEBUG_TAG,"Action was MOVE");
return true;
case (MotionEvent.ACTION_UP) :
Log.d(DEBUG_TAG,"Action was UP"+v.toString());
return false;
default :
//return true;
}
return true;
}
});
imageView2.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
//int action = MotionEventCompat.getActionMasked(event);
int action = event.getActionMasked();
switch(action) {
case (MotionEvent.ACTION_DOWN) :
Log.d(DEBUG_TAG,"Action was DOWN2"+v.toString());
return true;
case (MotionEvent.ACTION_MOVE) :
//Log.d(DEBUG_TAG,"Action was MOVE");
return true;
case (MotionEvent.ACTION_UP) :
Log.d(DEBUG_TAG,"Action was UP2"+v.toString());
return true;
default :
//return true;
}
return true;
}
});
}
}
If there is no simple way to do this, I'm thinking about solving this mathematically, but maybe some of you can help.
So my question is, is there a way to recognise an UP action on a second ImageView while currently being in a MotionEvent of another ImageView?
SOLUTION (see emandt's answer)
I ditched the second OnClickListener because I realised that the 2nd image doesn't need any, I just need its position.
Added this method:
#Nullable
private View getDroppedView(View droppedView, int x, int y, List<View> arrayOfPossibilities) {
Rect cVisibleBoundsRect = new Rect();
for (View cView : arrayOfPossibilities) {
//if currently iterated view doesn't have values for getGlobalVisibleRect, skip the .contains part
//ignore the item which is your current active item (which would potentially be dropped)
//getGlobalVisibleRect sets cVisibleBoundsRect immediately to the Rect given as parameter
if (!cView.getGlobalVisibleRect(cVisibleBoundsRect)||(cView.equals(droppedView))) continue;
if (cVisibleBoundsRect.contains(x, y)) {
Log.d(DEBUG_TAG,"Found something");
//THIS "cView" IS THE VIEW WHERE YOU RELEASED THE FINGER
return cView;
}
}
Log.d(DEBUG_TAG,"Found nothing");
return null;
}
And added this in onUP:
case (MotionEvent.ACTION_UP) :
View dropTarget;
Log.d(DEBUG_TAG,"Action was UP"+v.toString());
dropTarget = getDroppedView(v, (int)event.getRawX(), (int)event.getRawY(), listOfViews);
if (dropTarget != null){
v.setX(dropTarget.getX());
v.setY(dropTarget.getY());
}
I think you want to know which is the View where you release the finger from the screen, am I right?
To do this you can use the same "View.OnTouchListener()" for all of your Views and in the ACTION_UP you have to call a new method similar to this (pseudo-code):
....
case (MotionEvent.ACTION_UP) :
View[] cArrayOfPossibileViews = new View[]{ findViewById(IMAGE_1), findViewById(IMAGE2) }
getDroppedView(v, event.getRawX(), event.getRawY(), cArrayOfPossibileViews);
break;
}
....
#Nullable
private View getDroppedView(View view, int x, int y, View[] arrayOfPossibilities) {
Rect cVisibleBoundsRect = new Rect();
for (View cView : arrayOfPossibilities) {
if (!cView.getGlobalVisibleRect(cVisibleBoundsRect)) continue;
if (cVisibleBoundsRect.contains(x, y)) {
//THIS "cView" IS THE VIEW WHERE YOU RELEASED THE FINGER
return cView;
}
}
return null;
}
This method get View bounds and compare them avains X and Y of your Touch Event. If X and Y are contained inside a View bounds it means that View is the one you need.

Avoid overlap between touch and click android in OnTouch(), in IOnTouchListener?

I am creating this app.
code of my onsingletapup.cs file
class SingleTapUp : Android.Views.GestureDetector.SimpleOnGestureListener
{
public override bool OnSingleTapUp(MotionEvent e) {
// Toast.MakeText(this,, ToastLength.Long).Show();
return true;
}
}
here is my mainactivity.cs
public class MainActivity : ActionBarActivity, View.IOnTouchListener
{
GestureDetector gestureDetector;
float _viewX;
float _viewY;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
PopulateListView(someList,anynumbertoshow)
}
private void QueueListView(Queue<FeedItem> feedItemsList, int count)
{
RelativeLayout rl = this.FindViewById<RelativeLayout>(Resource.Id.newsContainer);
if(rl.Visibility == ViewStates.Gone)
{
this.FindViewById<LinearLayout>(Resource.Id.newsList).Visibility = ViewStates.Gone;
rl.Visibility = ViewStates.Visible;
}
Paint layerPaint = new Paint();
layerPaint.AntiAlias = true;
layerPaint.FilterBitmap = true;
layerPaint.Dither = true;
// RelativeLayout parentLayout = (RelativeLayout)LayoutInflater.from(context).inflate(R.layout.myLayout, null);
rl.SetLayerType(LayerType.Hardware, layerPaint);
rl.SetClipChildren(false);
Random rnd = new Random();
//this.progressDialog.Dismiss();
for (int i = 0; i < count; i++)
{
FeedItem rss = theNewsQueue.Dequeue();
var viewObj = this.LayoutInflater.Inflate(Resource.Layout.NewTile, rl, false);
TextView tv = viewObj.FindViewById<TextView>(Resource.Id.textView2);
TextView link = viewObj.FindViewById<TextView>(Resource.Id.link);
link.Text = rss.Link;
tv.Text = rss.Title;
viewObj.Rotation = angle;
angle = rnd.Next(-3, 3);
viewObj.SetLayerType(LayerType.Hardware, layerPaint);
rl.AddView(viewObj);
gestureDetector = new GestureDetector(this, new SingleTapUp());
viewObj.SetOnTouchListener(this); //Here I am adding my listener to all my control
rl.SetLayerType(LayerType.Hardware, layerPaint);
theNewsQueue.Enqueue(rss);
rss = null;
}
}
public bool OnTouch(View v, MotionEvent e)
{
if (gestureDetector.OnTouchEvent(e))
{
//will detect a click and open in browser
return true;
}
else
{
int initialTouchX = 0, initialTouchY = 0;
int newx = 0;
var x = v.Left;
switch (e.Action)
{
case MotionEventActions.Down:
{
_viewX = e.GetX();
_viewY = e.GetY();
initialTouchX = (int)e.RawX;
initialTouchY = (int)e.RawY;
break;
}
case MotionEventActions.Up:
{
int lastX = (int)e.GetX();
int lastY = (int)e.GetY();
if ((x - newx) > 40)
{
//right Swipe
sendViewToBack(v);
}
else if ((newx - x > 40))
{
//left Swipe
sendViewToBack(v);
}
break;
}
case MotionEventActions.Move:
{
// click = false;
var left = (int)(e.RawX - _viewX);
newx = left;
var right = (int)(left + v.Width);
var top = (int)(e.RawY - _viewY);
var bottom = (int)(top + v.Height);
v.Layout(left, top, right, bottom);
break;
}
}
}
// _gestureDetector.OnTouchEvent(e);
return true;
}
public void sendViewToBack(View child)
{
var parent = (ViewGroup)child.Parent;
if (null != parent)
{
parent.RemoveView(child);
if(viewType==0)
parent.AddView(QueueListView (theNewsQueue), 0);
else
parent.AddView(QueueListView (theNewsQueue), parent.ChildCount-1);
}
}
}
Now my question is on some devices my current code is giving some abnormal behavior. Like even if I perform OnSingleTapUp() which is supposed to perform click operation but it is performing a move operation. My question is what is wrong with my code so that it is not working correctly. Any help will be greatly appreciated. Thank you.
The onTouch and onClick doesn't work together. In all the cases the onTouch is going to get the priority, in fact onClick in also sort of fine implementation of onTouch. If you want to have onClick sort of functionality, let go the original onClick and try to handle that in onTouch. You can take help of the GestureDetector.SimpleOnGestureListener in Xamarin. For an example to override the double tap you can do it like this
class MyDoubleTapListener : GestureDetector.SimpleOnGestureListener
{
public override bool OnDoubleTap(MotionEvent e)
{
//Your code here
return false;
}
}
and then in your activity
public class Test : Activity, View.IOnTouchListener
{
private GestureDetector _gestureDetector = null;
protected override void OnCreate (Bundle bundle)
{
_gestureDetector = new GestureDetector(new MyDoubleTapListener (this));
_editText.SetOnTouchListener(this);
}
public bool OnTouch(View v, MotionEvent e)
{
return _gestureDetector.OnTouchEvent(e);
}
}
GestureDetector also provides you other methods that you can overide to suit your need. Follow this, https://developer.xamarin.com/api/type/Android.Views.GestureDetector/
I couldn't get exactly what your are trying to do inside onTouch interface. Anyway there's some points you must know:
1) When you handle a touch event, onTouch method returns a boolean that indicates if event was consumed (true) or not (false). If you consume touch event related to click, click listener won't be triggered. So, make sure you are only consuming what is desired.
2) When you set listeners as onClick or onTouch to some view, it becomes clickable and touchable, respectively, if it wasn't. If you are setting this attributes to false in some part of your code make sure it's enabled again when you want to handle such events.

Android : Update Image in GridView on touch event in Adapter

I have a GridView and attached adapter to it. Adapter populates images in the grid. I have set setOnTouchLister to GridView in my Activity and implemented in the adapter only. In adapter I have an Integer[] imageIDs that contains resource ids of all images that are added & an ArrayList<ImageSourceObject> imgObjsArr that extends ImageView & has other properties set.
Now onTouch(), I want to change the image of the selected image to other one. Here's my code :
SEtting adapter of grid in Activity in onCreate :
// Set Objects in Game View
gameView = (GridView) this.findViewById(R.id.game_gridView);
gameObjAdapter = new GameObjectsAdapter(this, R.id.game_gridView, null);
gameView.setAdapter(gameObjAdapter);
ADAPTER :
public class GameObjectsAdapter extends BaseAdapter implements OnTouchListener {
super();
mContext = c;
this.layoutResourceId = layoutResourceId;
objects = data;
gridViewResAdap = (GridView) mContext.findViewById(this.layoutResourceId);
createObjectsArray();
Log.d("GOA", "Created Objects Array");
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageSourceObject imgView;
if (convertView == null) {
imgView = new ImageSourceObject(mContext);
imgView.setLayoutParams(new GridView.LayoutParams(20, 20));
imgView.getScaleType();
imgView.setScaleType(ScaleType.FIT_XY);
imgView.setPadding(0, 0, 0, 0);
} else {
imgView = (ImageSourceObject) convertView;
}
// Chk status of touched of imgView & set image accordingly
if (imgView.isTouched())
imgView.setImage(R.drawable.droid_touched2);
else
imgView.setImage(imageIds[position]);
return imgView;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
int action = event.getActionMasked();
float currentXPos = event.getX();
float currentYPos = event.getY();
int position = gridViewResAdap.pointToPosition((int)currentXPos, (int) currentYPos);
// Key was Pressed Here
if (action == MotionEvent.ACTION_UP) {
if (position > 0) {
// Get the object which is clicked
ImageSourceObject isb = this.imgObjsArr.get(position);
Log.d("GA", " Postion ID " + isb.getId() + " [] ID : " + imageIds[position]);
// Change the status of touched & set image
isb.setTouched(true);
isb.setImage(R.drawable.droid_touched2);
// Update the ArrayList & Integer[] with this updated obj
this.imgObjsArr.set(position, isb);
imageIds[position] = R.drawable.droid_touched2;
Log.d("ISB", "++++ Object ID : " + isb.getId() + " [] ID : " + imageIds[position] + " ISB Touched :" + isb.isTouched());
Toast.makeText(mContext, "Postion Pressed : " + (position+1),
Toast.LENGTH_SHORT).show();
//this.gridViewResAdap.invalidate();
}
return true;
}
return false;
}
Logs :
02-19 15:19:11.615: D/GA(2046): Postion ID 2130837556 [] ID : 2130837556
02-19 15:19:11.617: D/ISB(2046): ++++ Object ID : 2130837559 [] ID : 2130837559 ISB Touched :true
The logs say that the object in Integer[] & ArrayList both are updated & have right values. After all this also the image is not updated on the screen. The gridViewResAdap is also the object of grid that is passed from the activity. I tried calling invalidate() on it also, but yet no results. As in my getView(), I am using imageIDs, so I have kept that also updated.
ImageSourceObject :
public class ImageSourceObject extends ImageView {
public void setImage(int resourceId) {
super.setImageResource(resourceId);
this.setId(resourceId);
}
Also, onTouch() gives error to call onPerformClick(), I am not sure where to call & why to call. I have alos not implemented onClickListener in the adapter. What can be done in this case & what to write in onClickListener when things are manged in onTouch().
Can you help me know why the image object is not updating and where am I going wrong ? I thought I have to refresh the grid, so have also called invalidate(), but no results.
Any help is highly appreciated.
Thanks
After your ImageView begins handling the TouchEvent, it is the only view allowed to do anything with that touch gesture. You want your GridView to intercept the TouchEvent, check the X and Y coordinates of the TouchEvent (event.getX(); event.getY()) and see if those coordinates fall within the bounds of one of your ImageView objects. If yes, set a flag on the ImageView or something that can trigger your setImageDrawable() method. I was able to achieve a similar effect in one of my projects but I had to create a custom GridView class (public class yourGridView extends GridView), then override the following:
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
int action = event.getAction();
switch(action) {
case MotionEvent.ACTION_DOWN:
Log.i(AGL, "InterceptAction = DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.i(AGL, "InterceptAction = MOVE");
break;
case MotionEvent.ACTION_CANCEL:
Log.i(AGL, "InterceptAction = CANCEL");
return false;
}
return true; //returning true tells your main Activity that you want the custom GridView to handle this TouchEvent; It will then send the TouchEvent to your GridView's onTouchEvent() method for handling.
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch(action) {
case MotionEvent.ACTION_MOVE:
int xCoord = (int) event.getX();
int yCoord = (int) event.getY();
Log.i(AGL, "MOVE EVENT;" + "\n" + "Touch X = " + Integer.toString(xCoord) + "\n" +
"Touch Y = " + Integer.toString(yCoord));
for(int i = 0; i < this.getChildCount(); i++) {
ImageView suspect = (ImageView) this.getChildAt(i);
if(suspect.getBounds().contains(xCoord, yCoord)) {
suspect.CHANGE_YOUR_IMAGE_HERE();
suspect.invalidate();
}
}
break;
}
return true;
}
PLEASE NOTE: getBounds() is a method I wrote in my custom ImageView class. This method returns a Rect object that represents the bounding box of the ImageView object. You will have to use your own logic for fetching the bounds of your ImageView.
ALSO NOTE: When I run this logic in my project, my ImageViews change images rapidly during the touch gesture. I haven't figured out yet how to limit it to one image change per MotionEvent.ACTION_MOVE.
I hope this helps.
You can simply do:
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
int action = event.getActionMasked();
float currentXPos = event.getX();
float currentYPos = event.getY();
int position = gridViewResAdap.pointToPosition((int)currentXPos, (int) currentYPos);
// Key was Pressed Here
if (action == MotionEvent.ACTION_UP) {
if (position > 0) {
((ImageView)v).setImageDrawable(ctx.getResources().getDrawable(R.drawable.droid_touched2));
}
return true;
}
return false;
}

ImageView.setImageResource is not displaying correct drawable

I have this app, it's basically a 'make fun' app I made with a person's face and the ability to either shoot it with a pistol, automatic rifle, or grenade (more weapons to come :-)).
I have a Weapon class, with the following code. (I'm pretty new to java so forgive me if I failed to follow proven ways, or do things as efficiently as I should)
public class Weapon {
// Parent
public static MainActivity ma;
// Constants
public static final int BULLET_WIDTH = 97;
public static final int BULLET_HEIGHT = 92;
public static final int EXPLOD_WIDTH = 299;
public static final int EXPLOD_HEIGHT = 237;
public static final int PISTOL = 0;
public static final int RIFLE = 1;
public static final int GRENADE = 2;
protected static int[] position = {0, 0};
protected static RelativeLayout rl = null;
protected static MediaPlayer mp;
// Protected stuff
// Object variables.
protected int type;
protected int drawableEffect;
protected int soundEffect;
// Functionals
protected ImageView effectImage;
public void equipWeapon() {
// Clear any existing listeners and assign a new one.
MainActivity.mainImage.setOnTouchListener(null);
MainActivity.mainImage.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// Which weapon are we using?
switch (type) {
case Weapon.PISTOL:
case Weapon.GRENADE:
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// Fire the weapon.
fireWeapon(v, event);
}
case Weapon.RIFLE:
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE: // This doesn't work ???
// Fire the weapon.
fireWeapon(v, event);
}
}
// perfomClick needed.
return v.performClick();
}
});
}
public void fireWeapon(View v, MotionEvent event) {
// Reference the layout.
Weapon.rl = (RelativeLayout)Weapon.ma.findViewById(R.id.relativeLayout);
// Define properties.
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
// Get the touch position.
Weapon.position[0] = (int)event.getX() - ((type == Weapon.PISTOL || type == Weapon.RIFLE) ? Weapon.BULLET_WIDTH:Weapon.EXPLOD_WIDTH);
Weapon.position[1] = (int)event.getY() - ((type == Weapon.PISTOL || type == Weapon.RIFLE) ? Weapon.BULLET_HEIGHT:Weapon.EXPLOD_HEIGHT);
// Set the position.
lp.setMargins(Weapon.position[0], Weapon.position[1], 0, 0);
effectImage.setLayoutParams(lp);
// Add the view to the layout.
Weapon.rl.addView(effectImage, lp);
// Play the sound.
Weapon.mp.seekTo(0);
Weapon.mp.start();
// Reload
reload();
}
public void reload() {
// Create the ImageView
this.effectImage = new ImageView(Weapon.ma);
this.effectImage.setImageResource(this.drawableEffect);
}
}
And I have a Pistol class which extends Weapon
public class Pistol extends Weapon {
public Pistol() {
// First save the type.
this.type = Weapon.PISTOL;
// Fetch the sound effect and image.
this.soundEffect = R.raw.gunshot;
this.drawableEffect = R.drawable.bullet_hole1;
// Create the media player and initialize the sound.
Weapon.mp = MediaPlayer.create(Weapon.ma, this.soundEffect);
// Create the ImageView
this.effectImage = null;
this.effectImage = new ImageView(Weapon.ma);
this.effectImage.setImageResource(this.drawableEffect);
}
}
As well as a Rifle class extending Weapon
public class Rifle extends Weapon {
public Rifle() {
// First save the type.
this.type = Weapon.RIFLE;
// Fetch the sound effect and image.
this.soundEffect = R.raw.gunshot;
this.drawableEffect = R.drawable.bullet_hole1;
// Create the media player and initialize the sound.
Weapon.mp = MediaPlayer.create(Weapon.ma, this.soundEffect);
// Create the ImageView
this.effectImage = null;
this.effectImage = new ImageView(Weapon.ma);
this.effectImage.setImageResource(this.drawableEffect);
}
}
finally, I have a Grenade class extending, yep you guessed it, Weapon as well.
public class Grenade extends Weapon {
public Grenade() {
// First save the type.
this.type = Weapon.GRENADE;
// Fetch the sound effect and image.
this.soundEffect = R.raw.grenade;
this.drawableEffect = R.drawable.boom;
// Create the media player and initialize the sound.
Weapon.mp = MediaPlayer.create(Weapon.ma, this.soundEffect);
// Create the ImageView
this.effectImage = new ImageView(Weapon.ma);
this.effectImage.setImageResource(this.drawableEffect);
}
}
I have buttons in the main view which I have registered onClick listeners to so you can switch weapons to your liking.. Here is one for example:
grenadeButton = (ImageButton)findViewById(R.id.grenadeButton);
grenadeButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (MainActivity.this.weapon != Weapon.GRENADE) {
// Change the background color.
resetButtons();
v.setBackgroundResource(R.drawable.background_selected);
// Change weapons.
MainActivity.this.currentWeapon = equipWeapon(Weapon.GRENADE);
}
}
});
and the equip weapon method in MainActivity.
public Weapon equipWeapon(int type) {
Weapon weapon = null;
switch (type) {
case Weapon.PISTOL:
weapon = new Pistol();
break;
case Weapon.RIFLE:
weapon = new Rifle();
break;
case Weapon.GRENADE:
weapon = new Grenade();
break;
}
// Play a sound and save changes.
MainActivity.this.weapon = type;
MainActivity.mp.seekTo(0);
MainActivity.mp.start();
return weapon;
}
Now, I appreciate you taking the time to review all this code. I know that's a lot to digest for what I'm assuming is a simple issue. I'm also aware of the rules of this forum and I have attempted to search for this issue already, but I'm not sure if I was using the right queries, as I did not find anything related to this issue.
Here we go:
When you start the app, the pistol is automatically equipped so you can start shooting immediately. It shoots fine, I get a bullet noise, and bullet holes all over the picture of the person's face ^_^. The rifle works fine as well (but it uses the same noise and graphic as the pistol, so it could very well be failing as well. Refer below).
When I switch to the grenade, I here a lovely explosion sound, but the image displayed is still a bullet hole and not an explosion.. I have no earthly idea how to fix this and I am stumped..
When I create the grenade object I specifically assign the drawable resource to the instance variable...
this.drawableEffect = R.drawable.boom;
Yet it still displays R.drawable.bullet_hole1....
Please let me know if you need more information and ask any questions you need to..
Thank you for your time..
I'm so stupid.....
MainActivity.equipWeapon
wasn't calling
Weapon.equipWeapon....
So the weapon wasn't changing... Oy' vey...

performClick not triggering

I am trying to trigger a click on the Carousel. I want that if I press the forward button, it automatically triggers the click on the carousel and then move forward. The manual click (physical touch) is working but performClick() is not. The code is as follows
//************* Forward Button: Select Objects *************
Button forwardButton = (Button)this.findViewById(R.id.ForwardButton);
forwardButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(NewFieldTrip.this, SelectObjects.class);
//ImagePosition = (int)carousel.getSelectedItemId();
carousel.performClick();
i.putExtra("SelectedScene",ImagePosition);
startActivity(i);
}
});
carousel.setOnItemClickListener(new CarouselAdapter.OnItemClickListener(){
#Override
public void onItemClick(CarouselAdapter<?> parent, View view,
int position, long id) {
Toast.makeText(NewFieldTrip.this, "Select Position=" + position, Toast.LENGTH_SHORT).show();
ImagePosition = position;
}
});
A helping hand would be great :)
EDIT:
public void scrollToChild(int i){
CarouselImageView view = (CarouselImageView)getAdapter().getView(i, null, null);
float angle = view.getCurrentAngle();
if(angle == 0)
return;
if(angle > 180.0f)
angle = 360.0f - angle;
else
angle = -angle;
mFlingRunnable.startUsingDistance(-angle);
}
What type is carousel of? ListView?
So if carousel is ListView then what event are you expected on ListView clicking?
performClick() trigger OnClickListener, which you didn't set to cаrousel. You set OnItemClickListener, so you have to call performItemClick(...). Try it.
UPD:
Try to do folowing:
1) make method Carousel.scrollToChild(int i) public
2)
int itemCount = carousel.getAdapter().getCount();
int item = new Random().nextInt(itemCount);
View view - carousel.getAdapter().getView(item, null, null);
int itemId = carousel.getAdapter().getItemId(item);
carousel.scrollToChild(item);
carousel.performItemClick(view, item, itemId);

Categories

Resources