i have two image views which translates on click.
the animation works properly for one view but for second image view , my animation is not according to coordinates provided.
when i click top image view (img1) it animates properly toward bottom image view (img2) . But when i click the bottom image view, it animates from somewhere down and move towards image view 2 initial position only. though the expected behaviour is, it should animate from its position to top image view (img1) initial position.
My xml is
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:src="#drawable/letter_f"
android:layout_alignParentTop="true"
android:id="#+id/imgview1"
android:background="#drawable/chart"/>
<ImageView android:layout_height="100dp"
android:layout_width="100dp"
android:id="#+id/imgview2"
android:src="#drawable/letter_g"
android:background="#drawable/chart"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
and my java class file is
public class AnimationDemo extends Activity implements OnClickListener
{
private ImageView img1;
private ImageView img2;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
img1 = (ImageView)findViewById(R.id.imgview1);
img2 = (ImageView)findViewById(R.id.imgview2);
img1.setOnClickListener(this);
img2.setOnClickListener(this);
}
#Override
public void onClick(View arg0)
{
int x1,y1; // Coordinates of first image view
int x2,y2; //Coordinates of second image view
ImageView img = (ImageView)arg0;
x1 = img1.getLeft();
y1 = img1.getTop();
x2 = img2.getLeft();
y2 = img2.getTop();
TranslateAnimation slide;
if(arg0 == img1)
{
//translate from img view 1 to img view 2
slide = new TranslateAnimation(Animation.ABSOLUTE,x1,Animation.ABSOLUTE, x2,Animation.ABSOLUTE, y1,Animation.ABSOLUTE,y2 );
}
else
{
// translate from img view 2 to img view 1
slide = new TranslateAnimation(Animation.ABSOLUTE,x2,Animation.ABSOLUTE, x1,Animation.ABSOLUTE, y2,Animation.ABSOLUTE,y1);
}
slide.setDuration(1000);
slide.setFillAfter(true);
img.startAnimation(slide);
}
}
Your troubles are due to your locations. I believe when animations are moved with absolute pixels it is relative to itself. So on your second animation you were in essence moving it from x2=220 to x1=0, and y2=419 to y1=0. So it was moving from (currentX+220, currentY+419) to (currentX +0, currentY +0) which = itself
To solve this instance simply negate and switch the values of the second slide declaration like so:
TranslateAnimation slide;
if(arg0 == img1)
{
//translate from img view 1 to img view 2
slide = new TranslateAnimation(Animation.ABSOLUTE,x1,Animation.ABSOLUTE, x2,Animation.ABSOLUTE, y1,Animation.ABSOLUTE,y2 );
}
else
{
// translate from img view 2 to img view 1
// slide = new TranslateAnimation(Animation.ABSOLUTE,x2,Animation.ABSOLUTE, x1,Animation.ABSOLUTE,y2,Animation.ABSOLUTE,y1);
slide = new TranslateAnimation(Animation.ABSOLUTE,0,Animation.ABSOLUTE, (-x2),Animation.ABSOLUTE,0,Animation.ABSOLUTE, (-y2));
}
This only happens because your top left sprite is at 0,0 though. You have to seriously rethink how you're moving your sprites around. Just remember, the TranslateAnimation moves them relative to their current positions, basically setting the sprites original location to (0,0).
Could be wrong, but hope it helps. It worked for me...
Sorry it took so long to get back to you, I lost your post and couldn't find it again for some reason. Glad you had commented earlier!
Related
In code - after first part of animation pivot of view is changing and...view position too!(it is strange behavior)
Here's code(stipulation - one ValueAnimator):
ValueAnimator animator = ValueAnimator.ofFloat(0,180);
float firstAnimLineX = ((47.5f * Resources.getSystem().getDisplayMetrics().density));
float firstAnimLineY = ((2.5f * Resources.getSystem().getDisplayMetrics().density));
float secondAnimLineX = ((47.5f * Resources.getSystem().getDisplayMetrics().density));
float secondAnimLineY = ((47.5f * Resources.getSystem().getDisplayMetrics().density));
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
view.setPivotX((Float) animator.getAnimatedValue()>180/2?firstAnimLineX : secondAnimLineX);
view.setPivotY((Float) animator.getAnimatedValue()>180/2?firstAnimLineY : secondAnimLineY);
view.setRotation((Float) animator.getAnimatedValue());
}
});
XML file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="50dp"
android:layout_height="50dp"
android:id="#+id/frameLayout">
<ImageView
android:layout_width="50dp"
android:layout_height="5dp"
android:layout_gravity="center_horizontal"
android:id="#+id/line"
/>
</FrameLayout>
</RelativeLayout>
And here is what i want to do(left part; right part - it's what realy happens)(yellow point - pivot):
I watched source code of setPivotX but it doesn't says me anything.
Maybe i should call someone of invalidate-methods of view?
I recreated this code and ran it on my Android phone. It gives the exact animation you are looking for.
I created an Image to match your 'match-stick' image.
I made it 400 px wide by 40 high for an example.
I gave it the id: 'bar'
ImageView bar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bar = findViewById(R.id.bar);
bar.getLayoutParams().width = 400; // I set the dimensions here.
bar.getLayoutParams().height = 40; // I set the dimensions here.
bar.setX(0); bar.setY(0); // Then I positioned it in upper left corner.
bar.setPivotX(380); // I set the pivot a little inside the image so that it looks kinda like it is pivoting on a nail.
bar.setPivotY(20);
bar.animate().rotation(-90).setDuration(2000); // Here it animates from your first image above, to your second image in 2 seconds.
// Here I used a postDelay to allow the first animation to finish its' 2 seconds 'before' calling the second animation. No need for an animate() - listener now.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
bar.setY(360); // This re-positions the original image to the
// location where the animation ended.
bar.setRotation(90); // Because the original image was horizontal, this turns it vertical.
// Now we finish the animation to your 3rd image above.
bar.animate().rotation(0).setDuration(2000);
}
},2100);
}
so all I want to do is to touch on a certain part of the screen where an invisible view is hidden.
After that touch the view should fade In.
The Problem: The Listener isn't triggered whe I touch the view.
Things I've tried: view.setImageAlpha(0), view.setAlpha(0), view.setVisibility(View.INVISIBLE)
When I set alpha=1 the listener works fine.
Thanks in advance.
Edit:
Thanks to #Viswanath L for the great solution which he mentioned in his post as second workaround.
I just wanted to give a little code example for that in case someone doesn't know how this works:
What I want: I want to touch the right corner of the screen and at this spot, a view(myView) should fade in.
fadeInListener = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
System.out.println("TRIGGERED");
//The screen size here is 1080x1920(vertical)
if (event.getRawX() > 800 && event.getRawY() > 1640) {
final AlphaAnimation fadeIn = new AlphaAnimation(0, 1);
fadeIn.setDuration(500);
fadeIn.setFillAfter(true);
myView.startAnimation(fadeIn);
}
}
return false;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
layout.setOnTouchListener(fadeInListener);
}
The layout is:
this.layout = (RelativeLayout) findViewById(R.id.layout);
And myView should be placed in the right corner and what's very important:
myView.setVisibility(View.Gone);
Hope this helps.
INVISBLE means you are trying to add a listener to a view which is not there. You can add the listener to a visible view only.
WORKAROUND
1) Try to make a dummy view which is visible but having the same color as background.
2) Try to set the listener for parent and check the position (whether the position does
belongs to INVISIBLE view).
onTouchListener does not trigger for an invisible View. You can make 2 exactly the same views one under another the one below having the map. It will be visible and so it can be touched but it will be obscured by the view above like they do here: http://blahti.wordpress.com/2012/06/26/images-with-clickable-areas/
Try this in your xml:
<View
android:id="#+id/my_inv_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/blue"
/>
<View
android:id="#+id/my_touch_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
And set up the click listener like this:
final View mTouchView = findViewById(R.id.my_touch_view);
final View mInvView = findViewById(R.id.my_inv_view);
mInvView.setVisibility(View.INVISIBLE);
mTouchView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mInvView.setVisibility(View.VISIBLE);
}
});
I have 3 VerticalViewPagers next to each other. Each view pager contains only images. Here's example:
when user clicks on the image, I need to make an EditText. The EditText has to be on an exact spot for each image. So I need to get the position of the image, add some constant and make there a EditText. How to do this?
Note: I tried getLocationOnScreen, for the leftmost image, i got [0,50] back and when I set margin top = 50 and left = 0 for the EditText, it was above the image.
Inflating the items:
public Object instantiateItem(ViewGroup collection, final int position) {
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View rootView = layoutInflater.inflate(R.layout.item_layout, null);
final ImageView imageView = (ImageView) rootView.findViewById(R.id.item);
final RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
collection.addView(rootView, 0);
rootView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int[] pos = new int[2];
imageView.getLocationOnScreen(pos);
params.leftMargin = coordinates.get(0).first;
params.topMargin = coordinates.get(0).second;
EditText editText = new EditText(context);
editText.setLayoutParams(params);
((RelativeLayout) rootView).addView(editText);
}
}
});
return rootView;
item_layout.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/item_relative_layout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/item"
android:contentDescription="#string/imageContent" />
</RelativeLayout>
You must also take taskbar height into calculation, since the getLocationOnScreen is the location when the layout is below the taskbar. When positioning an object on a screen, the top left corner of the applicationĀ“s layout is [0,0], but it is not the [0,0] point of the whole screen, because the application layout starts below the taskbar. The point [0,0] in the getLocationOnScreen lays in the top left corner of the whole screen so you will get the coordinates slightly moved by the taskbar height.
So when positioning your EditText, just add the taskbar height to the y-coordinate and you should be good.
So, I have a Layout that contains a Button and an ImageView. When you press the button the ImageView should slide out from the button like I just pulled down a rolldown curtain (bushing other views below it down). Basically what the image below show. When you press the button again the ImageView should, unlike the gif, smoothly animates up again.
.
Using this SO question I've managed to animate the height from 0 to full size but in the wrong direction. I set the scaleType to "Matrix" and the default behaviour when setting the height is to show the part from the top down to [height].
For the animation I'll need the opposite. So if I would set the height to 50dp it would show the bottom 50dp. Then I can move the ImageView down at the same time it's being revealed, thus giving the rolldown curtain effect.
I've looked throught all the different layout and view options and found nothing that seems to do this. So I'm guessing I need to specify the transformation matrix. I looked through the android.graphics.Matrix class but it's a little but too complicated for me. I simply have no idea how to use it.
If there is another, easier, way to do this then that would be fantastic but if not then I really need help with the matrix.
I'm also including the code here:
The Rolldown View XML
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/sliding_accordion"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="#drawable/acc_image"
android:contentDescription="#string/accord"
android:scaleType="matrix"
android:layout_below="#+id/acc_button"
android:layout_marginTop="-10dp"
android:layout_centerHorizontal="true"/>
<Button
android:id="#+id/acc_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
The implementation in code.
(Note, the MyCustomAnimation class is a copy-paste version of the class found here)
//Called from all constructors
private void create()
{
final Context context = getContext();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
RelativeLayout layout = (RelativeLayout) inflater.inflate(R.layout.widget_accordion, this, false);
final Button theButton = (Button) layout.findViewById(R.id.topic_button);
final ImageView accordionView = (ImageView) layout.findViewById(R.id.sliding_accordion);
accordionView.setVisibility(INVISIBLE);
theButton.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
if (accordionView.getVisibility() == View.VISIBLE)
{
MyCustomAnimation a = new MyCustomAnimation(accordionView, 1000, MyCustomAnimation.COLLAPSE);
height = a.getHeight();
accordionView.startAnimation(a);
}
else
{
MyCustomAnimation a = new MyCustomAnimation(accordionView, 1000, MyCustomAnimation.EXPAND);
a.setHeight(height);
accordionView.startAnimation(a);
}
}
});
this.addView(layout);
}
This took a long time perfect. But I managed to do it after a lot of experimenting.
I animate the margins of the drawer but because of the unexpected behavior of negative margins the button that opens the drawer can not be positioned on top.
When the drawer is closed the XML looks like so:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/accordion"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.animationtest.drawer.Drawer
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/topic_drawer"
android:layout_centerHorizontal="true"
android:layout_marginTop="0dp"
android:visibility="invisible"/>
<com.animationtest.drawer.Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/topic_btn"
android:layout_marginTop="58dp"/>
</RelativeLayout>
Then when the button is pressed the top_margin of the drawer is increased until it has come to whatever position is needed (in this case drawerHeight - someOffset).
I used android.view.animation.Animation to animate the widget my applyTransformation function looks something like this (Note that mLayoutParams are the drawer params):
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
int valueDifference = Math.abs(startValue - endValue);
float valueChange = interpolatedTime * valueDifference;
if(currentState.equals(State.COLLAPSED)) {
// is closed and I want to open it
mLayoutParams.topMargin = Math.round(interpolatedTime * valueDifference);
}
else {
// is opened and I want to close it
mLayoutParams.topMargin = valueDifference - Math.round(interpolatedTime * valueDifference);
}
drawerView.requestLayout(); //this is my drawer
}
Finally, to hide the top of the drawer as it moves, I overrode my DrawerView's dispatchDraw method to looks like so:
#Override
protected void dispatchDraw(Canvas canvas) {
float height = getHeight();
float top = height - ((LayoutParams) getLayoutParams()).topMargin;
Path path = new Path();
RectF rectF = new RectF(0.0f, top, getWidth(), height);
path.addRoundRect(rectF, 0.0f, 0.0f, Path.Direction.CW);
canvas.clipPath(path);
super.dispatchDraw(canvas);
}
One final note:
Because of the Button's position one would need to set the widgets margin as a negative number for it to align correctly in a list or layout. In this case it would have to be -58dp.
I am creating an Activity with two ImageViews.
The first ImageView occupies a part of the screen on startup and I want to show the other ImageView, whose content is a crop around the region where I touch the first Image and on TOP of it.
Class:
public class DetectEyesActivity extends Activity implements OnTouchListener {
private ImageView imgView;
private Bitmap imgBitmap;
private ImageView touchView2;
private Bitmap temp;
#Override
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.detecteyeslayout);
Intent intent = this.getIntent();
byte[] image = intent.getByteArrayExtra("Image");
imgView = (ImageView) findViewById(R.id.detectImageView1);
touchView2 = (ImageView) findViewById(R.id.detectImageView2);
imgBitmap = BitmapFactory.decodeByteArray(image, 0, image.length);
imgView.setImageBitmap(imgBitmap);
temp = Bitmap.createBitmap(imgBitmap, 200, 200, 200, 200);
//touchView2.setImageBitmap(temp);
imgView.setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
int y = (int)event.getY();
int x = (int)event.getX();
temp = Bitmap.createBitmap(imgBitmap, 200,200, 200, 200);
touchView2.setImageBitmap(temp);
touchView2.setVisibility(0);
touchView2.bringToFront();
touchView2.layout(x-200, y-200, x-30, y-30);
return true;
}
}
Layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
android:id="#+id/detectImageView1"
android:layout_width="400dp"
android:layout_height="400dp" />
<ImageView
android:id="#+id/detectImageView2"
android:layout_width="100dp"
android:layout_height="100dp"
android:visibility="gone" />
</LinearLayout>
But when I call
touchView2.setImageBitmap(temp);
Inside onTouch() the view is drawn below the initial image on the layout. But if I call it inside onCreate() it is drawn on top of the initial image?
Why does this happens, and how I can I solve this problem?
As I understand your question, you want one of your images overlayed on the other. LinearLayouts display their children in either a horizontal or vertical line. This is not a good ViewGroup to use for your case, as it does not allow multiple children to occupy the same space. I'd try either a Relative or Frame Layout.
Also, you have the second image's visibility set to gone initially, so it's not that the first image is being drawn over it, but that the second image just isn't being drawn at all until you call setVisibility in your onTouch.