Imageview not following finger touch - android

I want to build an app that has an imageview and it simply follows the finger touch. In other words, the imageview follows the touch of the finger. I have partially achieved this, in the sense that the imageview is following the touch of the finger but the problem is that it is at some offset. The imageview is about an inch down the actual touch.
Below is my code:
public class MainActivity extends AppCompatActivity {
ImageView img;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
img = (ImageView)findViewById(R.id.img1);
img.setImageResource(R.drawable.ic_remove_circle_black_24dp);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
img.setX(event.getX());
img.setY(event.getY());
return false;
}
}
What could be the reason behind the offset?
Edit: Solution
Following code does what I need:
public class MainActivity extends AppCompatActivity {
ImageView img;
int[] viewCoords = new int[2];
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
img = (ImageView)findViewById(R.id.img1);
img.setImageResource(R.drawable.ic_remove_circle_black_24dp);
}
#Override
public boolean onTouchEvent(MotionEvent event){
img.getLocationOnScreen(viewCoords);
img.setX(event.getX()-(viewCoords[0]-img.getX()));
img.setY(event.getY()-(viewCoords[1]-img.getY()));
return true;
}
}
Thanks to Doomsknight for the direction.

From what I can see, you are using the X and Y coordinates of the touch event of the Screen.
And then drawing this coordinates on the X and Y of the ImageView.
This will cause the offset you are seeing, as they do not match up, as the imageview probably isnt at the very top of your screen.
What I think you are trying to do is get the X and Y, of the actual image.
You will therefore need to offset the coordinates accordingly.
There is a good example of this already of getting the offset, and removing it: see link below.
https://stackoverflow.com/a/11312423/940834
You can get the top left corner of your view as follows:
int[] viewCoords = new int[2];
imageView.getLocationOnScreen(viewCoords);
From this and the touch
coordinates you can calculate the point inside the ImageView:
int touchX = (int) event.getX();
int touchY = (int) event.getY();
int imageX = touchX - viewCoords[0]; // viewCoords[0] is the X coordinate
int imageY = touchY - viewCoords[1]; // viewCoords[1] is the y coordinate

Related

How do I implement onDragListener in an object within a fragment?

My app has a class, MarkedLine, which extends View. An instance of this class is shown in a Fragment. I want users to be able to do the following 3 things:
Enlarge the line by doing "pinch" and "stretch" gestures
Touch any point of the line and get its coordinates
Move the line around
I have the first two working, but can't figure out the third one (the dragging).
Each MarkedLine consists of a horizontal line of boxes, some of which are coloured in. The user can zoom in by stretching, and tap a box to change its colour; I also want them to be able to move the line around the screen, because when it's zoomed in it will go off the edges of the screen.
The basic fragment layout (fragment_marked_line) is as follows (I've removed irrelevant bits, padding, margins etc.):
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:res="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<packagepath.models.ToolboxButton
android:id="#+id/toolbarNext"
android:layout_width="#dimen/toolbar_icon_size"
android:layout_height="#dimen/toolbar_icon_size"
android:src="#drawable/next_line"
res:layout_constraintTop_toTopOf="parent" />
<packagepath.models.MarkedLine
android:id="#+id/markedLine"
android:layout_width="0dp"
android:layout_height="wrap_content"
res:layout_constraintStart_toStartOf="parent"
res:layout_constraintEnd_toEndOf="parent"
res:layout_constraintTop_toBottomOf="#+id/toolbarNext" />
</android.support.constraint.ConstraintLayout>
(So basically it's a button with a full-width line underneath it. The button allows the user to bring up the next line).
The Fragment code (MarkedLineFragment) is as follows (n.b. A LineSet is basically just an array of MarkedLines, with a few extra variables like when it was created, the line dimensions etc):
public class MarkedLineFragment extends Fragment {
LineSet mLineSet
MarkedLine mMarkedLine;
ToolboxButton btn_next;
int mItemNumber, mMaxItems;
public MarkedLineFragment() {}
#Override
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View rootView = inflater.inflate(
R.layout.fragment_marked_line, container, false);
// Get view objects
btn_next = rootView.findViewById(R.id.toolbarNext);
mMarkedLine = rootView.findViewById(R.id.markedLine);
// Initialise the button
initialise_button();
// If the LineSet has already been set,
// pass it through to the MarkedLine
if(mLineSet != null) {
mMarkedLine.setLineSet(mLineSet);
mMaxItems = mLineSet.getNum_items();
}
// Initialise at line 1
mItemNumber = 1;
mMarkedLine.setCurrentItem(mItemNumber);
// Draw the MarkedLine
drawLine();
return rootView;
}
// Initialise the button so that it moves to the next line on clicking
public void initialise_button() {
btn_next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mItemNumber == mMaxItems) return;
else mItemNumber += 1;
set_new_item_number();
}
});
}
private void set_new_item_number() {
mMarkedLine.setCurrentItem(mItemNumber);
}
public void drawChart() {
if(mMarkedLine != null) mMarkedLine.postInvalidate();
}
}
Finally, MarkedLine class (I've left out the details of how the line is drawn, because I don't think it's relevant, and it's quite long - but I can add it in if needed):
public class MarkedLine extends View {
private LineSet mLineSet;
private int currentItem;
private int numBoxes;
private float canvas_height, canvas_width;
private float box_size;
private float minX, maxX, minY, maxY;
// Scaling (pinch & zoom) variables
private float scaleFactor = 1.0f; // Current scale factor
private ScaleGestureDetector detectorScale;// Detector for gestures
private GestureDetector detectorTouch; // Detector for tap gestures
public MarkedLine(Context thisContext, AttributeSet attrs) {
super(thisContext, attrs);
detectorScale = new ScaleGestureDetector(thisContext, new MarkedLine.ScaleListener());
detectorTouch = new GestureDetector(thisContext, new MarkedLine.TouchListener());
}
public void setCallback(OnBoxTouched callback) { mCallback = callback; }
public void setLineSet(LineSet lineSet) {
mLineSet = lineSet;
numBoxes = mLineSet.getNum_boxes();
invalidate();
}
public void setCurrentItem(int newItemNumber) {
currentItem = newItemNumber;
invalidate();
}
protected void onDraw(Canvas canvas) {
if (mLineSet == null) return;
// Set up canvas
canvas.save();
canvas.scale(scaleFactor, scaleFactor);
canvas.translate(translateX / scaleFactor, translateY / scaleFactor);
// draw_boxes reads how many boxes make up the MarkedLine,
// calculates what size they need to be to fit on the canvas,
// and then draws them
draw_boxes();
// fill_in_line adds in the appropriate colours to the
// boxes in the line
fill_in_line();
canvas.restore();
}
// GRID EVENT FUNCTIONS - respond to User touching screen
// onTouchEvent
// User has touched the screen - trigger listeners
#Override
public boolean onTouchEvent(MotionEvent event) {
detectorScale.onTouchEvent(event);
detectorTouch.onTouchEvent(event);
invalidate();
return true;
}
// LISTENERS
/*
* Respond to user touching the screen
*/
private class TouchListener extends GestureDetector.SimpleOnGestureListener {
public boolean onSingleTapUp(MotionEvent event) {
// Determine where the screen was touched
float xTouch = event.getX();
float yTouch = event.getY();
// Check that the touch was within the line; return if not
if(!touch_in_line(xTouch, yTouch)) return false;
// Figure out which Box was tapped
int xCell = getTouchedBox(xTouch);
// Now the box which was tapped is coloured in
colour_box(xCell);
return true;
}
}
/*
* Determine scale factor for zoom mode
* This can be called in View and Edit Activities
*/
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
float MIN_ZOOM = 1f; // Minimum zoom level
float MAX_ZOOM = 5f; // Maximum zoom level
scaleFactor *= detector.getScaleFactor();
scaleFactor = Math.max(MIN_ZOOM, Math.min(scaleFactor, MAX_ZOOM));
return true;
}
}
}
This all works fine. The user can stretch the line to make the boxes bigger/smaller, and then tap on any of the boxes on the line to colour them in. However, I can't get the box to move around the screen when the user drags their finger on it.
I assume I need to add an onDragListener to something, but I can't figure out what. I tried having a DragListener class, similar to the ScaleListener and TouchListener classes, with an onDrag method (I just has a couple of dummy lines so I could attach a breakpoint). Then I declared an instance of that class (dragListener). I tried attaching it in the MarkedLine constructor using this.onDragListener(dragListener) but it didn't respond to dragging.
Then I attempted something similar in the Fragment, attaching it to the mMarkedLine class in onCreateView, but again it didn't respond when I tried to drag.
I've read the Android documentation, which suggested the onDragListener class, but I'm clearly doing something wrong.
In case it helps anyone else, I fixed this by adding a check for dragging in the onTouchEvent of the MarkedLine class:
#Override
public boolean onTouchEvent(MotionEvent event) {
detectorScale.onTouchEvent(event);
detectorTouch.onTouchEvent(event);
// Check for drag gestures
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = event.getX() - previousTranslateX;
startY = event.getY() - previousTranslateY;
break;
case MotionEvent.ACTION_UP:
previousTranslateX = translateX;
previousTranslateY = translateY;
break;
case MotionEvent.ACTION_MOVE:
translateX = event.getX() - startX;
translateY = event.getY() - startY;
break;
}
invalidate();
return true;
}

How disable scroll movement when i move a bitmap?

I want move a bitmap in the screen, but i can do it only horizontally, because if I do it vertically, the scroll of the view start and the movement of the bitmap disappears. I have
public boolean onTouchEvent(MotionEvent event)
method where in case MOVE I change the X and Y of the bitmap. Then in onDraw() method I paint the bitmap. The scroll are in xml. Inside of it are a layout and inside a View.
I would like when I touch, in case DOWN, if I touch the bitmap, disable the scroll, but I is in other place no.
that is the resume of the code
public class Table extends ScrollView{
private static Integer srcX = 0, srcY = 0;
public Table(Context context) {
super(context);
setWillNotDraw(false);
setVerticalScrollBarEnabled(true);
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for(int i=1; i<= Paint_Table.num_players; i++)
canvas.drawBitmap(bitmap, X, Y, null);
}
#SuppressLint("ClickableViewAccessibility") #Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
if (youTouchBitmap) {
srcX = x;
srcY = y;
}
break;
case MotionEvent.ACTION_MOVE:
if (srcX !=0 && srcY != 0) {
X=x;
Y=y;
invalidate();
}
break;
}
return true;
}
}
Can someone help me?
Thanks and regards.
since i dont see code ive find some link might help you:
How to disable and enable the scrolling on android ScrollView?
in the link you can see in the answers a code that is custom scroll view its work on flag.
you can choose when the scroll will work ot not.
hope i helpd :)

Android dragging unlimited images from the sources

I am trying to implement a drag and drop function in Android.I have choosed to implement it using motion event because I think it is easy to understand.I want to make that image I move to remain in the same position and move a duplication. I don't really know how to explain, I want an image on the corner and when I move it the image still remain there but I move another one that is the same, and If I want to move another one from the same position again I move another position.It's like I am trying to get 10 balls from a basket but in this case the basket and the balls are the same image.
My code so far is this:
public class MainActivity extends ActionBarActivity {
private View selected_item = null;
private int offset_x = 0;
private int offset_y = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewGroup vg = (ViewGroup)findViewById(R.id.container);
vg.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getActionMasked())
{
case MotionEvent.ACTION_MOVE:
int x = (int)event.getX() - offset_x;
int y = (int)event.getY() - offset_y;
int w = getWindowManager().getDefaultDisplay().getWidth() - 100;
int h = getWindowManager().getDefaultDisplay().getHeight() - 100;
if(x > w)
x = w;
if(y > h)
y = h;
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
new ViewGroup.MarginLayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
lp.setMargins(x, y, 0, 0);
selected_item.setLayoutParams(lp);
break;
default:
break;
}
return true;
}
});
ImageView img = (ImageView)findViewById(R.id.newwall);
img.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getActionMasked())
{
case MotionEvent.ACTION_DOWN:
offset_x = (int)event.getX();
offset_y = (int)event.getY();
selected_item = v;
break;
default:
break;
}
return false;
}
});
Also, I am using a ViewGroup and I have a touchListener attached on it.When I am pressing the Layout I am getting the image where I press, I would like when I drop the image to remain there if I touch somewhere else on the screen.I have tried to set selected_item back to null when I end the drag but I didn't make it good I guess because I was getting error and app crashes.
Please help me solve these 2 problems.
Here is what I have used for similar purpose
ImageView snapshot = (ImageView)findViewById(R.id.nonFullScreenSnapshot);
vg.buildDrawingCache();
cache = Bitmap.createBitmap(vg.getDrawingCache());
Drawable drawableShot = new BitmapDrawable(getResources(), cache);
snapshot.setImageDrawable(drawableShot);
snapshot.setVisibility(View.VISIBLE);
In this case I have an ImageView already available from my xml layout, which should be at least as big as the image you want to duplicate.
So when the user touches your ViewGroup you should make a duplicate of it and then position it on the new location.
But be careful with the number of duplicates, because you can easily run out of memory and you will get OutOfMemory exception.

Add Image to layout on touch in android with respect to touch position

Where ever i touch on the screen with respect to x y position i need to add one image on that particular position.
I tried by implementing the ontouch listener but it is adding image to different position and many images are being appeared on many touch i want some thing like where ever i touch that same image should appear there
Please Help i am new to android working on project in a compnay
This is my activity code
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final RelativeLayout rl = (RelativeLayout) findViewById(R.id.wwcontainer);
//Set On TouchListner to the Layout
rl.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.i("OnTouch", "On Touch View Group....");
int x = (int) event.getX();
int y = (int) event.getY();
ImageView imageView = new ImageView(getApplicationContext());
imageView.setImageResource(R.drawable.icon);
imageView.setLayoutParams(new LayoutParams(x,y));
rl.addView(imageView);
return true;
}
});
}
I know about drag and drop i dont want drag and drop instead i need touch any where there image should appear wrt touch position please help me
I had same request and this is what i done and it worked perfectly for me
final RelativeLayout rr = (RelativeLayout) findViewById(R.id.rr);
rr.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
ImageView iv = new ImageView(getApplicationContext());
lp.setMargins(x, y, 0, 0);
iv.setLayoutParams(lp);
iv.setImageDrawable(getResources().getDrawable(
R.drawable.gr1));
((ViewGroup) v).addView(iv);
}
return false;
}
});
This will place image to RelativeLayout where you touched starting coordinates from there. If you want to center new image where you touched RelativeLayout you need to calculate Height and Width of your image and change one line in my code to
lp.setMargins(x - yourImageWidth/2, y - yourImageHeight/2, 0, 0);
You need to use AbsoluteLayout instead of RelativeLayout.
To add image at particular x,y location, you need AbsoluteLayout.
Did you check what int value getX() and getY() returns i think it will return 0,0.
please use event.getRawX() & event.getRawX() for actual touch position. i hope it will help.

Display image in area touch with finger on the screen

When I touch a region on my screen, I want an ImageView to be visible at the touch area. An example of imageview is as follows.
ImageView image = (ImageView)findViewById(R.id.image);
How can I set the image at region touch on the screen using the method below. Also when I tap on a new region the previous image become invisible.
#Override
public boolean onTouchEvent(MotionEvent event, view) {
final int action = event.getAction();
final int x = (int) event.getX();
final int y = (int) event.getY();
boolean result = false;
}
Use Canvas you will get the xy coordinates and you can easily get Imageview at that coordinates

Categories

Resources