View.setClipBounds() does not limit the View animation area? - java

I am currently trying to do a pseudo-circular reveal that will work on Android API levels below Lollipop. So, I have a floating action button (FAB) that I want (when pressed) to move vertically into a RelativeLayout (before clicked it sits outside of the RelativeLayout) and then scale by a certain factor so that it looks like a reveal.
I thought that using .setClipBounds() on the FAB would limit the scale animation in the area of the RelativeLayout but unfortunately the scale animation expands to take over the whole Activity area. This is the code in the click listener of the FAB:
circleFab.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
int cardHeight = relativeCardBuild.getHeight();
int cardWidth = relativeCardBuild.getWidth();
Log.i("RELAT H", "" + cardHeight);
Log.i("RELAT W", "" + cardWidth);
circleFab
.animate()
.translationY(-(cardHeight / 2))
.setInterpolator(new AccelerateDecelerateInterpolator())
.setDuration(200).start();
tickFab.animate().alpha(0.0f).setDuration(200).start();
circleFab.setClipBounds(new Rect(relativeCardBuild.getLeft(),
relativeCardBuild.getTop(), relativeCardBuild
.getRight(), relativeCardBuild.getBottom()));
Log.i("left ", relativeCardBuild.getLeft()+"");
Log.i("top ", relativeCardBuild.getTop()+"");
Log.i("right ", relativeCardBuild.getRight()+"");
Log.i("bottom ", relativeCardBuild.getBottom()+"");
circleFab.animate().setStartDelay(100).scaleX(20.0f)
.scaleY(20.0f).setDuration(500).start();
}
});
The logged values of the relativeCardBuild's left, top, right and bottom points are correct so I am indeed setting the clip bounds of the circleFab layout (it's a FrameLayout that contains an oval drawable and a bitmap drawable) correctly. Still, the scale animation takes up the whole activity screen.
Am I completely misunderstanding what .setClipBounds() does in this instance?

Related

Animation bag with some ImageViews

I have problem with my android animation. When I click the first time on my ImageView, my image have a rotation but when click the second time on my ImageView, rotation don't work. Why is it happened?
My rotation method in Java code:
private boolean tomIsInvisible = false;
public void eraseTom(View view) {
ImageView tom = findViewById(R.id.tom);
ImageView jerry = findViewById(R.id.jerry);
if (tomIsInvisible) {
tom.animate()
.rotation(3600)
.scaleX(1)
.scaleY(1)
.alpha(1)
.setDuration(3000);
jerry.animate()
.rotation(3600)
.scaleX(0)
.scaleY(0)
.alpha(0)
.setDuration(3000);
tomIsInvisible = false;
} else if(!tomIsInvisible) {
tom.animate()
.rotation(3600)
.scaleX(0)
.scaleY(0)
.alpha(0)
.setDuration(3000);
jerry.animate()
.rotation(3600)
.alpha(1)
.scaleX(1)
.scaleY(1)
.setDuration(3000);
tomIsInvisible = true;
}
}
Others methods on my ImageView work correctly.
When you call rotation(3600) first time it animates rotation from 0 to 3600. (default view rotation is 0). After first animation rotation is 3600 (ViewPropertyAnimator changes actual value of property while it animate things). So when you call rotation(3600) second time rotation of your view is already 3600 and you try to animate it to 3600. Thats why there is no visual changes. There is rotationBy method which apply specified value to view rotation, try to use it.
view.animate().rotationBy(3600)
Another solution is to animate from 0 to 360 and in the animation end reset view rotation to 0.

How to animate a button in Android to expand sideways?

I want a Button (or any View for that matter) to expand / stretch out sideways with an animation and I want it to happen at the click of another Button. For example, before Button 1 is pressed, the Button 2 shouldn't exist. But when Button 1 is pressed, the Button 2 should slowly come into existence with both its sides smoothly expanding to left and right to a certain size.
The following is a photo I drew to explain what I'm trying to achieve
I have looked at several tutorials, but most of them had sliding animation from one fixed end to the other. I have also tried scaling the X & Y of the button from value 0 to 1, but they just don't give the smooth animation effect (they just appear there out of nowhere) and the button doesn't expand / stretch sideways.
Any idea how this can be achieved?
Thank you for your time!!
the smooth animation effect ,you can use ObjectAnimtor.
// scale down button2 at the start of an activity
btn2.setScaleX(0.1f);
// on the click of button 1 let the button2 scale
btn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
btn2.animate()
.scaleX(4.0f)
.setDuration(1000)
.setInterpolator(new OvershootInterpolator(2.0f)) //Will give bounce effect to the scaling
.start();
}
});
I think you can use this library for Button 2 animation.
In order to it happen at the click of another Button just call View.performClick() for Button 2 from Button 1 onClick() method.
first define 2 objects of Animation and Button then create a On Click listener for Button and write these codes in it:
//here i define :Button btnoff
//Animation animation1
//set on click listener in oncreate
btnOff.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
animation1 = new ScaleAnimation(0,2,1,1,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animation1.setDuration(1200);
btnOff.startAnimation(animation1);}
});
you can learn more in this link.

Occasional flickering between ImageViews when moved

I have a series of ImageViews that I programatically added into a LinearLayout, so they all end up horizontally lined up.
But when I try to use a TranslateAnimation to move all the images at once, a 1 pixel white gap flashes between every ImageView for about .02 seconds and then disappears. And this seems to consistently happen every 2 seconds or so.
TranslateAnimation moveLeft = new TranslateAnimation(0, -1250, 0, 0);
moveLeft.setDuration(10000);
moveLeft.setFillAfter(true);
I make my ImageViews all at the same time before I move them. (Also, the ImageViews have all default settings) I've also confirmed that there are no white gaps between the ImageViews before I move them.
The flickering only happens when I set all the ImageViews's animations to moveLeft.
Also, here is the class in question :
public class Terrain {
Bitmap tile;
InputStream is;
ImageView imageViewPlatform;
Drawable tileDrawable;
ArrayList<ImageView> terrainArray = new ArrayList<ImageView>();
ArrayList<TranslateAnimation> moveLeftArray = new ArrayList<TranslateAnimation>();
int count = 0;
int terrainBlockNumber = 0;
boolean initialized = false;
TranslateAnimation moveLeft;
public void initialize(Activity activity){
is = activity.getResources().openRawResource(+R.drawable.game_tile);
tile = BitmapFactory.decodeStream(is);
tileDrawable = new BitmapDrawable(activity.getResources(), tile);
moveLeft = new TranslateAnimation(0, -1250, 0, 0);
moveLeft.setDuration(10000);
moveLeft.setFillAfter(true);
initialized = true;
Log.d("Terrain", "Terrain images are initialized.");
}
public void draw(Activity activity, LinearLayout linearLayout,
LinearLayout.LayoutParams layoutParams) {
if (!initialized) {
throw new RuntimeException("initialize() method must " +
"be called before the draw() method.");
}else{
terrainArray.add(new ImageView(activity));
++count;
terrainArray.get(count-1).setImageDrawable(tileDrawable);
linearLayout.addView(terrainArray.get(count-1), layoutParams);
}
}
public void move(Activity activity) {
terrainBlockNumber++;
final int terrainAnimationBlock = terrainBlockNumber;
moveLeft.setAnimationListener(new Animation.AnimationListener() {
int currentCount = terrainAnimationBlock;
#Override
public void onAnimationStart(Animation animation) {
Log.d("Animation Started", "Block Number is " + currentCount);
}
#Override
public void onAnimationEnd(Animation animation) {
terrainArray.get(currentCount - 1).setVisibility(View.GONE);
Log.d("Terrain Deletion", "Block number " +
currentCount + " has been deleted.");
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
terrainArray.get(terrainBlockNumber - 1).startAnimation(moveLeft);
}
}
}
This is the XML file for the activity
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.project.PlayActivity">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/linearLayout"
android:weightSum="1"
android:layout_alignParentTop="true"
android:layout_marginTop="200dp"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true">
</LinearLayout>
</RelativeLayout>
UPDATE :
Moving the entire LinearLayout does not seem to work either. Although, moving the entire LinearLayout isn't really helpful. It cuts off ImageViews that are off-screen.
But since you requested it, all I did was change the move method to :
public void move(LinearLayout linearLayout){
linearLayout.setAnimation(moveLeft);
}
All the images did actually move at the same speed, and there is still the flickering between the images.
UPDATE 2
I have confirmed that it has something to do with my images/how they're formatted/the size of the images or something along those lines.
If it is any help, the image I use is 95 X 84 pixels. (It's really tiny)
If you have several images you might want to:
Use a RecyclerView. This gives you more control over animations and decorations, and optimizes the memory usage at the same time. This answer will help you understand how to make your animations.
Make sure you are not constantly resizing your images. If the animation needs to handle images that are originally too big, it might impact on the quality of the animation (i.e. use thumbnails and fixed sizes in order to avoid costly computations)
For instance, if your original images are 600x800 but your image
view has a centerCrop/fit/etc ending up occupying a space of 200x200,
android will be doing a lot of resizing to match those settings. The
more computations it does, the more chances you get of missing
frames. In other words: what you experience is a low framerate,
which happens when android is unable to finish all drawing
computations in time for the next screen refresh.
There are different problems you can attack:
Reduce the computations by using the right image sizes
Smaller images also mean less memory usage, which reduces the need of memory reallocation or forced garbage collection.
Avoid computing/rendering things that are invisible. Either because they are out of screen or because something overlaps them. In your case, recycler view might help to load only the images on your visible screen, instead of wasting space and computations on images that are out of sight at the moment.
Reduce the layout rewrite. Android tries to render only the sections with updates, instead of re-render all the screen. But if your layout forces other layouts to recalculate their size, you can end up forcing a whole resize. In your case, do not use LinearLayout to list images. Instead, use some layout that is actually designed for that sort of things. As I said, RecyclerView with the default LinearLayoutManager works very well.
Check if you have hardware acceleration turned on.
Try to put the ImageViews in a LinearLayout or other ViewGroup and animate the entire ViewGroup and see if that helps.

Animating crossfade between 2 layouts

I'm trying to implement an animation which crossfades between 2 layout, with a layover between them. The first layout is the main layout, the second is a simple linear layout with textView and red background (your classic "Wrong!" screen if you will...). My goal is to animate a quick transition between the mainLayout and wrongLayout, have the program wait for a short period of time while displaying the wrongLayout and then automatically return to mainLayout. This turns out to be extremelly hard, I've tried using monitors, Thread.sleep() etc. but what I get is that the program waits before starting the animation and THEN performs it without any layover.
My code is as follows:
In the main method-
LinearLayout wrongLayout = (LinearLayout) findViewById(R.id.wrong_layout);
RelativeLayout mainLayout = (RelativeLayout) findViewById(R.id.main_layout);
int animationDuration = getResources().getInteger(
android.R.integer.config_longAnimTime);
crossfade(wrongLayout, mainLayout, animationDuration);
/* This is where I want it to wait for 1 second */
crossfade(mainLayout, wrongLayout, animationDuration);
and the crossfade method-
private void crossfade(View fadeInLayout, final View fadeOutLayout,
int animationDuration) {
// Set the content view to 0% opacity but visible, so that it is visible
// (but fully transparent) during the animation.
fadeInLayout.setAlpha(0f);
fadeInLayout.setVisibility(View.VISIBLE);
// Animate the content view to 100% opacity, and clear any animation
// listener set on the view.
fadeInLayout.animate()
.alpha(1f)
.setDuration(animationDuration)
.setListener(null);
// Animate the loading view to 0% opacity. After the animation ends,
// set its visibility to GONE as an optimization step (it won't
// participate in layout passes, etc.)
fadeOutLayout.animate()
.alpha(0f)
.setDuration(animationDuration)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
fadeOutLayout.setVisibility(View.GONE);
}
});
}
Thanks a lot...
Ok, so I've found this post which deals with just about the same problem-
Why the Sleep executes first and than the code above it in android?
I've changed the appropriate execution function and now it seems to work properly, though I'm still puzzled by the fact that I cannot cause the code to stop at a designated location for a specific amount of time. Oh well...

ImageView disappears when TranslateAnimation is applied

I understand, that this is local problem, but I was fighting with it for 1 day and I want ask for your help.
I have such kind of "game", where user can move items by swype, in this case, we are doing swype from top to bottom. Items are actual ImageViews.
On the first image we can see 7 items before the actual swype
Item goes as down as he can, until he meets another item or border of the field (invisible now)
On the second image, items have been moved once to down (only those who didnt have obstacle moved, 4 of them)
And, final position of items after second swype:
Now the problem : I can't explain why, but exactly when I do first swype, from top to bottom, and apply to those 4 items which will move down the actual animation of transition to new position, they dissapear on half way and appear on the new place!
When I do any other swype, to any direction, any items are animated, there are no problems. Everything goes fine when I do second swype to bottom.
I checked and overchecked, animation is done properly, there comes right parameters, and there are no other ImageViews on the way of animation, but something is overlaying the animation exactly in case where there are obsticles on the top of ImageViews! This is just weird.
All needed code is following:
Animation void
private void moveItem(final FieldItem item, final float x, final float y) {
// item to animate, transition X, transition Y
final RelativeLayout.LayoutParams oldParams = (LayoutParams) item
.getLayoutParams();
TranslateAnimation animation = new TranslateAnimation(0.0f, x, 0.0f, y);
animation.setDuration(500);
animation.setFillAfter(true);
animation.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
item.invalidate();
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
item.clearAnimation();
//all following is just to remove old item from layout
//and put new item on the place where animation should have ended
//nothing which can affect, it works perfect with any other condition
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
itemSize, itemSize);
params.leftMargin = (int) (oldParams.leftMargin + x);
params.topMargin = (int) (oldParams.topMargin + y);
gView.rLayout.removeView(item);
putItem(1, params);
gView.rLayout.invalidate();
//it's only ArrayList which contains copies of all Layout's children
//of ImageView class, for providing field moves logic, can't affect
//also recounts how many imageViews are in children of Layout
updateField();
//shows right margins, right amount of items on the field, they are always recounted depending of RelativeLayout children
Log.i("my_log", "Pos change, from " + oldParams.leftMargin + "/" + oldParams.topMargin + " to " + params.leftMargin + "/" + params.topMargin);
Log.i("my_log", "Size of field: " + field.size());
}
});
item.startAnimation(animation);
}
Layout which is used in here:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/rootLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clipChildren="false"
android:orientation="vertical" >
<com.crispy_chocolate.outofthebox.GameView
android:id="#+id/game"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clipChildren="false" />
</RelativeLayout>
So the question is - how can ImageView even dissapear during the local case of animation when in any other case the same methods work totally fine? Maybe someone will be kind to help me.
Apparently, it's some kind of a bug, because If I put any imageview to the bottom part of the screen, or write some text, animation starts to go completely OK. weird.

Categories

Resources