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;
};
}
}
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.
I am working on a project where I have a view, which, once clicked, instantiates a class, passing the view to the constructor, which creates 4 anchor points on to the view. This is done using the following:
customView = new CustomView(MainActivity.this, viewCounter,
customView.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
Resizer resizer = new Resizer(MainActivity.this, MainActivity.this, container, customView, lblStatus);
}
});
The resizer class is as follows:
public Resizer(Context context, AppCompatActivity activity, ViewGroup container, ViewGroup viewToBeResized, TextView lblStatus)
{
this.context = context;
this.activity = activity;
this.container = container;
this.viewToBeResized = viewToBeResized;
this.lblStatus = lblStatus;
createAnchorPoints();
}
private void createAnchorPoints()
{
Drawable circle = ContextCompat.getDrawable(context, R.drawable.anchor);
int circleSize = dpToPx(CIRCLE_SIZE_DP);
Anchor topLeftAnchor = new Anchor(context, viewToBeResized, Anchor.ResizeMode.TOP_LEFT, lblStatus);
topLeftAnchor.setImageDrawable(circle);
RelativeLayout.LayoutParams topLeftParms = new RelativeLayout.LayoutParams(circleSize, circleSize);
topLeftParms.addRule(RelativeLayout.ALIGN_PARENT_START, viewToBeResized.getId());
topLeftParms.addRule(RelativeLayout.ALIGN_PARENT_TOP, viewToBeResized.getId());
viewToBeResized.addView(topLeftAnchor, topLeftParms);
Anchor topRightAnchor = new Anchor(context, viewToBeResized, Anchor.ResizeMode.TOP_RIGHT, lblStatus);
topRightAnchor.setImageDrawable(circle);
RelativeLayout.LayoutParams topRightParms = new RelativeLayout.LayoutParams(circleSize, circleSize);
topRightParms.addRule(RelativeLayout.ALIGN_PARENT_END, viewToBeResized.getId());
topRightParms.addRule(RelativeLayout.ALIGN_PARENT_TOP, viewToBeResized.getId());
viewToBeResized.addView(topRightAnchor, topRightParms);
Anchor bottomLeftAnchor = new Anchor(context, viewToBeResized, Anchor.ResizeMode.BOTTOM_RIGHT, lblStatus);
bottomLeftAnchor.setImageDrawable(circle);
RelativeLayout.LayoutParams bottomLeftParms = new RelativeLayout.LayoutParams(circleSize, circleSize);
bottomLeftParms.addRule(RelativeLayout.ALIGN_PARENT_START, viewToBeResized.getId());
bottomLeftParms.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, viewToBeResized.getId());
viewToBeResized.addView(bottomLeftAnchor, bottomLeftParms);
Anchor bottomRightAnchor = new Anchor(context, viewToBeResized, Anchor.ResizeMode.BOTTOM_RIGHT, lblStatus);
bottomRightAnchor.setImageDrawable(circle);
RelativeLayout.LayoutParams bottomRightParms = new RelativeLayout.LayoutParams(circleSize, circleSize);
bottomRightParms.addRule(RelativeLayout.ALIGN_PARENT_END, viewToBeResized.getId());
bottomRightParms.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, viewToBeResized.getId());
viewToBeResized.addView(bottomRightAnchor, bottomRightParms);
}
In the anchor class that gets created at each corner, a touch listener is used. What I am trying to do is as the user drags the anchor view, the main view, that is passed into the anchor, will resize in the direction the user dragged.
Below is my touch listener
public class AnchorTouchListener implements View.OnTouchListener
{
private int _xDelta;
private int _yDelta;
private View viewToResize;
private TextView lblStatus;
private Anchor.ResizeMode resizeMode;
public AnchorTouchListener(View viewToResize, TextView lblStatus, Anchor.ResizeMode resizeMode)
{
this.viewToResize = viewToResize;
this.lblStatus = lblStatus;
this.resizeMode = resizeMode;
}
#Override
public boolean onTouch(View view, MotionEvent event)
{
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
Log.d("Anchor", "Updating X & Y");
int diff = 0;
switch (event.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
lblStatus.setText("Moving down");
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = Y - lParams.topMargin;
break;
case MotionEvent.ACTION_UP:
lblStatus.setText("Drag finished");
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
lblStatus.setText("Moving around");
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
layoutParams.leftMargin = X - _xDelta;
layoutParams.topMargin = Y - _yDelta;
layoutParams.rightMargin = _xDelta - X;
layoutParams.bottomMargin = _yDelta - Y;
view.setLayoutParams(layoutParams);
//viewToResize.animate().scaleX(0.6f);
if (resizeMode == Anchor.ResizeMode.BOTTOM_RIGHT)
{
diff = diff - X - _xDelta;
Log.d("Anchor Touch", "Diff: " + diff);
if (diff > 0)
{
((RelativeLayout.LayoutParams) viewToResize.getLayoutParams()).width = viewToResize.getLayoutParams().width + Math.abs(diff);
}
else
{
((RelativeLayout.LayoutParams)viewToResize.getLayoutParams()).width = viewToResize.getLayoutParams().width - Math.abs(diff);
}
}
break;
}
return true;
}
}
It is kind of working, except its not moving smoothly with the anchor, the view being resized seems to grow quicker than what is being dragged and is very erratic at how it resize and shrinks.
Is there a better way for doing what I am trying to achieve or can anyone see what I might be doing wrong.
UPDATE
Added video to show what I am trying to achieve and what the problem is.
Since the anchors are positioned with a RelativeLayout, there is no need to write code to move the anchors. Simply resize the grey box and the anchors will be positioned correctly upon layout. The size of the grey box can be determined by capturing initial conditions of the pointer placement and the initial size of the box to achieve the following.
I have only implemented the bottom right anchor and I have taken some liberties with your implementation, but the concept is still valid for your code and the other anchor points.
AnchorTouchListener.java
public class AnchorTouchListener implements View.OnTouchListener {
private int _xDelta;
private int _yDelta;
private View viewToResize;
private TextView lblStatus;
// private Anchor.ResizeMode resizeMode;
public AnchorTouchListener(View viewToResize, TextView lblStatus/*, Anchor.ResizeMode resizeMode*/) {
this.viewToResize = viewToResize;
this.lblStatus = lblStatus;
// this.resizeMode = resizeMode;
}
private int initialHeight;
private int initialWidth;
private int initialX;
private int initialY;
#Override
public boolean onTouch(View view, MotionEvent event) {
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
Log.d("Anchor", "Updating X & Y");
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
lblStatus.setText("Action down");
// Capture initial conditions of the view to resize.
initialHeight = viewToResize.getHeight();
initialWidth = viewToResize.getWidth();
// Capture initial touch point.
initialX = X;
initialY = Y;
break;
case MotionEvent.ACTION_UP:
lblStatus.setText("Drag finished");
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
lblStatus.setText("Moving around");
RelativeLayout.LayoutParams lp =
(RelativeLayout.LayoutParams) viewToResize.getLayoutParams();
// Compute how far we have moved in the X/Y directions.
_xDelta = X - initialX;
_yDelta = Y - initialY;
// Adjust the size of the targeted view. Note that we don't have to position
// the resize handle since it will be positioned correctly due to the layout.
lp.width = initialWidth + _xDelta;
lp.height = initialHeight + _yDelta;
viewToResize.setLayoutParams(lp);
break;
}
return true;
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Drawable circle = ContextCompat.getDrawable(this, R.drawable.circle);
ImageView imageView = new ImageView(this);
imageView.setImageDrawable(circle);
int circleSize = dpToPx(CIRCLE_SIZE_DP);
RelativeLayout viewToBeResized = findViewById(R.id.customView);
ImageView bottomRightAnchor = new ImageView(this);
bottomRightAnchor.setImageDrawable(circle);
RelativeLayout.LayoutParams bottomRightParms =
new RelativeLayout.LayoutParams(circleSize, circleSize);
bottomRightParms.addRule(RelativeLayout.ALIGN_PARENT_END, viewToBeResized.getId());
bottomRightParms.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, viewToBeResized.getId());
viewToBeResized.addView(bottomRightAnchor, bottomRightParms);
bottomRightAnchor.setOnTouchListener(
new AnchorTouchListener(viewToBeResized, ((TextView) findViewById(R.id.status))));
}
private int dpToPx(int dp) {
return (int) (dp * getResources().getDisplayMetrics().density);
}
private static final int CIRCLE_SIZE_DP = 20;
}
activity_main.xml
<RelativeLayout
android:id="#+id/relativeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<RelativeLayout
android:id="#+id/customView"
android:layout_width="150dp"
android:layout_height="150dp"
android:background="#android:color/holo_green_light" />
<TextView
android:id="#+id/status"
android:layout_width="wrap_content"
tools:text="Status"
android:layout_height="wrap_content" />
</RelativeLayout>
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
In above line of code in your AnchorTouchListener class you are getting the params of the view endpoint you created earlier.
Getting the correct LayourParams should solve the problem.
(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'm new to building apps on Android. I do have Java and android studio working experience, and build basic android apps but the project I'm working on now is a little bit complicated.
I want to move a image inside a imageview corresponding to touch pointer, in other words to direction of touch but inside a specific area(circular).
Just like in android app pou i.e. pou eyes move corresponding to touch pointer.
I started with below code:
public class TouchActivity extends Activity {
private ViewGroup mainLayout;
private ImageView image;
private int xDelta;
private int yDelta;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_touch);
mainLayout = (RelativeLayout) findViewById(R.id.main);
image = (ImageView) findViewById(R.id.image);
image.setOnTouchListener(onTouchListener());
}
private OnTouchListener onTouchListener() {
return new OnTouchListener() {
#SuppressLint("ClickableViewAccessibility")
#Override
public boolean onTouch(View view, 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)
view.getLayoutParams();
xDelta = x - lParams.leftMargin;
yDelta = y - lParams.topMargin;
break;
case MotionEvent.ACTION_UP:
Toast.makeText(TouchActivity.this,
"thanks for new location!", Toast.LENGTH_SHORT)
.show();
break;
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view
.getLayoutParams();
layoutParams.leftMargin = x - xDelta;
layoutParams.topMargin = y - yDelta;
layoutParams.rightMargin = 0;
layoutParams.bottomMargin = 0;
view.setLayoutParams(layoutParams);
break;
}
mainLayout.invalidate();
return true;
}
};
}
}
... and successfully managed to move an image corresponding to touch pointer but I want to implement something like this:
(eyes are moving according to touch but inside a specific area)
Any ideas?
(by kalu) Move click image inside imageview ajust height or with depends the size of resource(image) and translate x or y direction.
Try This:
// your image view
ImageView mCoverView = findViewById(R.id.imageview);
Glide.with(aActivity).load(cover) //set img url
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(new BitmapImageViewTarget(mCoverView) {
#Override
protected void setResource(Bitmap resource) {
final Bitmap f_res = resource;
// just if you want change for a drawable res
// final Bitmap f_res = BitmapFactory.decodeResource(aActivity.getResources(),R.drawable.ic_ampliada);
//k ajust center but ajust height or with depend the image
mCoverView.setScaleType(ImageView.ScaleType.CENTER_CROP);
mCoverView.setImageBitmap(f_res);
final String dir;
if(f_res.getWidth()>f_res.getHeight())
dir="x";
else
dir="y";
mCoverView.setOnClickListener(new View.OnClickListener() {
// size of move
int value = 25;
double resh=f_res.getHeight();
double resw=f_res.getWidth();
double coverh =mCoverView.getHeight();
double coverw = mCoverView.getWidth();
int xTranslate = 0;
double sacale_w_from_h = coverh / resh * resw;
//k wtotal distancia do centro as bordas (x=0 (centro imagem))
double wtotal = (sacale_w_from_h/2);
int yTranslate = 0;
double sacale_h_from_w = coverw / resw * resh;
//k wtotal distancia do centro as bordas (y=0 (centro imagem))
double htotal = sacale_h_from_w / 2;
#Override
public void onClick(View v) {
if (dir == "x"){
if (xTranslate>wtotal || xTranslate<-wtotal)
value=-value;
xTranslate += value;
}else if(dir == "y"){
if (yTranslate>htotal || yTranslate<-htotal)
value=-value;
yTranslate += value;
}
this.translateImage(xTranslate,yTranslate);
}
private void translateImage(int xTranslate, int yTranslate)
{
Bitmap translateBitmap = Bitmap.createBitmap(f_res.getWidth() + xTranslate, f_res.getHeight() + yTranslate, f_res.getConfig());
Canvas translateCanvas = new Canvas(translateBitmap);
Matrix translateMatrix = new Matrix();
translateMatrix.setTranslate(xTranslate, yTranslate);
Paint paint = new Paint();
translateCanvas.drawBitmap(f_res, translateMatrix, paint);
mCoverView.setImageBitmap(translateBitmap);
}
});
}
#Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
if (glideAnimation == null || !glideAnimation.animate(resource, this)) {
setResource(resource);
}
}
});
//-------------------------------------------------------------------
To understand this question, first read how this method works.
I am trying to implements a drag and drop ListView, it's going alright but have run into
a road block. So I don't have to handled everything, I am intercepting(but returning false) MotionEvents sent to the ListView, letting it handle scrolling and stuff. When I want to start dragging a item, I then return true and handled all the dragging stuff. Everything is working fine except for one thing. The drag(drag and drop) is started when it is determined that a long press as a occurred(in onInterceptTouchEvent). I get the Bitmap for the image that I drag around like so. itemPositition being the index of the item that was selected.
(omitting irrelevant parts)
...
View dragItem = mListView.getChildAt(itemPosition);
dragItem.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(dragItem.getDrawingCache());
mDragImage = new ImageView(mContext);
mDragImage.setImageBitmap(bitmap);
...
The problem is, mDragImage is a solid black like this.
But, if I don't let ListView handle anything. As in, I start the drag on ACTION_DOWN and stop on ACTION_UP, mDragImage looks has expected(but I obviously lose scrolling abilities).
Since the drag is started with a long press, the ListView is given the opportunity to do things before the long press occurs. This is my guess as to why this is happening. When a item is pressed, it is highlighted by the ListView. Somewhere in doing so, it is messing with the bitmap. So when I go to get it, it's in a weird state(all black).
I see two options for fixing this, neither of which I know how to do.
Create a image from scratch.
Handle the highlighting myself(if that is the problem).
Option two seems a better one to me, except that I looked at the documentation and the source code and could not find out how to do so. Here are some things I have done/tried.
I set setOnItemClickListener(...) and
setOnItemSelectedListener(...) with a empty method(highlighting
still happens). (Before anyone suggests it, calling
setOnClickListener results in a runtime error.)
I also looked into trying to get the ListView to make a new item
(for option 2), but could not find a way.
Spent 45ish minutes looking through the source code and
documentation trying to pinpoint where the highlighting was
happening(I never found it).
Any help fixing this would be appreciated.
(EDIT1 START)
So I don't actually know if onLongClickListener is working, I made an error before thinking it was. I am trying to set it up right now, will update when I find out if it does.
(EDIT1 END)
Last minute edit before post. I tried using onLongClickListener just now, and the image is good. I would still like to know if there is another way. How I have to use onLongClickListener to get things working is ugly, but it works. I also spent so much time trying to figure this out, it would be nice to find out the answer. I still want to be able to change/handle the highlight color, the default orangeish color is not pretty. Oh and sorry about the length of the post. I could not think of way of making it shorter, while supplying all the information I thought was needed.
use this code, it's allows operation drug and drop in ListView:
public class DraggableListView extends ListView {
private static final String LOG_TAG = "tasks365";
private static final int END_OF_LIST_POSITION = -2;
private DropListener mDropListener;
private int draggingItemHoverPosition;
private int dragStartPosition; // where was the dragged item originally
private int mUpperBound; // scroll the view when dragging point is moving out of this bound
private int mLowerBound; // scroll the view when dragging point is moving out of this bound
private int touchSlop;
private Dragging dragging;
private GestureDetector longPressDetector;
public DraggableListView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.listViewStyle);
}
public DraggableListView(final Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
longPressDetector = new GestureDetector(getContext(), new SimpleOnGestureListener() {
#Override
public void onLongPress(final MotionEvent e) {
int x = (int) e.getX();
final int y = (int) e.getY();
int itemnum = pointToPosition(x, y);
if (itemnum == AdapterView.INVALID_POSITION) {
return;
}
if (dragging != null) {
dragging.stop();
dragging = null;
}
final View item = getChildAt(itemnum - getFirstVisiblePosition());
item.setPressed(false);
dragging = new Dragging(getContext());
dragging.start(y, ((int) e.getRawY()) - y, item);
draggingItemHoverPosition = itemnum;
dragStartPosition = draggingItemHoverPosition;
int height = getHeight();
mUpperBound = Math.min(y - touchSlop, height / 3);
mLowerBound = Math.max(y + touchSlop, height * 2 / 3);
}
});
setOnItemLongClickListener(new OnItemLongClickListener() {
#SuppressWarnings("unused")
public boolean onItemLongClick(AdapterView<?> paramAdapterView, View paramView, int paramInt, long paramLong) {
// Return true to let AbsListView reset touch mode
// Without this handler, the pressed item will keep highlight.
return true;
}
});
}
/* pointToPosition() doesn't consider invisible views, but we need to, so implement a slightly different version. */
private int myPointToPosition(int x, int y) {
if (y < 0) {
return getFirstVisiblePosition();
}
Rect frame = new Rect();
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
child.getHitRect(frame);
if (frame.contains(x, y)) {
return getFirstVisiblePosition() + i;
}
}
if ((x >= frame.left) && (x < frame.right) && (y >= frame.bottom)) {
return END_OF_LIST_POSITION;
}
return INVALID_POSITION;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
if (longPressDetector.onTouchEvent(ev)) {
return true;
}
if ((dragging == null) || (mDropListener == null)) {
// it is not dragging, or there is no drop listener
return super.onTouchEvent(ev);
}
int action = ev.getAction();
switch (ev.getAction()) {
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
dragging.stop();
dragging = null;
if (mDropListener != null) {
if (draggingItemHoverPosition == END_OF_LIST_POSITION) {
mDropListener.drop(dragStartPosition, getCount() - 1);
} else if (draggingItemHoverPosition != INVALID_POSITION) {
mDropListener.drop(dragStartPosition, draggingItemHoverPosition);
}
}
resetViews();
break;
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
int x = (int) ev.getX();
int y = (int) ev.getY();
dragging.drag(x, y);
int position = dragging.calculateHoverPosition();
if (position != INVALID_POSITION) {
if ((action == MotionEvent.ACTION_DOWN) || (position != draggingItemHoverPosition)) {
draggingItemHoverPosition = position;
doExpansion();
}
scrollList(y);
}
break;
}
return true;
}
private void doExpansion() {
int expanItemViewIndex = draggingItemHoverPosition - getFirstVisiblePosition();
if (draggingItemHoverPosition >= dragStartPosition) {
expanItemViewIndex++;
}
// Log.v(LOG_TAG, "Dragging item hovers over position " + draggingItemHoverPosition + ", expand item at index "
// + expanItemViewIndex);
View draggingItemOriginalView = getChildAt(dragStartPosition - getFirstVisiblePosition());
for (int i = 0;; i++) {
View itemView = getChildAt(i);
if (itemView == null) {
break;
}
ViewGroup.LayoutParams params = itemView.getLayoutParams();
int height = LayoutParams.WRAP_CONTENT;
if (itemView.equals(draggingItemOriginalView)) {
height = 1;
} else if (i == expanItemViewIndex) {
height = itemView.getHeight() + dragging.getDraggingItemHeight();
}
params.height = height;
itemView.setLayoutParams(params);
}
}
/**
* Reset view to original height.
*/
private void resetViews() {
for (int i = 0;; i++) {
View v = getChildAt(i);
if (v == null) {
layoutChildren(); // force children to be recreated where needed
v = getChildAt(i);
if (v == null) {
break;
}
}
ViewGroup.LayoutParams params = v.getLayoutParams();
params.height = LayoutParams.WRAP_CONTENT;
v.setLayoutParams(params);
}
}
private void resetScrollBounds(int y) {
int height = getHeight();
if (y >= height / 3) {
mUpperBound = height / 3;
}
if (y <= height * 2 / 3) {
mLowerBound = height * 2 / 3;
}
}
private void scrollList(int y) {
resetScrollBounds(y);
int height = getHeight();
int speed = 0;
if (y > mLowerBound) {
// scroll the list up a bit
speed = y > (height + mLowerBound) / 2 ? 16 : 4;
} else if (y < mUpperBound) {
// scroll the list down a bit
speed = y < mUpperBound / 2 ? -16 : -4;
}
if (speed != 0) {
int ref = pointToPosition(0, height / 2);
if (ref == AdapterView.INVALID_POSITION) {
//we hit a divider or an invisible view, check somewhere else
ref = pointToPosition(0, height / 2 + getDividerHeight() + 64);
}
View v = getChildAt(ref - getFirstVisiblePosition());
if (v != null) {
int pos = v.getTop();
setSelectionFromTop(ref, pos - speed);
}
}
}
public void setDropListener(DropListener l) {
mDropListener = l;
}
public interface DropListener {
void drop(int from, int to);
}
class Dragging {
private Context context;
private WindowManager windowManager;
private WindowManager.LayoutParams mWindowParams;
private ImageView mDragView;
private Bitmap mDragBitmap;
private int coordOffset;
private int mDragPoint; // at what offset inside the item did the user grab it
private int draggingItemHeight;
private int x;
private int y;
private int lastY;
public Dragging(Context context) {
this.context = context;
windowManager = (WindowManager) context.getSystemService("window");
}
/**
* #param y
* #param offset - the difference in y axis between screen coordinates and coordinates in this view
* #param view - which view is dragged
*/
public void start(int y, int offset, View view) {
this.y = y;
lastY = y;
this.coordOffset = offset;
mDragPoint = y - view.getTop();
draggingItemHeight = view.getHeight();
mDragView = new ImageView(context);
mDragView.setBackgroundResource(android.R.drawable.alert_light_frame);
// Create a copy of the drawing cache so that it does not get recycled
// by the framework when the list tries to clean up memory
view.setDrawingCacheEnabled(true);
mDragBitmap = Bitmap.createBitmap(view.getDrawingCache());
mDragView.setImageBitmap(mDragBitmap);
mWindowParams = new WindowManager.LayoutParams();
mWindowParams.gravity = Gravity.TOP;
mWindowParams.x = 0;
mWindowParams.y = y - mDragPoint + coordOffset;
mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
mWindowParams.format = PixelFormat.TRANSLUCENT;
mWindowParams.windowAnimations = 0;
windowManager.addView(mDragView, mWindowParams);
}
public void drag(int x, int y) {
lastY = this.y;
this.x = x;
this.y = y;
mWindowParams.y = y - mDragPoint + coordOffset;
windowManager.updateViewLayout(mDragView, mWindowParams);
}
public void stop() {
if (mDragView != null) {
windowManager.removeView(mDragView);
mDragView.setImageDrawable(null);
mDragView = null;
}
if (mDragBitmap != null) {
mDragBitmap.recycle();
mDragBitmap = null;
}
}
public int getDraggingItemHeight() {
return draggingItemHeight;
}
public int calculateHoverPosition() {
int adjustedY = (int) (y - mDragPoint + (Math.signum(y - lastY) + 2) * draggingItemHeight / 2);
// Log.v(LOG_TAG, "calculateHoverPosition(): lastY=" + lastY + ", y=" + y + ", adjustedY=" + adjustedY);
int pos = myPointToPosition(0, adjustedY);
if (pos >= 0) {
if (pos >= dragStartPosition) {
pos -= 1;
}
}
return pos;
}
}
}