I have a custom ImageView and a Button, clicking the Button and moving up and down resizes the ImageView but it does not run smoothly.
I created a separate thread to smoothen the user movement but apparently it can't make any GUI changes.. I tried to find a way to use Animation but i don't see a way to continuously update the target height.
Working code
Button onTouchListener:
// resize button start location
private PointF startResize = new PointF();
ImageView resize = (ImageView) findViewById( R.id.resize );
resize.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
// save first touch location
startResize.set( boardImage.getHeight(), event.getY() );
break;
case MotionEvent.ACTION_MOVE:
// calculate horizontal move distance
int movedDistance = Math.round(event.getY() - startResize.y);
if ( Math.abs( movedDistance ) > 4 ) {
// set new height
boardImage.setHeight( movedDistance + (int)startResize.x );
}
break;
}
return true; // indicate event was handled
}
});
Custom ImageView
setHeight:
// set height and revalidate
public void setHeight( int newHeight ){
height = newHeight;
// rescale image
setImageMatrix( checkMatrix() );
requestLayout();
}
onMeasure:
#Override
public void onMeasure( int widthMeasureSpec, int heightMeasureSpec ) {
setMeasuredDimension( width, height );
}
EDIT better explanation
Touching the red encircled Button and dragging it up/down resizes the ImageView above it to any given size. see images below.
I tried to use an Animation but i have to cancel it and set a new one with every tiny little movement made witch results in creating 20/30 new Animations every second..
(source: eightytwo.axc.nl)
(source: eightytwo.axc.nl)
Related
I use Android studio and I have this image with a transparent background. Whenever i click on it it'll bring me to another Activity. But even when I click on the transparent part of the image it'll bring me to the other Activity.
Is it possible to make the nontransparent part clickable (or touchable) and the transparent part unclickable?
Yes this is possible but it becomes much more difficult than just adding an OnClickListener.
The trick is to use a Touch listener instead of click and on either a DOWN or UP event take the position and then either use some simple maths to work out whether it was a transparent area (if the design is a simple one) or, do some more complicated stuff to work out your pixel values at the centre.
new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
If (event.getAction() == MotionEvent.ACTION_DOWN) {
final int x = (int) event.getX();
final int y = (int) event.getY();
//now map the coords we got to the
//bitmap (because of scaling)
ImageView imageView = ((ImageView)v);
Bitmap bitmap =((BitmapDrawable)imageView.getDrawable()).getBitmap();
int pixel = bitmap.getPixel(x,y);
//now check alpha for transparency
int alpha = Color.alpha(pixel);
If (alpha != 0) {
//do whatever you would have done for your click event here
}
}
return true; //we've handled the event
}
}
I currently have Views lined up horizontally in a ViewPager and can cycle through them with a PagerAdapter. Currently, to perform the action that I would like to do on swipe, I have to do a double-tap on the View's page. I could post code, but it's somewhat difficult to extract the necessary pieces...
What I would like is the ability to swipe vertically on these views, have them translate vertically with swipe and fade-out, and then perform an action when they reach a certain distance away from the edge of the device.
To get an idea of what I am thinking, in the Gallery app you can pinch an opened photo to zoom-out and open a horizontal filmstrip view. From there you can swipe up (or down) on a photo/video to delete it. For those who do not have the same Gallery app, it's exactly like closing applications on iOS.
I've tried scanning though the source code for the Gallery app, but no luck finding the correct Activity.
view.setOnTouchListener(new View.OnTouchListener(){
public boolean onTouch(View v, MotionEvent motion) {
float y = motion.getY();
/* NOTE: the following line might need to be in runOnUiThread() */
view.animate().alpha(1-Math.abs(y-height/2)/(height/2)).setDuration(50).start();
return true; //false if you want to pass this event on to other listeners
}
});
The explanation for using 1-Math.abs(y-height/2)/(height/2) is that I want alpha to be 1 when I am in the center, and alpha to be 0 when it is at the top or bottom. You have to determine yourself how you obtain the height value, or if you want to use a different method to calculate alpha. If you want to get the touch position relative to the screen instead of the position relative to the view, use getRawY().
Additionally, it may be useful for you to know that to see if the MotionEvent is a press, drag, or release event, use
motion.getAction() == with MotionEvent.ACTION_UP, MotionEvent.ACTION_MOVE, and MotionEvent.ACTION_DOWN, respectively.
I ended up getting this working more-or-less by cloning the well-written Android-SwipeToDismiss library and just replacing the ListView code with a ViewPager.
The finished product looked like this.
Check the below code, this may helpful to you:
public class MainActivity extends Activity implements View.OnTouchListener{
private RelativeLayout baseLayout;
private int previousFingerPosition = 0;
private int baseLayoutPosition = 0;
private int defaultViewHeight;
private boolean isClosing = false;
private boolean isScrollingUp = false;
private boolean isScrollingDown = false;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_popup);
baseLayout = (RelativeLayout) findViewById(R.id.base_popup_layout);//this is the main layout
baseLayout.setOnTouchListener(this);
}
public boolean onTouch(View view, MotionEvent event) {
// Get finger position on screen
final int Y = (int) event.getRawY();
// Switch on motion event type
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
// save default base layout height
defaultViewHeight = baseLayout.getHeight();
// Init finger and view position
previousFingerPosition = Y;
baseLayoutPosition = (int) baseLayout.getY();
break;
case MotionEvent.ACTION_UP:
// If user was doing a scroll up
if(isScrollingUp){
// Reset baselayout position
baseLayout.setY(0);
// We are not in scrolling up mode anymore
isScrollingUp = false;
}
// If user was doing a scroll down
if(isScrollingDown){
// Reset baselayout position
baseLayout.setY(0);
// Reset base layout size
baseLayout.getLayoutParams().height = defaultViewHeight;
baseLayout.requestLayout();
// We are not in scrolling down mode anymore
isScrollingDown = false;
}
break;
case MotionEvent.ACTION_MOVE:
if(!isClosing){
int currentYPosition = (int) baseLayout.getY();
// If we scroll up
if(previousFingerPosition >Y){
// First time android rise an event for "up" move
if(!isScrollingUp){
isScrollingUp = true;
}
// Has user scroll down before -> view is smaller than it's default size -> resize it instead of change it position
if(baseLayout.getHeight()<defaultViewHeight){
baseLayout.getLayoutParams().height = baseLayout.getHeight() - (Y - previousFingerPosition);
baseLayout.requestLayout();
}
else {
// Has user scroll enough to "auto close" popup ?
if ((baseLayoutPosition - currentYPosition) > defaultViewHeight / 4) {
closeUpAndDismissDialog(currentYPosition);
return true;
}
//
}
baseLayout.setY(baseLayout.getY() + (Y - previousFingerPosition));
}
// If we scroll down
else{
// First time android rise an event for "down" move
if(!isScrollingDown){
isScrollingDown = true;
}
// Has user scroll enough to "auto close" popup ?
if (Math.abs(baseLayoutPosition - currentYPosition) > defaultViewHeight / 2)
{
closeDownAndDismissDialog(currentYPosition);
return true;
}
// Change base layout size and position (must change position because view anchor is top left corner)
baseLayout.setY(baseLayout.getY() + (Y - previousFingerPosition));
baseLayout.getLayoutParams().height = baseLayout.getHeight() - (Y - previousFingerPosition);
baseLayout.requestLayout();
}
// Update position
previousFingerPosition = Y;
}
break;
}
return true;
}
}
For animation use the below methods:
public void closeUpAndDismissDialog(int currentPosition){
isClosing = true;
ObjectAnimator positionAnimator = ObjectAnimator.ofFloat(baseLayout, "y", currentPosition, -baseLayout.getHeight());
positionAnimator.setDuration(300);
positionAnimator.addListener(new Animator.AnimatorListener()
{
. . .
#Override
public void onAnimationEnd(Animator animator)
{
finish();
}
. . .
});
positionAnimator.start();
}
public void closeDownAndDismissDialog(int currentPosition){
isClosing = true;
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int screenHeight = size.y;
ObjectAnimator positionAnimator = ObjectAnimator.ofFloat(baseLayout, "y", currentPosition, screenHeight+baseLayout.getHeight());
positionAnimator.setDuration(300);
positionAnimator.addListener(new Animator.AnimatorListener()
{
. . .
#Override
public void onAnimationEnd(Animator animator)
{
finish();
}
. . .
});
positionAnimator.start();
}
I am trying to implement a drag and drop function in Android.I have choosed to implement it using motion event because I think it is easy to understand.I want to make that image I move to remain in the same position and move a duplication. I don't really know how to explain, I want an image on the corner and when I move it the image still remain there but I move another one that is the same, and If I want to move another one from the same position again I move another position.It's like I am trying to get 10 balls from a basket but in this case the basket and the balls are the same image.
My code so far is this:
public class MainActivity extends ActionBarActivity {
private View selected_item = null;
private int offset_x = 0;
private int offset_y = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewGroup vg = (ViewGroup)findViewById(R.id.container);
vg.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getActionMasked())
{
case MotionEvent.ACTION_MOVE:
int x = (int)event.getX() - offset_x;
int y = (int)event.getY() - offset_y;
int w = getWindowManager().getDefaultDisplay().getWidth() - 100;
int h = getWindowManager().getDefaultDisplay().getHeight() - 100;
if(x > w)
x = w;
if(y > h)
y = h;
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
new ViewGroup.MarginLayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
lp.setMargins(x, y, 0, 0);
selected_item.setLayoutParams(lp);
break;
default:
break;
}
return true;
}
});
ImageView img = (ImageView)findViewById(R.id.newwall);
img.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getActionMasked())
{
case MotionEvent.ACTION_DOWN:
offset_x = (int)event.getX();
offset_y = (int)event.getY();
selected_item = v;
break;
default:
break;
}
return false;
}
});
Also, I am using a ViewGroup and I have a touchListener attached on it.When I am pressing the Layout I am getting the image where I press, I would like when I drop the image to remain there if I touch somewhere else on the screen.I have tried to set selected_item back to null when I end the drag but I didn't make it good I guess because I was getting error and app crashes.
Please help me solve these 2 problems.
Here is what I have used for similar purpose
ImageView snapshot = (ImageView)findViewById(R.id.nonFullScreenSnapshot);
vg.buildDrawingCache();
cache = Bitmap.createBitmap(vg.getDrawingCache());
Drawable drawableShot = new BitmapDrawable(getResources(), cache);
snapshot.setImageDrawable(drawableShot);
snapshot.setVisibility(View.VISIBLE);
In this case I have an ImageView already available from my xml layout, which should be at least as big as the image you want to duplicate.
So when the user touches your ViewGroup you should make a duplicate of it and then position it on the new location.
But be careful with the number of duplicates, because you can easily run out of memory and you will get OutOfMemory exception.
Where ever i touch on the screen with respect to x y position i need to add one image on that particular position.
I tried by implementing the ontouch listener but it is adding image to different position and many images are being appeared on many touch i want some thing like where ever i touch that same image should appear there
Please Help i am new to android working on project in a compnay
This is my activity code
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final RelativeLayout rl = (RelativeLayout) findViewById(R.id.wwcontainer);
//Set On TouchListner to the Layout
rl.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.i("OnTouch", "On Touch View Group....");
int x = (int) event.getX();
int y = (int) event.getY();
ImageView imageView = new ImageView(getApplicationContext());
imageView.setImageResource(R.drawable.icon);
imageView.setLayoutParams(new LayoutParams(x,y));
rl.addView(imageView);
return true;
}
});
}
I know about drag and drop i dont want drag and drop instead i need touch any where there image should appear wrt touch position please help me
I had same request and this is what i done and it worked perfectly for me
final RelativeLayout rr = (RelativeLayout) findViewById(R.id.rr);
rr.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
ImageView iv = new ImageView(getApplicationContext());
lp.setMargins(x, y, 0, 0);
iv.setLayoutParams(lp);
iv.setImageDrawable(getResources().getDrawable(
R.drawable.gr1));
((ViewGroup) v).addView(iv);
}
return false;
}
});
This will place image to RelativeLayout where you touched starting coordinates from there. If you want to center new image where you touched RelativeLayout you need to calculate Height and Width of your image and change one line in my code to
lp.setMargins(x - yourImageWidth/2, y - yourImageHeight/2, 0, 0);
You need to use AbsoluteLayout instead of RelativeLayout.
To add image at particular x,y location, you need AbsoluteLayout.
Did you check what int value getX() and getY() returns i think it will return 0,0.
please use event.getRawX() & event.getRawX() for actual touch position. i hope it will help.
I have created my own component which extends RelativeLayout, inside it I have a field of View type which is being positioned with margins:
Blue quad represents my parent view, and a red circle is a child.
Now I want to allow user to move this red circle while moving a finger on a screen.
This is my onTouchEvent() method:
#Override
public boolean onTouchEvent(MotionEvent event) {
int eventAction = event.getAction();
switch (eventAction) {
case MotionEvent.ACTION_DOWN:
// finger touches the screen
break;
case MotionEvent.ACTION_MOVE:
marginX = (int)event.getX();
marginY = (int)event.getY();
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams)pointer.getLayoutParams(); // pointer is this red circle
lp.setMargins(marginX, marginY, 0, 0);
break;
case MotionEvent.ACTION_UP:
// finger leaves the screen
break;
}
return true;
}
But I quickly found out that it doesn't refresh it's position while user is moving his finger on a screen, but instead it does it only when user releases his finger from the screen. So basically, when I move my finger, circle stays in a same position, but when I stop moving, circle is drawn in new position. I tried using invalidate() method on both, parent and child views, but it didn't help. I assume that it may have something to do with UI thread, but I don't have access to runOnUiThread()' method as it's not anActivity`.
EDIT:
I passed an activity to my class, so that I can use runOnUiThread(). My case: ACTION_MOVE now looks like this:
case MotionEvent.ACTION_MOVE:
marginX = (int)event.getX();
marginY = (int)event.getY();
activity.runOnUiThread(new Runnable() {
public void run() {
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams)pointer.getLayoutParams();
lp.setMargins(marginX, marginY, 0, 0);
pointer.invalidate();
}
});
break;
If it's simple pointer you can draw it on Canvas as Drawable:
#Override
protected void onDraw(Canvas canvas) {
pointer.setBounds(marginX, marginY, marginX + pointerWidth, marginY + pointerHeight);
pointer.draw(canvas);
super.onDraw(canvas);
}
And then call invalidate() on pointer in onTouchEvent() method.
I think you need drag and drop function
Refer http://www.vogella.com/articles/AndroidDragAndDrop/article.html