I am trying to do this but it gave me headache
I have a view that draw a color bar. And I want to allow user to move it around (drag and drop)
this is on draw method:
int r,g,b;
for(int i = 0; i < 64; i++)
{
r = Math.round((float)colorBuffer[i][0]*MAX_SCALING);
g = Math.round((float)colorBuffer[i][1]*MAX_SCALING);
b = Math.round((float)colorBuffer[i][2]*MAX_SCALING);
paint.setColor(Color.argb(MAX_SCALING, r, g, b));
canvas.drawLine(x1, y1, x2, y1, paint);
y1+=3;
}
rgb is just the color.
this is my ontouch implementation.
public boolean onTouchEvent(MotionEvent e)
{
float x = e.getX();
float y = e.getY();
switch (e.getAction())
{
case MotionEvent.ACTION_DOWN:
{
Toast t = Toast.makeText(getContext(), "Touch", Toast.LENGTH_SHORT);
t.show();
break;
}
case MotionEvent.ACTION_MOVE:
{
x1=(int) x;
x2=(int) (x+30);
y1=(int) y;
break;
}
case MotionEvent.ACTION_UP:
{
Toast t = Toast.makeText(getContext(), "Release", Toast.LENGTH_SHORT);
t.show();
x1=(int) x;
x2=(int) (x+30);
y1=(int) y;
break;
}
}
invalidate();
return true;
}
this works perfectly fine, but the problem is that it works even outside the view.
so if i touch outsite the view my bar move over there too
even when i click a button my bar try to move too
I want to drag and drop the component only if the user touch within the view
any help would be appreciate
thanks
On touch get the x, y, width, and height of your view. Then every time when you are moving the bar, as I understand in MotionEvent.ACTION_MOVE, check if current coordinates are whithin the views's bounds, if this is true, then allow to move the bar.
Related
I have a problem with detect area click into an image.
I have the images below:
https://i.stack.imgur.com/fZmq0.jpg
https://i.stack.imgur.com/sb6Va.jpg
https://i.stack.imgur.com/YMwpy.jpg
How can I detect when touching into the yellow area?
It can be easy. You don't need to slice it.
The thing you have to do is
Click event.
Get the position where you clicked.
Get the colour of the position.
Check if the colour is yellow or not.
Do what you want when it is yellow.
It seems like the yellow is not just one yellow colour. So, What you can do is have a range of the yellow colour and compare all the possible yellow colours.
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
float x = event.getX();
float y = event.getY();
if(getColourOfThePixel(x, y)){
// DO SOMETHING
}
}
return super.onTouchEvent(event);
}
public boolean getColourOfThePixel(float x, float y){
int colorXY = mBitmap.getPixel(rangeX, rangeY);
int r = Color.red(colorXY);
int g = Color.green(colorXY);
int b = Color.blue(colorXY);
if (isYellow(r, g, b)) {
return true;
}
return false;
}
public boolean isYellow(int r, int g, int b){
// CHECK THE RANGE OF YELLOW COLOUR
}
To make it sure, you'd better have +-x, y ranges(like a square, maybe +-20pixel) because checking only one pixel may not work sometimes. So, if the square has a yellow colour, the event you wanna implement would work out.
I hope this is helpful.
I am trying to develop a simple game wherein I need to throw a bullet .
I would like the ball follows the touch, or swipe direction.
However, I have a small problem that I have not had success in solving.
I take coordinates on the ACTION_DOWN of MotionEvent, and the coordinates on the ACTION_UP of MotionEvent, then calculate the straight line equation in order to move the ball according to this straight line.
The problem is that when I swipe in a direction close to "up" or "forward" or "in front of", the ball moves at lightning speed while in the other direction of more skewed (right or left) or diagonal, the ball moves at a normal speed.
Where is the flaw in my calculation?
Help me please, I am not far from the result but need to you for solve this problem!
The onTouch method:
public boolean onTouchEvent(MotionEvent event) {
switch(event.getAction()) {
case(MotionEvent.ACTION_DOWN):
balle.setX(event.getX());
balle.setY(event.getY());
ya = event.getY();
xa = event.getX();
break;
case(MotionEvent.ACTION_UP):
xb = event.getX();
yb = event.getY();
balle.setMove(true);
break;
}
return true;
}
This is my moveDirection method:
public void moveDirection(float xa, float ya, float xb, float yb) {
if(!move) {
return;
}
else {
float m, b;
float dx = xb-xa;
m = (yb - ya) / (xb - xa);
b = ya - (m * xa);
if(dx > 0) {
this.x += speedX;
}
else {
this.x += -speedX;
}
this.y = (m * this.x + b);
}
}
Thank you in advance!
I see you are not capturing all the events so, maybe the code from the Android Documentation with de VelocityTracker api may help, in this example when you pull down your finger, a new tracker is created and when you move (in any direction) you capture the velocity of the event, i think you can move the ball according with the velocity and direction of touch.
public class MainActivity extends Activity {
private static final String DEBUG_TAG = "Velocity";
...
private VelocityTracker mVelocityTracker = null;
#Override
public boolean onTouchEvent(MotionEvent event) {
int index = event.getActionIndex();
int action = event.getActionMasked();
int pointerId = event.getPointerId(index);
switch(action) {
case MotionEvent.ACTION_DOWN:
if(mVelocityTracker == null) {
// Retrieve a new VelocityTracker object to watch the velocity of a motion.
mVelocityTracker = VelocityTracker.obtain();
}
else {
// Reset the velocity tracker back to its initial state.
mVelocityTracker.clear();
}
// Add a user's movement to the tracker.
mVelocityTracker.addMovement(event);
break;
case MotionEvent.ACTION_MOVE:
mVelocityTracker.addMovement(event);
// When you want to determine the velocity, call
// computeCurrentVelocity(). Then call getXVelocity()
// and getYVelocity() to retrieve the velocity for each pointer ID.
mVelocityTracker.computeCurrentVelocity(1000);
// Log velocity of pixels per second
// Best practice to use VelocityTrackerCompat where possible.
Log.d("", "X velocity: " +
VelocityTrackerCompat.getXVelocity(mVelocityTracker,
pointerId));
Log.d("", "Y velocity: " +
VelocityTrackerCompat.getYVelocity(mVelocityTracker,
pointerId));
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
// Return a VelocityTracker object back to be re-used by others.
mVelocityTracker.recycle();
break;
}
return true;
}
}
Link for doc.
A little problem for you but Break point for me during the development of an application.
I have a background image of Layout in which I have a Zip(Cloth zip) in the middle and at the top of image.
I want to do the following some things:
get coordinates of center-point(that is the starting point of Touch) of that image where that zip exists.
On moving the finger down, getting the changed coordinates.
X coordinate should be constant after getting the mid point, means the user can only drag on the middle of the screen vertically.
So badly waiting for an expert response.
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int height = displaymetrics.heightPixels;
int width = displaymetrics.widthPixels;
int center1 = (width/2) - (aspected touchable area you need);
int center2 = (width/2) + (aspected touchable area you need);
#Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int)event.getX();
int y = (int)event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//Logic for Zip motion
case MotionEvent.ACTION_UP:
//Logic for Zip motion
}
return false;
}
I need to drag an image like in a videogame. I have a few lines drawed and I need to drag it and see the lines drawed before "out" of the window. I give you two images trying to help to understand it.
Image before drag:
Then I touch the screen with my finger and I make a move to the top of the screen, so this three lines have to be upper than the initial image, like this:
I don't know how to do this "drag efect", can someone help me? This is not an image as a .jpg file, is three lines drawed with "drawLine" on a canvas into an imageView.
My onTouchEvent Code and my drawRectangle code:
public boolean onTouch(View view, MotionEvent event)
{
switch (event.getAction())
{
case MotionEvent.ACTION_UP:
{
x = event.getX();
y = event.getY();
getFirstFoot();
return true;
}
case MotionEvent.ACTION_MOVE:
{
ammountX = event.getX() - startX;
ammountY = event.getY() - startY;
canvas.save();
canvas.translate(ammountX, ammountY);
//canvas.restore();
imageView.invalidate();
return true;
}
case MotionEvent.ACTION_DOWN:
{
startX = event.getX();
startY = event.getY();
}
}
return true;
}
drawRectagle code:
private void drawRectangle(boolean erase)
{
buttonRed.setVisibility(View.VISIBLE);
buttonGree.setVisibility(View.VISIBLE);
buttonYellow.setVisibility(View.VISIBLE);
Bitmap bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.ascensorsininfo);
canvas.drawBitmap(bitmap2, x - (bitmap2.getWidth() / 2), y - bitmap2.getHeight(), new Paint());
drawedPoints.add(String.valueOf(x - (bitmap2.getWidth() / 2)));
drawedPoints.add(String.valueOf(y - bitmap2.getHeight()));
imageView.invalidate();
y -= bitmap2.getHeight();
}
Any solution would be apreciated. Thanks!
Check out Canvas.translate
It will "move" everything you draw afterwards the ammount you say in x and y axis.
Don't forget to save and restore it, like:
canvas.save();
canvas.translate(ammountX, ammountY);
// [draw your stuff here]
canvas.restore();
If your question is more towards how to detect the dragging effect, you have to Override your view's onTouchEvent method. Something like:
#Override
public boolean onTouchEvent (MotionEvent event){
if(event.getActionMasked() == MotionEvent.DOWN){
startX = event.getX();
startY = event.getY();
return true;
}else if(event.getActionMasked() == MotionEvent.MOVE){
ammountX = event.getX() - startX;
ammountY = event.getY() - startY;
return true;
}
return super.onTouchEvent(event);
}
I have a puzzle game where pieces are dragged around the screen but can not overlap. If they attempt to overlap, their position is changed back to where they were not overlapping and the UI is redrawn with invalidate(). This is working well except when the activity is destroyed and rebuilt like when closing the app and restarting it or when the orientation is changed.
What seems to happen is that the position variables that I use for collisions (x,y,right,bottom, etc.) are not reset to how they were initialized in the constructor. Pieces collide with invisible objects, snap to seemingly random positions, or move erratically.
The only ways to fix it are to manually kill the app (like with a task killer) or re-install it. Then it will work fine until the game activity is created a second time. What am I doing wrong? Any ideas? Here's how the piece are added in the onCreate() inside my GameView class:
Pieces redtiki = new Pieces(this,0,0,R.drawable.tikired);
...
board.addView(redtiki);
And this is a portion of my Pieces class:
public class Pieces extends View{
private int x;
private int y;
private int width;
private int height;
private int right;
private int bottom;
private int initialX;
private int initialY;
private Bitmap sizedBitmap;
private Bitmap sourceBitmap;
private int boardSize = 6;
public static ArrayList<Pieces> aPieces = new ArrayList<Pieces>();
//private final Paint mPaint = new Paint();
public Pieces(Context context, int x, int y, int img){
super(context);
this.x = x;
this.y = y;
sourceBitmap = BitmapFactory.decodeResource(getResources(), img);
aPieces.add(this);
initialX=x;
initialY=y;
}
private void sizePiece(){
int scaledWidth;
int scaledHeight;
int h = sourceBitmap.getHeight();
int w = sourceBitmap.getWidth();
if (h>w){
scaledWidth = 1;
}else if (w>h){
scaledWidth = w/h;
}else{
scaledWidth = 0;
}
if (h>w){
scaledHeight = h/w;
}else if (w>h){
scaledHeight = 1;
}else{
scaledHeight = 0;
}
int dstWidth = (((((View) getParent()).getWidth())*scaledWidth)/boardSize)-1;//TODO make sure that -1 is necessary for
int dstHeight = (((((View) getParent()).getHeight())*scaledHeight)/boardSize)-1;//fitting all pieces on the board
sizedBitmap = Bitmap.createScaledBitmap(sourceBitmap, dstWidth, dstHeight, true);
width = sizedBitmap.getWidth();
height = sizedBitmap.getHeight();
right = x+width;
bottom = y+height;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
sizePiece();
canvas.drawBitmap(sizedBitmap, x, y, null);
}
#Override
public boolean onTouchEvent(MotionEvent event){
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//check if touch is on piece
if (eventX > x && eventX < (x+width) && eventY > y && eventY < (y+height)){
initialX=x;
initialY=y;
break;
}else{
return false;
}
case MotionEvent.ACTION_MOVE:
//determine if piece should move horizontally or vertically
if(width>height){
for (Pieces piece : aPieces) {
//if object equals itself in array, skip to next object
if(piece==this){
continue;
}
//check if there the possibility for a horizontal collision
if(this.isAllignedHorizontallyWith(piece)){
//check for and handle collisions while moving left
if(this.isRightOf(piece)){
if(eventX>piece.right+(width/2)){
x = (int)(eventX-(width/2)); //move normally
/*for(Pieces piece2 : aPieces){
if(this.isAllignedHorizontallyWith(piece2)){
if(this.isLeftOf(piece2)){
if(eventX<piece2.x-(width/2)){
x = (int)(eventX-(width/2));
continue;
}else{
x = piece2.x-width-1;
}
}
}
}*/
continue;
}else{
x = piece.right+1;
}
}
//check for and handle collisions while moving right
if(this.isLeftOf(piece)){
if(eventX<piece.x-(width/2)){
x = (int)(eventX-(width/2));
continue;
}else{
x = piece.x-width-1;
}
}
break;
}else{
x = (int)(eventX-(width/2));
}
}
}
if(height>width){
for (Pieces piece : aPieces) {
//if object equals itself in array, skip to next object
if(piece==this){
continue;
}
//check if there the possibility for a vertical collision
if(this.isAllignedVerticallyWith(piece)){
//check for and handle collisions while moving up
if(this.isBelow(piece)){
if(eventY>piece.bottom+(height/2)){
y = (int)(eventY-(height/2)); //move normally
continue;
}else{
y = piece.bottom+1;
}
}
//check for and handle collisions while moving down
if(this.isAbove(piece)){
if(eventY<piece.y-(height/2)){
y = (int)(eventY-(height/2));
continue;
}else{
y = piece.y-height-1;
}
}
break;
}else{
y = (int)(eventY-(height/2));
}
}
}
invalidate();
break;
case MotionEvent.ACTION_UP:
// end move
if(this.moves()){
GameView.counter++;
}
initialX=x;
initialY=y;
break;
}
// parse puzzle
invalidate();
return true;
}
In your Activity class, implement the methods OnPause(), OnResume().
Use log statements within the above mentioned methods to see whether the positions/coordinates are changed during the closing/opening of the app.
You can save the state of the various components when "OnPause()" is called. When "OnResume()" is invoked (i.e application comes to the foreground) read the saved state and draw the View with the coordinates you read recently.
Please not that "OnCreate()" will only be called once when the Activity is being created. Switching orientations will not invoked "OnCreate()"
You will find a flowchart explaining the Android API documentation.
http://developer.android.com/reference/android/app/Activity.html
I just realized what was wrong. Each time that I create a new Pieces object, it is added to my ArrayList, aPieces. So every time that the orientation changed, or I loaded a new level, it would load all my new pieces and display them, but my old pieces were still in the ArrayList and, therefore, still being checked for collisions. to solve this, before I load each new level (and all the pieces that make up the level), I clear the list with Pieces.aPieces.clear();. Now, it works perfectly.