I have two ImageView(s) set in my layout one on top of the other, say A and B.
I have set the alpha of B to 0 so it's totally faded as I want to control which image is displayed by setting the appropriate alpha to 1 in my code.
Now I also want to rotate the Images by 360 degrees before they fade out and before the new image comes on the screen when I click on the ImageView(s).
I'm using the ViewPropertyAnimator's rotation() and alpha() methods to do this.
This works without any issues when the App is installed and runs for for 1st time.
However, next time when I click on the Images, only the fade-in and fade-out animations work.
The rotation does not work.
Check this code :
boolean isImage1Showing = true;
//onClick() method for the 2 ImageView(s)
public void fadeAndRotate(View view){
if (isImage1Showing){
//Rotate the resource on 1st ImageView by 360 degrees
imageViewA.animate().rotation(360f).setDuration(2000);
imageViewA.animate().alpha(0).setDuration(2000);
//Displaying the other image on to the screen
imageViewB.animate().alpha(1).setDuration(2000);
isImage1Showing = false;
} else {
isImage1Showing = true;
imageViewB.animate().rotation(360f).setDuration(2000);
//Displaying the previous image
imageViewA.animate().alpha(1).setDuration(2000);
//fading out the currently displayed image
imageViewB.animate().alpha(0).setDuration(2000);
}
}
Use the
.rotationBy(float value)
method instead of the
.rotation(float value)
method. In your case it rotates TO 360f but you want it to rotate BY 360f.
So this code should work :
imageViewA.animate().rotationBy(360f).setDuration(2000);
Related
I'm working on an android library to display an image as a fixed background image. To do this, I'm dynamically ajusting the position of the image every 10ms based on the locationOnScreen. I understand that it's an aweful solution, but I'm here to improve this :)
The issue with this is that there is a glitch when the parent scrollable view is scrolling too fast and the image jump while the other view are moving. (click on the gif for the full demo)
As it's a library, I don't want to add complexity when integrating the lib, meaning no scroll listener, theme or no window override etc.
Solution tried:
- changing the loop delay
- using window background is not possible for a library
- no access to activity theme or similar
handler
override fun run() {
fixedBackgroundImageLayout.getLocationOnScreen(locationOnScreen)
fixedBackgroundImagePlugin.update(locationOnScreen)
handler.postDelayed(this, 10)
}
FixedBackgroundImagePlugin#update
override fun update(locationOnScreen: IntArray) {
if (backgroundImageFrameLayout == null) {
return
}
yPosition = parentLocationOnScreen[1] - locationOnScreen[1]
backgroundImageFrameLayout.top = 2 * yPosition - lastYPosition - 10
lastYPosition = yPosition
}
the backgroundImageFrameLayout has the image as a background image.
I've also setup a sample repository to help you dig in if wanted.
I'm open to any advice/lead
Update: Previous code I posted had some interaction issues that, surprisingly, made the code work but pegged the CPU. The following code is substantially like the previous code, but behaves. Although the new code involves a scroll listener that causes the view to redraw itself, it is self-contained. The scroll listener is needed to detect when the view is re-positioned on the screen. When called, the scroll listener simply invalidates the view.
You can do what you need all within the custom view BackgroundImageFrameLayout. Here is a draw() override that will take care of drawing the background of the FrameLayout that holds the image.
Add the following to the init block:
viewTreeObserver.addOnScrollChangedListener {
invalidate()
}
Add the following override method to BackgroundImageFrameLayout:
override fun onDraw(canvas: Canvas) { // draw(canvas) may be better choice.
if (background == null) {
return
}
// Get the location of this view on the screen to compute its top and bottom coordinates.
val location = IntArray(2)
getLocationOnScreen(location)
val imageTop = location[1]
val imageBottom = imageTop + height
// Draw the slice of the image that should be viewable.
canvas.save()
canvas.translate(0f, -imageTop.toFloat())
background?.setBounds(0, imageTop, width, imageBottom)
background?.draw(canvas)
canvas.restore()
}
Remove everything else that tries to manipulate the background - you won't need it.
Here is a demo of the app with the new onDraw():
I think there may be some other issues with the size of the screen vs. the size of the image, but this is the direction that you should go (IMHO.)
I have an ImageView that is rotated using RotateAnimation(). I am writing a test case where I want to test that after a button is clicked this view is rotated. So I thought that I can get the rotation angle before the click and after it to check the difference:
oldRotationDegrees = view.getRotation();
//click that button and wait for 3 seconds
assertTrue(Math.abs(view.getRotation() - oldRotationDegrees) > 0);
However this difference is always 0, because getRotation() always returns 0. I have checked that there is really a rotation visible, so it seems that RotateAnimation() doesn't affect the value returned by getRotation().
So how can I verify that the image has been rotated after the button is pressed?
In case it matters, I am using Robotium for these tests.
Update: I am now testing also with robolectric (unit tests) and the behaviour is (without surprise) the same.
Update 2: This answer https://stackoverflow.com/a/4213493/2160877 explains why this happens.
First of all, I'll let you know that I'm new to Unity and to coding overall (I do know some very basic javascript coding). My question: How can I rotate a 2D object (prefab) 120 degrees on a certain axis (in my case the z-axis, so it rotates like you're looking at a steering wheel) every time I touch on the screen. Right now I have it like this:
function TouchOnScreen ()
{
if (Input.touchCount > 0)
{
var touch = Input.touches[0];
if (touch.position.x < Screen.width/2)
{
transform.rotation = Quaternion.Euler(0,0,120);
Debug.Log("RotateRight");
}
else if (touch.position.x > Screen.width/2)
{
transform.rotation = Quaternion.Euler(0,0,-120);
Debug.Log("RotateLeft");
}
}
}
This code rotates the object whenever I press on a certain side of the screen, but not how I want it to. I want it to rotate so you see the object rotating from A to B, but not (like it is now) in one frame from A to B. Also, this code lets me only rotate one time to each direction.
How can I make it that whenever I press on a certain side of the screen, that it adds or subtracts to/from the previous rotated angle, so I can keep on rotating.
NOTE: Please use javascript, and if you know a simpler code, let me know!
Help is highly appreciated, thanks in advance!
Instead of
transform.rotation = Quaternion.Euler(0,0,-120);
You use:
var lSpeed = 10.0f; // Set this to a value you like
transform.rotation = Quaterion.Lerp ( transform.rotation, Quaternion.Euler(0,0,-120), Time.deltaTime*lSpeed);
I am new to andengine and want to know that how I can switch between two BaseGameActivities. And also when switching from first activity to second, there is no black screen transition in between switching. Is there any possible way to do it.
Please help me out.
A BaseGameActivity can be used as any other Android Activity, too:
Intent intent = new Intent(this, MyOtherBaseGameActivity.class);
startActivity(intent);
So if you want to change from your program to another app (maybe by opening the browser…) you can do that as with any other Android App, too. However if both Activities are part of your own App, there is rarely a case where this is recommendable (It is like starting a second program). Although it is possible to exchange data between the activities as described in this post.
But maybe you are only looking for a way to switch between Views in AndEngine. If that's the case you can switch between Scenes without any transition necessary.
MyOtherScene secondScene = new MyOtherScene();
mEngine.setScene(secondScene);
That way you can switch between what is being displayed, without needing to load every image again.
EDIT:
Since you can't use AndEngine to switch between Activities, nor is a smooth switching between scenes possible. Here a quick example on how to switch between two screens (e.g. menus). In this example the screens are actually 2 different images (as big as the display … maybe some background images). Note: there is no such thing as 'screens' in AndEngine, it is simply a self made class that extends Entity.
Your Screen
public MyScreen extends Entity{
private float firstX;
public MyScreen(Sprite niceBackgroundImage1, Sprite niceBackgroundImage2){
this.attachChild(niceBackgroundImage1); // attach something to the screen, so you can see it (preferably an image that is as big as your camera)
this.attachChild(niceBackgroundImage2);
this.firstY=-1; // this is a variable to remember the first x coordinate touched
}
#Override
public boolean onAreaTouched(TouchEvent sceneTouchEvent, float touchAreaLocalX, float touchAreaLocalY) {
if(sceneTouchEvent.getAction()==TouchEvent.ACTION_DOWN){
this.firstY=touchAreaLocalX; // remember the x, on the first touch
}
if(sceneTouchEvent.getAction()==TouchEvent.ACTION_MOVE){
if(touchAreaLocalX>firstY+20){
// user swiped from left to right (at least 20 pixels)
niceBackgroundImage1.registerEntityModifier(new MoveModifier(3f, 0, niceBackgroundImage1.getWidth(), 0, 0, EaseBounceOut.getInstance()));
// the last line actualy moves the nice..image1 from left to right (in 3 seconds) and lets it bounce a little bit before it is completely out of the screen
return true;
}
}
return false;
}
...
}
Your Activity
private HUD hud; // create a HUD
...
#Override
protected void onCreateResources() {
this.hud = new HUD(); // init the HUD
this.myScreen = new MyScreen(image1, image2) // init the screen
this.hud.attachChild(myScreen); // attach the screen to the hud
mEngine.getCamera().setHud(hud); // attach your HUD to the camera
}
#Override
protected Scene onCreateScene() {
Scene myScene = new Scene();
myScene.registerTouchArea(myScreen); // you have to register the touch area of your Screen Class to the scene.
mEngine.setScene(myScene);
}
And this is how it works:
you create yourself a own screen class that extends Entity. An Entity can be everything visible in AndEngine (like a Sprite, Rectangle or even a whole scene). Put something in your screen class to make it look nice, preferably a big image that fills the whole display. That image will be responsible to register the touch afterwards. If the image is too small and the user misses the image, then no touch will be registered.
In this case I attach the instance of MyScreen to the cameras HUD. That way it will be at a fixed position on the display and it will have a fixed size (just in case you want to make the scene scrollable or zoomable).
Now when the app starts the HUD will be created and attached to the camera and with it your MyScreen class. Then the scene will be created and the screen's area will be registered as touch area to the scene. When a swipe movement on a horizontal axis gets noticed by the screen class, the first image will move outside the screen (in the same direction as the swipe).
But be careful, this is just an example. There is nothing defined on how the touch has to act when the first image was moved outside the screen or how big the screen actually is etc...
I know this is quite a long example, maybe it won't even work the first time and it is definitely not the only way on how switching between different screens can be done. But it shows you how to override the onAreaTouched() method and register the entity modifier to make the image move. Hopefully it will lead you in the right direction, to accomplish what you want to do.
I have to animate a circular count down timer and I'm doing it by animating the background of an ImageView using AnimationDrawable (each image has the according slice of the circle removed). The problem is that the user has the ability to pause this animation, so I have to reload the animation but then a problem appears. I've tried setting the the animation to null, setting the background of the ImageView to null, setting the visibility of the animation, but practically nothing helped, because number of frames remains the same. I have to find a workaround for deleting all frames and adding new ones or to reset the whole animation to the default state.
Step 1 - initializing the animation (starting frame index is 0)
timerView.setBackgroundResource(R.drawable.timer_switch);
timerAnimation = (AnimationDrawable)timerView.getBackground();
System.out.println("Number of frames: " + timerAnimation.getNumberOfFrames());
for (int frameIndex = startingFrameIndex; frameIndex < 60; frameIndex++) {
if (frameIndex < 10) {
uri = "drawable/timer_0000" + frameIndex;
} else {
uri = "drawable/timer_000" + frameIndex;
}
imageResourceId = getResources().getIdentifier(uri, null, getPackageName());
timerAnimation.addFrame(getResources().getDrawable(imageResourceId), timerImageFrameDuration);
}
Step 2 - here's the tricky part where I don't know what to do. Things that I've tried:
timerAnimation.stop();
timerAnimation.setCallback(null);
timerAnimation.setVisibility(true, false);
timerAnimation = null;
Step 3 - after calling step 2 I call step 1 again, but the Sys.out still displays 60 as the current number of frames. (starting index here is set to the last hidden frame when pause button was tapped.)
Any idea is welcomed.
Thanks
This will send the (AnimationDrawable) timerAnimation to the first frame as soon as stop() has been called:
timerAnimation.stop();
timerAnimation.selectDrawable(0);
I had the same problem where stopping the animation would stop on the current frame. I wanted it to behave like iOS, where stopping would go back to the first frame. This solution works for me:
((AnimationDrawable)(someButton.getBackground())).stop();
someButton.setBackgroundDrawable(null);
someButton.setBackgroundResource(R.drawable.animation);
This first stops it (probably not necessary). Then it kills the background animation. Finally, it recreates the background.
Another possible solution would be to have the same image for the first frame and last frame and do the following instead of calling the stop() method.
((AnimationDrawable)(someButton.getBackground())).setOneShot(true);
if anyone does look into this any further. There is also a method called setVisible(boolean visible, boolean restart). However, that did not work for myself.
You can try public boolean setVisible (boolean visible, boolean restart) and it will play the animation once. For example:
animationDrawable.setVisible(false, true);
I would setVisibility(true, true):
timerAnimation.stop();
timerAnimation.setVisibility(true, true);
visible boolean: true if visible, false otherwise
restart boolean:
when visible, true to force the animation to restart from the first frame
android.view.animation.Animation.reset() doesnt work?