I want to implement a drag and drop but it turned out to be ridiculously time consuming, here is the problematic code:
public class MyTouchListener implements View.OnTouchListener {
public static float sharedX,sharedY;
public boolean onTouch(View view, MotionEvent motionEvent) {
sharedX = motionEvent.getX();
sharedY = motionEvent.getY();
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
ClipData data = ClipData.newPlainText("", "");
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
view.startDrag(data, shadowBuilder, view, 0);
view.setVisibility(View.INVISIBLE);
return true;
case MotionEvent.ACTION_CANCEL:
break;
case MotionEvent.ACTION_MOVE:
view.setVisibility(View.VISIBLE);
break;
case MotionEvent.ACTION_UP:
view.setVisibility(View.VISIBLE);
break;
}
return false;
}
}
The action down and action cancel are being fired, although action cancel not giving correct result (motionevent.getX isn't a sane, normal value)
None of the other events fire. I can't figure out why and I gave up trying.
Related
I was creating Ontouchlistener But i got 2 error. 1st unexpected token and 2nd Cannot resolve constructor 'Intent(anonymous android.view.View.OnTouchListener, java.lang.Class<com.krish.galaxypdfviewer.Website>)'
And when i tried onclick listener it worked without any error but i want to use Ontouchlistener
Here is the code whats wrong here?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FloatingActionButton actionButton = findViewById(R.id.action_button);
defineView();
handleIntent();
defineActionBar();
checkPermission();
long start;
actionButton.setOnTouchListener(new View.OnTouchListener(){
#Override
public boolean onTouch(final View v, final MotionEvent event){
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
start=System.currentTimeMillis();
return true;
case MotionEvent.ACTION_UP:
if(System.currentTimeMillis()-start<500){ //Click is less than 500ms, you can adjust this value later...
//Do what you want on click over here...
}else{
openWebsite(); //It's a long click, do what you want over here...
}
return true;
default:
return false;
}
});
public void openWebsite() {
Intent intent = new Intent(this, Website.class);
startActivity(intent);
}
There's a missing closing curly brace for the onTouch method.
actionButton.setOnTouchListener(new View.OnTouchListener(){
#Override
public boolean onTouch(final View v, final MotionEvent event){
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
start=System.currentTimeMillis();
return true;
case MotionEvent.ACTION_UP:
if(System.currentTimeMillis()-start<500){ //Click is less than 500ms, you can adjust this value later...
//Do what you want on click over here...
}else{
openWebsite(); //It's a long click, do what you want over here...
}
return true;
default:
return false;
}
} // this one closes onTouch
});
I want to apply some animation whenever user touch on button, like-
on touch/hover = scale down,
move finger out of the view bound = scale up to previous position,
on release/click = scale up to previous position
On touch animation is working perfectly but I am unable to figure out scale up animation to it's previous position when finger is being released. Also I am not too much familiar with Motion touch event, so please tell me which Motion Event will be appropriate to do this. Can anyone please help me. here is my code:
imageView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
imageView.animate().scaleX(0.5f).scaleY(0.5f).start();
break;
case MotionEvent.ACTION_CANCEL:
imageView.animate().scaleX(2.0f).scaleY(2.0f).start();
break;
case MotionEvent.ACTION_UP:
imageView.animate().scaleX(2.0f).scaleY(2.0f).start();
startActivity(new Intent(ActivityOne.this, ActivityTwo.class));
break;
}
return true;
}
});
I have also tried with object animator, something like that:
private void scaleAnimation(View view) {
ObjectAnimator scaleDownX = ObjectAnimator.ofFloat(view, "scaleX", 0.5f);
ObjectAnimator scaleDownY = ObjectAnimator.ofFloat(view, "scaleY", 0.5f);
scaleDownX.setDuration(150);
scaleDownY.setDuration(150);
//scaleDownX.setRepeatMode(ValueAnimator.REVERSE);
//scaleDownY.setRepeatMode(ValueAnimator.REVERSE);
//scaleDownX.setRepeatCount(1);
//scaleDownY.setRepeatCount(1);
animatorSet = new AnimatorSet();
//animatorSet.play(scaleDownX).with(scaleDownY);
animatorSet.playTogether(scaleDownX, scaleDownY);
animatorSet.start();
}
Alright after a long experiment I have discovered the answer by myself. Here it is:
After touch, if user move his finger then we need to cancel button click
boolean isMove;
// initialize
isMove = false;
Set scale down and scale up animation
private void startScaleAnimation(View view) {
ObjectAnimator scaleDownX = ObjectAnimator.ofFloat(view, "scaleX", 0.8f);
ObjectAnimator scaleDownY = ObjectAnimator.ofFloat(view, "scaleY", 0.8f);
scaleDownX.setDuration(150);
scaleDownY.setDuration(150);
scaleDownX.start();
scaleDownY.start();
}
private void cancelScaleAnimation(View view) {
ObjectAnimator scaleDownX = ObjectAnimator.ofFloat(view, "scaleX", 1.0f);
ObjectAnimator scaleDownY = ObjectAnimator.ofFloat(view, "scaleY", 1.0f);
scaleDownX.setDuration(150);
scaleDownY.setDuration(150);
scaleDownX.start();
scaleDownY.start();
}
Now, apply this animation along with onTouch listener
imageView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startScaleAnimation(imageView);
break;
case MotionEvent.ACTION_MOVE:
cancelScaleAnimation(imageView);
isMove =true;
break;
case MotionEvent.ACTION_UP:
cancelScaleAnimation(imageView);
if (!isMove){
isMove = false;
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
startActivity(new Intent(ActivityOne.this, ActivityTwo.class));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
overridePendingTransition(R.anim.enter_slide_left, R.anim.exit_slide_left);
}
}
},150);
}else {
isMove = false;
}
break;
}
return true;
}
});
I'm relatively a rookie/beginner with Java/Android programming. I've been trying to make it so while I press a given button in my application it produces a DTMF tone, but when I try to use setOnTouchListener the Android Studio shows me that error. It also gives me an error for MotionEvent which states Expression expected
Here are the important parts of the code:
boolean pressedCCW = false;
class SendCCWTone extends AsyncTask<Void,Void,Void>{
#Override
protected Void doInBackground(Void... arg0){
ToneGenerator toneGen;
toneGen = new ToneGenerator(AudioManager.STREAM_DTMF,100);
while(pressedCCW){
toneGen.startTone(ToneGenerator.TONE_DTMF_1);
}
toneGen.stopTone();
toneGen.release();
createLog("CCW");
return null;
}
}
final Button buttonCCW = (Button) findViewById(R.id.counter_clockwise);
buttonCCW.setOnTouchListener(new View.OnTouchListener(){// Where the error is
#Override
public boolean onTouch(View v, MotionEvent event){// Where the other error is located
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
if(pressedCCW == false){
pressedCCW = true;
new SendCCWTone().execute();
}
break;
case MotionEvent.ACTION_UP:
pressedCCW = false;
}
return true;
}
});
You are creating OnTouchListener inside of setOnClickListener. If you need TouchListener then you should register using setOnTouchListener instead of setOnClickListener
buttonCCW.setOnTouchListener(new View.OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event){
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
if(pressedCCW == false){
pressedCCW = true;
new SendCCWTone().execute();
}
break;
case MotionEvent.ACTION_UP:
pressedCCW = false;
}
return true;
}
});
This problem can be solved if you place setOnTouchListener inside the onCreate() method of your activity.
Rather than use setOnClickListener, you can set onClick in the XML and point to a method (it does the same thing and looks nicer). In this case, you'd have a method like produceSound:
public void produceSound(View view) {
// your onClick method
}
and in the activity's XML, find where that button, counter_clockwise, is and add: android:onClick="produceSound" to the button's XML.
More here if you're curious: How exactly does the android:onClick XML attribute differ from setOnClickListener?
However, if you're using onTouch, then you will have to stick with what everyone else is suggesting. XML does not support an android:onTouch attribute.
Try to add this to your code :
implements View.OnTouchListener
and use setOnTouchListner instead of setOnClickListener.
buttonCCW.setOnListener(new View.OnTouchListener(){// Where the error is
#Override
public boolean onTouch(View v, MotionEvent event){// Where the other error is located
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
if(pressedCCW == false){
pressedCCW = true;
new SendCCWTone().execute();
}
break;
case MotionEvent.ACTION_UP:
pressedCCW = false;
}
return true;
}
});
I created an onTouchEvent to find where the user touches and move my object to that position. what I would like to do is if the user presses up on the screen, the object moves a certain distance straight up. and the same for the other directions. I know that I need a few if statements to do this but I don't know how to do it. does anyone have any advice or know how to do this, thanks
public boolean onTouchEvent(MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_DOWN) {
// the new image position became where you touched
x = ev.getX();
y = ev.getY();
// if statement to detect where user presses down
if(){
}
// redraw the image at the new position
Draw.this.invalidate();
}
return true;
}
Try this
public boolean onTouchEvent(MotionEvent ev) {
initialise boolean actionDownFlag = false;
if(ev.getAction() == MotionEvent.ACTION_DOWN) {
// the new image position became where you touched
x = (int) ev.getX();
y = (int) ev.getY();
// if statement to detect where user presses down
if(actionDownFlag){
catcher.moveDown();
}
// redraw the image at the new position
Draw.this.invalidate();
}
return true;
}
public void moveDown(){
posX -= //WhereEver you want to move the position (-5);
}
try this:
layout_counter.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event)
{
if (currentState != State.EDIT_MOVE) return false;
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) view.getLayoutParams();
if (view.getId() != R.id.layout_counter) return false;
switch (event.getAction())
{
case MotionEvent.ACTION_MOVE:
params.topMargin = (int) event.getRawY() - view.getHeight();
params.leftMargin = (int) event.getRawX() - (view.getWidth() / 2);
view.setLayoutParams(params);
break;
case MotionEvent.ACTION_UP:
params.topMargin = (int) event.getRawY() - view.getHeight();
params.leftMargin = (int) event.getRawX() - (view.getWidth() / 2);
view.setLayoutParams(params);
break;
case MotionEvent.ACTION_DOWN:
view.setLayoutParams(params);
break;
}
return true;
}
});
You need to use OnLongClickListener which suits better with drag and drop framework of android:
Observe the following example:
public class MainActivity extends Activity {
private ImageView myImage;
private static final String IMAGEVIEW_TAG = "The Android Logo";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myImage = (ImageView)findViewById(R.id.image);
// Sets the tag
myImage.setTag(IMAGEVIEW_TAG);
// set the listener to the dragging data
myImage.setOnLongClickListener(new MyClickListener());
findViewById(R.id.toplinear).setOnDragListener(new MyDragListener());
findViewById(R.id.bottomlinear).setOnDragListener(new MyDragListener());
}
private final class MyClickListener implements 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);
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;
}
}
class MyDragListener implements OnDragListener {
Drawable normalShape = getResources().getDrawable(R.drawable.normal_shape);
Drawable targetShape = getResources().getDrawable(R.drawable.target_shape);
#Override
public boolean onDrag(View v, DragEvent event) {
// 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:
v.setBackground(targetShape); //change the shape of the view
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 == findViewById(R.id.bottomlinear)) {
View view = (View) event.getLocalState();
ViewGroup viewgroup = (ViewGroup) view.getParent();
viewgroup.removeView(view);
//change the text
TextView text = (TextView) v.findViewById(R.id.text);
text.setText("The item is dropped");
LinearLayout containView = (LinearLayout) v;
containView.addView(view);
view.setVisibility(View.VISIBLE);
} else {
View view = (View) event.getLocalState();
view.setVisibility(View.VISIBLE);
Context context = getApplicationContext();
Toast.makeText(context, "You can't drop the image here",
Toast.LENGTH_LONG).show();
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;
}
}
}
The above code taken from here demonstrates how to drag and drop and how to do something while dragging..
I've used something similar as well.
onDrag Class:
private class ChoiceDragListener implements OnDragListener {
#Override
public boolean onDrag(View v, DragEvent event) {
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
// no action necessary
break;
case DragEvent.ACTION_DRAG_ENTERED:
// no action necessary
break;
case DragEvent.ACTION_DRAG_EXITED:
// no action necessary
break;
case DragEvent.ACTION_DROP:
// handle the dragged view being dropped over a drop view
View view = (View) event.getLocalState();
dropTarget = (RelativeLayout) v;
dropped = (RelativeLayout) view;
tagDropped = dropped.getTag().toString();
Log.i("tagDropped", "" + tagDropped);
tagDropTarget = dropTarget.getTag().toString();
Log.i("tagDropTarget", "" + tagDropTarget);
matchTag();
break;
case DragEvent.ACTION_DRAG_ENDED:
// no action necessary
break;
default:
break;
}
return true;
}
}
ChoiceTouchListener class:
private final class ChoiceTouchListener implements OnTouchListener {
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
/*
* Drag details: we only need default behavior - clip data could
* be set to pass data as part of drag - shadow can be tailored
*/
ClipData data = ClipData.newPlainText("", "");
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(
view);
// start dragging the item touched
view.startDrag(data, shadowBuilder, view, 0);
return true;
} else {
return false;
}
}
}
Now i want to move object on its original position where it is drag
I have search like that but not answered any one drag and drop with onDraglistener animate to go back to original position if not dropped on target
first get the distance between dragger control and drag receiver control:
textview1 is dragger control
textview2 is drag receiver control
//if text view2 is below textview one and text view 2 is on the right of text view one
int topMargin=textview2_top_margin - textview1_top_margin
int leftMargin=textview2_left_margin - textview1_left_margin
public void animation() {
Animation animation = new TranslateAnimation(left_margin, 0, topMargin, 0);
animation.setDuration(1000);
controlToAnimate.startAnimation(animation);
}