So I'm messing around with interacting with touch events/gestures in Android. One of the first things I did was make a textview in a relativelayout that I can drag around.
Java code is:
public class draggystuff extends ActionBarActivity implements View.OnTouchListener {
private TextView mTextView;
private ViewGroup mRootLayout;
private int _xDelta;
private int _yDelta;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_draggystuff);
mRootLayout = (ViewGroup) findViewById(R.id.root);
mTextView = (TextView) mRootLayout.findViewById(R.id.textView);
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mTextView.getLayoutParams();
mTextView.setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) mTextView.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = Y - lParams.topMargin;
Log.d("x is", String.valueOf(_xDelta));
Log.d("y is", String.valueOf(_yDelta));
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mTextView
.getLayoutParams();
layoutParams.leftMargin = X - _xDelta;
layoutParams.topMargin = Y - _yDelta;
layoutParams.rightMargin = -250;
layoutParams.bottomMargin = -250;
mTextView.setLayoutParams(layoutParams);
break;
}
mRootLayout.invalidate();
return true;
}
}
This works just fine. It sets up the textview in the upper left corner, and I can drag it around the screen. When I stop dragging, it stays put where I left it.
Next I decided that I should start with the textview in the center of the screen. To do this, I modified my OnCreate method as follows:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_draggystuff);
mRootLayout = (ViewGroup) findViewById(R.id.root);
mTextView = (TextView) mRootLayout.findViewById(R.id.textView);
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mTextView.getLayoutParams();
layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
mTextView.setOnTouchListener(this);
}
This accomplished the goal of centering my TextView, but now it would not move when I dragged it. I figured this might be because the centering attribute was locking it in place. I thought that if I removed the centering attribute before I changed its coordinates, that might work. So I added a line to my ontouch method as follows:
public boolean onTouch(View v, MotionEvent event) {
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) mTextView.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = Y - lParams.topMargin;
Log.d("x is", String.valueOf(_xDelta));
Log.d("y is", String.valueOf(_yDelta));
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mTextView
.getLayoutParams();
layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, 0);
layoutParams.leftMargin = X - _xDelta;
layoutParams.topMargin = Y - _yDelta;
layoutParams.rightMargin = -250;
layoutParams.bottomMargin = -250;
mTextView.setLayoutParams(layoutParams);
break;
}
mRootLayout.invalidate();
return true;
}
Now however, the textview starts out in the middle of the screen, but as soon as a drag even begins, it instantly moves back to the upper left before following the relative movements of my finger!
How can I center the textview in the relativelayout in such a way that it neither locks in place nor moves back to the corner before dragging?
Instead of using a relative layout, try a linear layout and use setGravity(Gravity.CENTER) on your textview to see whether it is indeed the addrule method that causes the textview to ignore any touch events.
Also, have you tried applying the layout params using XML, and seeing whether the problem is reproduced over there?
Last, does the textview move to the upper-left on the down action event or the move action event?
So to fix this issue I changed the way I Was moving the view.
My xdelta and ydelta variables became the following:
_xDelta = X - mTextView.getX();
_yDelta = Y - mTextView.getY();
Then in my action_move event, instead of setting the left and top margins, I simply used the setX and setY methods like so:
mTextView.setX(X-_xDelta);
mTextView.setY(Y-_yDelta);
Related
I want to move a button in constrainlayout according to finger movement however it has problem. I used the constrainset to reposition the button where I put my finger down, but the button automatically shifted a bit more than I expected.
I already know how to do this with RelativeLayout but I want to apply it with ConstrainLayout.
Hope everybody help please.
Below is my code:
public class MainActivity extends AppCompatActivity implements View.OnTouchListener {
AppCompatButton btn;
ConstraintLayout mLayout;
ConstraintSet constraintSet;
#SuppressLint("ClickableViewAccessibility")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
hideNavigationBar();
constraintSet = new ConstraintSet();
mLayout = findViewById(R.id.view_layout);
constraintSet.clone(mLayout);
btn = findViewById(R.id.btn);
btn.setOnTouchListener(this);
}
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
final float x = motionEvent.getRawX();
final float y = motionEvent.getRawY();
switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_DOWN:
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
if (x >= 0 && y >= 0) {
constraintSet.setHorizontalBias(R.id.btn, (x) / (mLayout.getWidth()));
constraintSet.setVerticalBias(R.id.btn, (y) / (mLayout.getHeight()));
constraintSet.applyTo(mLayout);
}
break;
}
return true;
}
The problem is the math.
The horizontal bias in ConstraintLayout works so that 0 the button is all the way to the left.
and 1 is all the way to the right.
So the total travel distance is layout width - button width
float hBias = (x) / (mLayout.getWidth()-mButton.getWidth())
float vBias = (y) / (mLayout.getHeight()-mButton.getHeight())
constraintSet.setHorizontalBias(R.id.btn, hBias);
constraintSet.setVerticalBias(R.id.btn, vBias);
But you did not say where on the button your finger should position.
This would be top left hand corner.
You might want to offset to the middle of the button which would be something like
float hBias = (x - mButton.getWidth() / 2) / (mLayout.getWidth() - mButton.getWidth())
float vBias = (y - mButton.getHeight() / 2) / (mLayout.getHeight() - mButton.getHeight())
constraintSet.setHorizontalBias(R.id.btn, hBias);
constraintSet.setVerticalBias(R.id.btn, vBias);
I have added drag functinality to my custom editext by overriding the touchevent()
Now the problem is after the edittext is dragged and dropped in a particular position and i want to input text into the edittext by clicking on it, it still getting dragged maybe because the touch event has been overriden and keyboard does not appear to input text
The workaround maybe triggering the dragfunctionality on long press but now the default longpress functionality of the edittext may change
I dont want this to happen
What to do.
mainactivity.java
public class MainActivity extends Activity
{
RelativeLayout dropLayout;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
dropLayout = (RelativeLayout) findViewById(R.id.ondraglayout);
dropLayout.setOnDragListener(new MyDragListener());
EditText et = (EditText) findViewById(R.id.mainEditText1);
}
}
my customedittext.java
public class CustomEdittext extends EditText
{
public CustomEdittext(Context context){
super(context);
}
public CustomEdittext(Context context, AttributeSet attr){
super(context, attr);
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
switch(event.getAction()){
case MotionEvent.ACTION_DOWN :
break;
case MotionEvent.ACTION_MOVE :
ClipData dragdata = ClipData.newPlainText("","");
View.DragShadowBuilder shdwbldr = new View.DragShadowBuilder(this);
this.startDrag(dragdata, shdwbldr, this, 0);
this.setVisibility(View.INVISIBLE);
break;
}
return true;
}
}
mydraglistener.java
public class MyDragListener implements OnDragListener
{
private RelativeLayout.LayoutParams params;
#Override
public boolean onDrag(View v, DragEvent event)
{
View view = (View) event.getLocalState();
switch(event.getAction())
{
case DragEvent.ACTION_DRAG_STARTED:
params = (RelativeLayout.LayoutParams) view.getLayoutParams();
break;
case DragEvent.ACTION_DRAG_ENTERED:
int x = (int) event.getX();
int y = (int) event.getY();
break;
case DragEvent.ACTION_DRAG_EXITED :
break;
case DragEvent.ACTION_DRAG_LOCATION :
x= (int) event.getX();
y = (int) event.getY();
break;
case DragEvent.ACTION_DRAG_ENDED :
break;
case DragEvent.ACTION_DROP:
x = (int) event.getX();
y = (int) event.getY();
params.leftMargin = x;
params.topMargin = y;
view.setLayoutParams(params);
view.setVisibility(View.VISIBLE);
break;
default: break;
}
return true;
}
}
my main.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="#CDC2C0"
android:id="#+id/ondraglayout">
<com.mycompany.myapp.CustomEdittext
android:layout_height="wrap_content"
android:ems="10"
android:layout_width="wrap_content"
android:id="#+id/mainEditText1"/>
Your whole code not making sense at all: First let discuss what happening inside your onTouchEvent:
#Override
public boolean onTouchEvent(MotionEvent event)
{
switch(event.getAction()){
case MotionEvent.ACTION_DOWN :
break;
case MotionEvent.ACTION_MOVE :
ClipData dragdata = ClipData.newPlainText("","");
View.DragShadowBuilder shdwbldr = new View.DragShadowBuilder(this);
this.startDrag(dragdata, shdwbldr, this, 0);
this.setVisibility(View.INVISIBLE);
break;
}
return true;
When you put your finger in the screen, the system first trigger MotionEvent.ACTION_DOWN, and afterwards, she will deliver events of MotionEvent.ACTION_MOVE as long as nothing else in the system will consume this events. The meaning of this is your call for startDrag() will call on each movement of the finger, not really make sense right? So first I suggest you to move the code from MotionEvent.ACTION_MOVE into MotionEvent.ACTION_DOWN.
Now to the more important part. When you assign a DragListener to View, the meaning is that this View will receive all the DragEvent that the system will deliver as long as the Listener returns true for the DragEvent.ACTION_DRAG_STARTED.
Now, you assigned your DragListener, to the RelativeLayout. So lets look into your code:
case DragEvent.ACTION_DROP:
x = (int) event.getX();
y = (int) event.getY();
params.leftMargin = x;
params.topMargin = y;
view.setLayoutParams(params);
view.setVisibility(View.VISIBLE);
break;
You set new position for the LayoutParams, but who is the View that will receive this params? The RelativeLayout, not your EditText. Actually your EditText is now INVISBLE as you set it visibilty to INVISIBLE inside your onTouchEvent and never changed it back. Your code "view.setVisibility(View.VISIBLE);" inside the ACTION_DROP is not referring to the EditText but to the RelativeLayout. Unless there is other code you not shown here, this is the case.
Anyway, in your case I would recommend you to move your startDrag() call to a LongCLickListener. I have no clue which functionality of the EditText you think that may change ,as, at least as far as I know, there is no functionality for LongClick in EditText. If you want to avoid it you can also add a flag to your code and turn it on after the ACTION_DROP, and then make the code inside the ACTION_DOWN to run just if this flag is set to false.
I'm trying to create something like the unlock activity of the android, where you drag the lock image outside of the circle to unlock the phone. I want to drag an image and to start an activity when it reaches a certain position. I tried doing it with a canvas but it turned out to paint other parts of my screen. So I tried using the following snippet where I found in another post here:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_touch_ball);
windowwidth = getWindowManager().getDefaultDisplay().getWidth();
windowheight = getWindowManager().getDefaultDisplay().getHeight();
final ImageView balls = (ImageView)findViewById(R.id.ball);
balls.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
LayoutParams layoutParams = (LayoutParams) balls.getLayoutParams();
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
int x_cord = (int)event.getRawX();
int y_cord = (int)event.getRawY();
if(x_cord>windowwidth){x_cord=windowwidth;}
if(y_cord>windowheight){y_cord=windowheight;}
layoutParams.leftMargin = x_cord;
layoutParams.topMargin = y_cord;
balls.setLayoutParams(layoutParams);
break;
default:
break;
}
return true;
}
});
}
But this also doesn't work so well, since when I touch the image it changes its size and also doesn't move smoothly on the screen.
Do you know how can I start an activity, lets say when I drag an image from the bottom of the screen to the top?
This is because of following line
layoutParams.leftMargin = x_cord;
layoutParams.topMargin = y_cord;
balls.setLayoutParams(layoutParams);
If you are setting margins, according to that balls will move.
I've created an OnTouchListener that will allow me to drag views around the screen. This works well, except for one problem:
My views resize instead of leaving the parent. They are in a RelativeLayout, which I suspect is contributing to the problem. They only resize when touching the right or bottom boundaries of my RelativeLayout.
I'm hoping there is a simple solution to this problem, (ideally not involving resizing the RelativeLayout), but I haven't found a solution yet.
Ideally, this solution would be applicable for all views, as I use this OnTouchListener for TextViews as well as ImageViews. I was hoping to find an XML solution. I'm assuming others have dealt with this issue??
PS: Before I post this..I've just remembered I believe there is a flag for hitting a RelativeLayout's border, so maybe I can apply negative margin to the TextView when that happens. Thoughts?
EDIT
Here is my OnTouchListener:
// Dragging functionality for all views and double tap to remove
// functionality for ImageViews
final OnTouchListener onTouchListener = new OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
v.bringToFront();
//if(v instanceof android.widget.ImageView)
//mScaleDetector.onTouchEvent(event);
layoutParams = (LayoutParams) v.getLayoutParams();
switch (event.getActionMasked())
{
case MotionEvent.ACTION_DOWN:
// Where the user started the drag
pressed_x = (int) event.getRawX();
pressed_y = (int) event.getRawY();
if (v instanceof android.widget.ImageView)
{
curTime = System.currentTimeMillis();
if(curTime - prevTime <= DOUBLE_TAP_INTERVAL)
{
v.setVisibility(View.GONE);
}
prevTime = curTime;
}
case MotionEvent.ACTION_MOVE:
// Where the user's finger is during the drag
final int x = (int) event.getRawX();
final int y = (int) event.getRawY();
// Calculate change in x and change in y
dx = x - pressed_x;
dy = y - pressed_y;
// Update the margins
layoutParams.leftMargin += dx;
layoutParams.topMargin += dy;
v.setLayoutParams(layoutParams);
// Save where the user's finger was for the next ACTION_MOVE
pressed_x = x;
pressed_y = y;
break;
default:
break;
}
return true;
}
}
can any one help me how to drag and drop the text view on entire image view. i found from this drag n drop textview in android here the text view is static, in my app textview and image view's are dynamically change. `#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Remember our initial down event location.
startX = event.getRawX();
startY = event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
float x = event.getRawX();
float y = event.getRawY();
// Calculate move update. This will happen many times
// during the course of a single movement gesture.
scrollByX = x - startX; //move update x increment
scrollByY = y - startY; //move update y increment
startX = x; //reset initial values to latest
startY = y;
invalidate(); //force a redraw
break;
}
return true; //done with this event so consume it
}
i wright this code, but it's not working properly.
You can always change the image and text of existing view programatically using setText sort of methods.
There are many drag and drop tutrials if you google it. strongly suggest you try them out.
Basically what you do is implement a OnTouchListener on the TextView like
textview.setOntouchListener(listen);
OnTouchListener onThumbTouch = new OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
switch(v.getId())
{
case R.id.slider_thumb_id:
{
switch(event.getAction())
{
case MotionEvent.ACTION_MOVE:
{
}
case MotionEvent.ACTION_UP:
{
}
}
break;
}
}
return true;
}
};
Here from the event attribute you get the value of x and y and the touch event and
use that to alter the position of the textview. I did it by add add/subtracting the margin values.
EDIT:
This is what I did to update the position of my view
Look event.getRawY(); is going to give you the distance from the parent view. So if I get event.getRawY() = 50. I know I need the text view to be 50 pixels from the top.
LinearLayout.LayoutParams iconParams = (LinearLayout.LayoutParams)
v.getLayoutParams();
iconParams.topMargin = 50;
v.setLayoutParams(iconParams);
So now the view that i selected is 50 px from the top of the parent view.