I created a method for changing the position of an ImageView, based on the position of other Image.
public void move(double zx, double zy) {
RelativeLayout.LayoutParams params =
new RelativeLayout.LayoutParams(80,80);
// the imageView s was initialized in the onCreate()
System.out.println("working");
if (zx < s.getLeft()) {
if (s.getLeft() - zx > 0) {
params.leftMargin = s.getLeft() -1;
} else
params.leftMargin = s.getLeft() +1;
}
if (zx > s.getLeft()) {
if (s.getLeft() - zx > 0) {
params.leftMargin = s.getLeft() -1;
} else
params.leftMargin = s.getLeft() +1;
}
if (zy > s.getTop()) {
if (s.getTop() - zy > 0) {
params.topMargin = s.getTop() -1;
} else
params.topMargin = s.getTop() + 1;
}
if (zy < (int)s.getY()) {
if ((int)s.getY() - zy > 0) {
params.topMargin = s.getTop() -1;
} else
params.topMargin = s.getTop() + 1;
}
s.setLayoutParams(params);
}
Then I called in the onCreate()
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fase);
s = (ImageView)findViewById(R.id.s);
box = (ImageView)findViewById(R.id.box);
move(box.getLeft(),box.getTop());
}
The message "working" was printed, but only once. The imageview's position also didn't change. My conclusion is that the method wasn't executed repeatedly. Otherwise, the imageView's position would be changing every time, and the message "working" would appear each instant. How can I solve it? Should I call the method in other class? I tried to call it in a timertask and execute the timertask each milisecond, but tha application just stopped.
Drag command for the other ImageView (inside oncreate):
box.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
LayoutParams layoutParams = (LayoutParams) box.getLayoutParams();
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
System.out.println(box.getLeft());
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 - 250;
layoutParams.topMargin = y_cord - 300;
box.setLayoutParams(layoutParams);
break;
default:
break;
}
return true;
}
});
First, you never told your program to execute your method move more than once when onCreate is called. Second timertask each milisecond.. i think this will be way to much executing move 1000 times each second .. and third using timertask can lead to many Problems, you can use handler instead for example.
Have a look at this, it shows you how to implement a handler for repeating Tasks!
Related
I have two activities; one is IntermediateActivity, and one is the DragAndDrop activity. The IntermediateActivity has a 5-second timer, and a visitcount variable incremented every time the IntermediateActivity is opened. After the timer is over, the DragAndDrop activity is opened, in which the user has to drag a circle to the desired position, and when the user can do that, I start an intent that opens the the IntermediateActivity again.
What is happening is that for the runs of DragAndDrop when the IntermediateActivity is opened, the visit count gets incremented by 2 instead of one.
Here's how I call the intent for IntermediateActivity in the DragAndDrop Activity :
public class DragAndDrop extends AppCompatActivity implements View.OnTouchListener{
private ImageView img;
private ImageView img_outline;
private ViewGroup rootLayout;
private int _xDelta;
private int _yDelta;
#SuppressLint("ClickableViewAccessibility")
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
List<Integer> givenList = Arrays.asList(0, 1, 2, 3);
Random rand = new Random();
int randomElement = givenList.get(rand.nextInt(givenList.size()));
// Randomise location of Circle
switch (randomElement){
case 0:
setContentView(R.layout.bottom_left);
rootLayout = (ViewGroup) findViewById(R.id.bottom_left_layout);
img = (ImageView) rootLayout.findViewById(R.id.circle_bottomLeft);
img_outline = findViewById(R.id.circle_outline_bottomLeft);
break;
case 1:
setContentView(R.layout.bottom_right);
rootLayout = (ViewGroup) findViewById(R.id.bottom_right_layout);
img = (ImageView) rootLayout.findViewById(R.id.circle_bottomRight);
img_outline = findViewById(R.id.circle_outline_bottomRight);
break;
case 2:
setContentView(R.layout.top_left);
rootLayout = (ViewGroup) findViewById(R.id.top_left_layout);
img = (ImageView) rootLayout.findViewById(R.id.circle_topleft);
img_outline = findViewById(R.id.circle_outline_topleft);
break;
case 3:
setContentView(R.layout.top_right);
rootLayout = (ViewGroup) findViewById(R.id.top_right_layout);
img = (ImageView) rootLayout.findViewById(R.id.circle_topRight);
img_outline = findViewById(R.id.circle_outline_topRight);
break;
}
img.setOnTouchListener(this);
}
public void check_success(){
float centreX = img.getX() + img.getWidth() / 2;
float centreY = img.getY() + img.getHeight() / 2;
float centreX_outline = img_outline.getX() + img_outline.getWidth() / 2;
float centreY_outline = img_outline.getY() + img_outline.getHeight() / 2;
// Location Range for 150 x 150dp square with center = center of outline
if((centreX >= centreX_outline-75) &&(centreX <= centreX_outline+75)
&& (centreY >= centreY_outline-75) &&(centreY <= centreY_outline+75)){
// Vibrate
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
v.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE));
} else {
v.vibrate(500);
}
// Start Intermediate Activity
Intent i = new Intent(DragAndDrop.this, IntermediateActivity.class);
startActivity(i);
}
}
public boolean onTouch(View view, MotionEvent event) {
check_success();
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) view.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = Y - lParams.topMargin;
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
//Drag Functionality
ViewGroup.MarginLayoutParams marginParams = new ViewGroup.MarginLayoutParams(img.getLayoutParams());
int left = (int) event.getRawX() - (view.getWidth() / 2);
int top = (int) event.getRawY() - (view.getHeight());
marginParams.setMargins(left, top, 0, 0);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(marginParams);
img.setLayoutParams(layoutParams);
break;
}
rootLayout.invalidate();
return true;
}
}
And here's the code for the IntermediateActivity in which the variablevisitCount tracks the number of times the activity is called :
private TextView footer_text;
private TextView timer_text;
public int timer_counter;
static int visitCount = 0;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.intermediate_screen);
timer_text = findViewById(R.id.timer);
footer_text = findViewById(R.id.footer);
timer_counter = 5;
Resources resource = getResources();
if (resource.getConfiguration().locale.getLanguage() == "hi") {
footer_text.setText("कार्य की पूर्णता : " + String.valueOf(visitCount) + "/30");
} else {
footer_text.setText("Tasks completed: " + String.valueOf(visitCount) + "/30");
}
visitCount++;
if (visitCount == 31) {
visitCount = 0;
Intent k = new Intent(IntermediateActivity.this, MainActivity.class);
startActivity(k);
} else {
new CountDownTimer(5000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
timer_text.setText(String.valueOf(timer_counter));
timer_counter--;
}
#Override
public void onFinish() {
i = new Intent(IntermediateActivity.this, DragAndDrop.class);
startActivity(i);
}
}.start();
}
}
I tried to go through the code multiple times but I couldn't get why the count would be getting incremented multiple times even when the intent would be sent only once.
(Xamarin with Visual Studio 2015 ) I want to implement a simple Activity inwith an Imageview, which can be moved/dragged with touch: This is what I have implemented, but the Image is flickering and moving slower. Can you give me an example how to implement this?
Thanks for your help!
private void TouchMeImageViewOnTouch(object sender, View.TouchEventArgs touchEventArgs)
{
View bild = (View)sender;
RelativeLayout.LayoutParams layouti = (RelativeLayout.LayoutParams)bild.LayoutParameters;
switch (touchEventArgs.Event.Action & MotionEventActions.Mask)
{
case MotionEventActions.Down:
xDelta = touchEventArgs.Event.GetX()-layouti.LeftMargin;
yDelta = touchEventArgs.Event.GetX() - layouti.LeftMargin;
break;
case MotionEventActions.Move:
int wert = (int)touchEventArgs.Event.GetX();
yvalue = touchEventArgs.Event.GetY()-yDelta;
xvalue = touchEventArgs.Event.GetX()-xDelta;
float xdpi = (int) Resources.DisplayMetrics.Density;
layouti.LeftMargin = (int)xvalue;
layouti.TopMargin = (int)yvalue;
container.Invalidate();
break;
case MotionEventActions.Up:
break;
default:
break;
}
xPositionText.Text = xvalue.ToString();
yPositionText.Text = yvalue.ToString();
}
I have tried to implement a dragable imageview for testing. the drag is slow in the android emulator. But by testing it in the real device it works fine and move fast.
Try the following code sample:
public class MainActivity : Activity, IOnTouchListener
{
Button dragAbleBt;
ImageView imgV1;
int screenWidth = 0;
int screenHeight = 0;
int lastX = 0, lastY = 0;
public bool OnTouch(View v, MotionEvent e)
{
MotionEventActions ea = e.Action;
switch (ea) {
case MotionEventActions.Down:
lastX = (int)e.RawX;
lastY = (int)e.RawY;
break;
case MotionEventActions.Move:
int dx = (int)e.RawX - lastX;
int dy = (int)e.RawY - lastY;
int left = v.Left + dx;
int right = v.Right + dx;
int top = v.Top + dy;
int bottom = v.Bottom + dy;
if (left < 0)
{
left = 0;
right = left + v.Width;
}
if (right > screenWidth)
{
right = screenWidth;
left = right - v.Width;
}
if (top < 0)
{
top = 0;
bottom = top + v.Height;
}
if (bottom > screenHeight)
{
bottom = screenHeight;
top = bottom - v.Height;
}
v.Layout(left, top, right, bottom);
lastX = (int) e.RawX;
lastY = (int) e.RawY;
v.PostInvalidate();
break;
case MotionEventActions.Up:
break;
}
if (v.Id == Resource.Id.imageView1)
{
return true;
}
return false;
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView (Resource.Layout.Main);
//DisplayMetrics dm = Resources.DisplayMetrics;
//screenWidth = dm.WidthPixels;
//screenHeight = dm.HeightPixels;
dragAbleBt = FindViewById<Button>(Resource.Id.button1);
imgV1 = FindViewById<ImageView>(Resource.Id.imageView1);
dragAbleBt.SetOnTouchListener(this);
imgV1.SetOnTouchListener(this);
}
public override void OnWindowFocusChanged(bool hasFocus)
{
base.OnWindowFocusChanged(hasFocus);
if (hasFocus)
{
Rect outRect = new Rect();
this.Window.FindViewById(Window.IdAndroidContent).GetDrawingRect(outRect);
screenWidth = outRect.Width();
screenHeight = outRect.Height();
}
}
}
Please refer the source code to the github
I have two layouts, one LinearLayout and one RelativeLayout. In the LinearLayout I have 10 images. When I click one image, it is added to the RelativeLayout. Similar event is given for all 10 images. In the RelativeLayout, I have set a OnTouchListener to the ImageView added from the LinearLayout. But my problem is, onTouch only works for the ImageView which is recently added but when I try to touch previously added images, it doesn't work. I want to add listener for all images added in the relative layout.
Below is what I have tried so far:
for(int i = 0; i < data.length; i++){
image[i] = new ImageView(getApplicationContext());
try{
// int imgID = getResources().getIdentifier(data[i], null, getPackageName());
image[i].setImageResource(data[i]);
}catch(Exception e){
int imgID = getResources().getIdentifier("nia", "drawable", "package");
image[i].setImageResource(imgID);
}
LinearLayout.LayoutParams LEye = new LinearLayout.LayoutParams(
100 , 70);
LEye.leftMargin=20;
image[i].setLayoutParams(LEye);
shapeImageContainer.addView(image[i]); //shapeImageContainer is the Linear Layout
final int c=i;
image[i].setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
//addContentView( addIcon(), new RelativeLayout.LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT ) );
Toast.makeText(NewProject.this, "Position "+c, Toast.LENGTH_SHORT).show();
rootView.addView(addIcon(c)); //rootView is the Relative layout
}
});
//image[i].setOnTouchListener(MyOnTouchListener);
}
private ImageView addIcon(int c){
item = new ImageView(this);
item.setImageResource(data[c]);
item.setAdjustViewBounds(true);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(100, 60 );
if( mIconIdCounter != 1 ){
params.addRule(RelativeLayout.RIGHT_OF,c-1);
}
item.setLayoutParams( params );
item.setId( mIconIdCounter );
++mIconIdCounter;
item.setOnTouchListener(MyOnTouchListener);
return item;
}
OnTouchListener MyOnTouchListener = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
// scroll.setEnabled(false);
// horizontal.setEnabled(false);
// scroll.setVisibility(View.GONE);
// horizontal.setVisibility(View.GONE);
RelativeLayout.LayoutParams layoutParams2 = (RelativeLayout.LayoutParams) item.getLayoutParams();
switch(event.getActionMasked())
{
case MotionEvent.ACTION_MOVE:
scroll.requestDisallowInterceptTouchEvent(true);
horizontal.requestDisallowInterceptTouchEvent(true);
int x_cord = (int) event.getRawX();
int y_cord = (int) event.getRawY();
//right margin
if (x_cord > windowwidth) {
x_cord = windowwidth-10;
}
// left margin original
if (x_cord <68) {
x_cord = 68;
}
// left margin original
if (y_cord <68) {
y_cord = 68;
}
if (y_cord > windowheight) {
y_cord = windowheight-10;
}
// tv.setText(String.valueOf(y_cord));
layoutParams2.leftMargin = x_cord -60;
layoutParams2.topMargin = y_cord -65;
item.setLayoutParams(layoutParams2);
break;
default:
break;
}
return true;
}
};
But my problem is, onTouch only works for the imageview which is
recently added but when I try to touch previously added images,it
doesn't work.
That's because in the OnTouchListener you use the item field to do your work(which will always point to the last ImageView added as you wrote the code) instead of using the View for which the listener is called. Try something like this:
RelativeLayout.LayoutParams layoutParams2 = (RelativeLayout.LayoutParams) v.getLayoutParams();
// rest of the onTouch callback...
v.setLayoutParams(layoutParams2);
I am trying to shift the position of a image button when on click. I tried the following but it crashes at "rlOut.addView(imgP, p);" I have no issues when running them in onCreate().
public class Delet3Activity extends Activity {
RelativeLayout rlOut;
ImageButton imbBtn;
EditText et1, et2;
ImageView ivB;
ImageButton imgP;
RelativeLayout.LayoutParams p;
RelativeLayout.LayoutParams params;
int mX, mY;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
et1 = (EditText)findViewById(R.id.et1);
et2 = (EditText)findViewById(R.id.et2);
imbBtn = (ImageButton)findViewById(R.id.imgBtn);
rlOut = (RelativeLayout)findViewById(R.id.rlOut);
imgP = (ImageButton)findViewById(R.id.imgP);
ivB = new ImageView(this);
ivB.setBackgroundColor(Color.RED);
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
width = width/2-62;
height = height/2-62;
p = new RelativeLayout.LayoutParams(62, 62);
imbBtn.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
LayoutParams par = (LayoutParams)imbBtn.getLayoutParams();
if(event.getAction()==MotionEvent.ACTION_DOWN)
{
Log.d("ok","down");
mX = (int) event.getX() - imbBtn.getWidth() / 2;
mY = (int) event.getY() - imbBtn.getHeight() / 2;
et1.setText("mX down: "+String.valueOf(mX));
et2.setText("mY down: "+String.valueOf(mY));
}
else if (event.getAction()==MotionEvent.ACTION_UP)
{
Log.d("ok","up");
rlOut.addView(ivB, params);
p.leftMargin=4;
params.leftMargin = 60;
params.topMargin = 20;
rlOut.addView(imgP, p);
Log.d("ok","p");
}
else if (event.getAction()==MotionEvent.ACTION_MOVE)
{
Log.d("ok","move");
mX = (int) event.getX() - imbBtn.getWidth() / 2;
mY = (int) event.getY() - imbBtn.getHeight() / 2;
et1.setText("mX move: "+String.valueOf(mX));
et2.setText("mY move: "+String.valueOf(mY));
}
return false;
}
});
}
}
OnCreate method is the place where you set the setContentView(R.layout.main). I suppose the variable rlOut stands for RelativeLayout which might be in your main layout. Call the above function within the OnCreate methods after you set the contentView and have initialized the variable rlOut using findViewById. Or if the variable rlOut is in some other layout file then you will have to first inflate that layout using layout inflater and then find the view using findViewById method.
Hope this helps.
EDIT
The following code should probably be the solution you are looking for:
imbBtn.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
LayoutParams par = (LayoutParams)imbBtn.getLayoutParams();
if (event.getAction()==MotionEvent.ACTION_MOVE)
{
Log.d("ok","move");
mX = (int) event.getX() - imbBtn.getWidth() / 2;
mY = (int) event.getY() - imbBtn.getHeight() / 2;
par.leftMargin = imbBtn.getLeft() + mX;
par.topMargin = imbBtn.getTop() + mY;
imbBtn.setLayoutParams(par);
et1.setText("mX move: "+String.valueOf(mX));
et2.setText("mY move: "+String.valueOf(mY));
}
return false;
}
});
MotionEvent.ACTION_MOVE is the only event you need to capture. Hope this solution is helpful to you.
I want to drag a view. Until now i tried it with a LinearLayout and margins and with a AbsoluteLayout.
AbsoluteLayout example:
button.Touch = (clickedView, motionEvent) =>
{
Button b = (Button)clickedView;
if (motionEvent.Action == MotionEventActions.Move)
{
AbsoluteLayout.LayoutParams layoutParams = new AbsoluteLayout.LayoutParams(100, 35, (int)motionEvent.GetX(), (int)motionEvent.GetY());
b.LayoutParameters = layoutParams;
}
return true;
};
In every case I tried I got a curios behaviour. Here's why. The view i'm dragging follows my finger but jumps always between two positions. One postition hits my finger the other is somewhere to my fingers left-top. If I'm just writing my current position into a textview (without moving the view) the coordinates behave as expected. But if i'm also moving the view they are jumping again.
How can i avoid this?
EDIT: I used sounds comment on my question to implement a working draging for monodroid (it is done for Java/Android SDK in the linked site). Maybe others are interested in doing that some day, so here's my solution:
[Activity(Label = "Draging", MainLauncher = true, Icon = "#drawable/icon")]
public class Activity1 : Activity
{
private View selectedItem = null;
private int offset_x = 0;
private int offset_y = 0;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Main);
ViewGroup vg = (ViewGroup)FindViewById(Resource.Id.vg);
vg.Touch = (element, motionEvent) =>
{
switch (motionEvent.Action)
{
case MotionEventActions.Move:
int x = (int)motionEvent.GetX() - offset_x;
int y = (int)motionEvent.GetY() - offset_y;
int w = WindowManager.DefaultDisplay.Width - 100;
int h = WindowManager.DefaultDisplay.Height - 100;
if (x > w)
x = w;
if (y > h)
y = h;
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
new ViewGroup.MarginLayoutParams(
LinearLayout.LayoutParams.WrapContent,
LinearLayout.LayoutParams.WrapContent));
lp.SetMargins(x, y, 0, 0);
selectedItem.LayoutParameters = lp;
break;
default:
break;
}
return true;
};
ImageView img = FindViewById<ImageView>(Resource.Id.img);
img.Touch = (element, motionEvent) =>
{
switch (motionEvent.Action)
{
case MotionEventActions.Down:
offset_x = (int)motionEvent.GetX();
offset_y = (int)motionEvent.GetY();
selectedItem = element;
break;
default:
break;
}
return false;
};
}
}