Android: bad animation framerate when fading screen - android

I have simple task: fade screen (+ other actions, but it doesnt matter now) when something happens (say, button pressed).
My minSDKVersion is 11. I do it in this way: activity layout contains a view:
<View
android:id="#+id/bgFadingView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0"
android:background="#android:color/black" />
and method where I fade screen is as follows:
protected void fadeBGView(boolean fadeIn)
{
ObjectAnimator animator = ObjectAnimator.ofFloat(bgFadingView, "alpha", fadeIn ? 0.75f : 0f); //bgFadingView is initialized via findViewById(R.id.bgFadingView);
animator.setDuration(1000);
animator.start();
}
in other words, I have black view, which occupies the whole screen and when I need to fadeIn, I change view's alpha from 0 to 0.75.
The problem is that it works with bad framerate... I see fading animation frame by frame - it works at about 15fps. What am I doing wrong? Android system fading works much more smoothly - I want to archieve the same result or close. How to?

All I had to do was:
ObjectAnimator.setFrameDelay(10);
default frame delay was too long, so my animations didnt work smoothly. The problem was not due to device performance limitations.

Related

Blinking Video/SurfaceView when resizing to PiP mode

I'm working on PiP mode in my app. In fact it is working pretty fine, but I have a problem with blinking/disappearing video for a split second.
I have VideoActivity in "fullscreen"/normal mode. I'm calling enterPictureInPictureMode(); and Activity is collapsing to small PiP-frame. At the moment when animation is ending shrinking layout then video get transparent for a split second/one frame. Also exacly in this frame whole PiP-frame gets shadow under (elevation). When I touch this small PiP-frame it expands a bit to big PiP-frame (not fullscreen) and this anim is smooth, but when auto-collapse to small PiP-frame it blinks again on the end... Everytime when Activity is animating to small PiP-frame (no matter if is collapsing from big PiP-frame or fullscreen Activity) one-frame transparency-blink occurs when reaching final "small bounds". No impact to sound, video is playing steady, no calls to onPlayerStateChanged.
With newer API version we can create animation with bounds and thats how I know the video view is blinking... Using no-attribute method makes whole layout collapses and I can see blink only on area with video/player/surface view (black stripes above and below video). When I use newer method and setSourceRectHint I can see whole PiP-frame disapears without respecting black background of its parent. In fact I've added dummy View with fixed size, background color and centerInParent like PlayerView - it blinks/hides just like player when is placed below (first in parent) PlayerView layer, but placed above doesn't blink at all and is showing above PlayerView even when it disappears for split sec.
How to fix that blink or maybe though set black background, not transparent...
if (Build.VERSION.SDK_INT >= 26) {
Rect bounds = new Rect();
playerView.getVideoSurfaceView().getDrawingRect(bounds);
int toTop = (playerView.getMeasuredHeight() - bounds.height()) / 2,
toLeft = (playerView.getMeasuredWidth() - bounds.width()) / 2;
bounds.top += toTop;
bounds.left += toLeft;
bounds.bottom += toTop;
bounds.right += toLeft;
enterPictureInPictureMode(new PictureInPictureParams.Builder().
setSourceRectHint(bounds).
setAspectRatio(new Rational(bounds.width(), bounds.height())).
build());
} else
enterPictureInPictureMode();
xml:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/black">
<com.google.android.exoplayer2.ui.PlayerView
android:id="#+id/activity_video_player_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:background="#android:color/black"
app:controller_layout_id="#layout/exo_custom_control_view"
app:fastforward_increment="10000"
app:rewind_increment="10000"
app:show_timeout="100" />
...
PS. Above problem also appears when using usual VideoView played in WebView and got into fullscreen by VideoEnabledWebChromeClient. But in this case blink reveals for a split second part of WebViews content
edit: I've just found a workaround for blinking ExoPlayer - by replacing SurfaceView with TextureView, adding app:surface_type="texture_view" - but I'm reading that TextureView is a bit less efficient and also this is not fixing VideoView blink (fullscreen from WebView)
edit2: can confirm blinks on Android 8 (Xiaomi) and 9 (Pixel)

Letting an image expand into view using an animation

In my Android app, I have a TextView with a white background. When it is clicked, its background will change to a .png picture of some icon by calling setBackgroundResource(R.drawable.icon) on the TextView. This works as intended, but the change is rather abrupt. I would like to make the icon appear more gradually; when the TextView is clicked, a tiny version of the icon should appear in the center of the TextView and then immediately expand and fill out the entire TextView. I believe the best way to do this would be by using an animation, which of the available animation types in Android are best for this task?
In case it is not clear what I mean, I drew a sketch to illustrate. The second sequence shows how the code works right now, the first shows how I would like it to be.
So, I managed to get the effect you want with an ImageView, using ScaleAnimation. Here's what you have to do:
First, our XML ImageView:
<ImageView
android:id="#+id/scale_anim"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#android:color/white" />
It has fixed dimensions and a white background.
The animation will start with one click with this, inside your onCreate() method:
ImageView starImageView = (ImageView) findViewById(R.id.scale_anim);
starImageView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ScaleAnimation starScaleAnimation =
new ScaleAnimation(0.3f, 1f, 0.3f, 1f,
ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
starScaleAnimation.setDuration(500);
((ImageView) v).setImageResource(R.drawable.star);
ScaleAnimation scaleAnim = starScaleAnimation;
v.startAnimation(scaleAnim);
}
});
We are applying a scale animation on the ImageView that stars with 30% of the original size and scales to 100% of its size, from its center point. The duration of this animation is half a second. All these parameters can be changed.
Every time you click the ImageView, your drawable will be applied and the animation will start.
Try this way if it solve yours.
Create an ImageView (X) above your original ImageView (A) - same size and same place as (A)
Animate (X) with ObjectAnimator, listen for the onAnimationEnd call and set the (A)'s background. Then remove (X).
Hope this will help.

android, how to sweep alpha animation from left to right?

I should display an animation that draws line from left to right. Please look at following image.
First layer is background (whole image without root lines and country names)
Second layer is lines and country names.
I can use alpha animation in following way in my activity:
mIvRoot = (ImageView) findViewById(R.id.ivRoot);
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(mIvRoot, "alpha", 0f, 1f);
alphaAnim.setDuration(2000);
alphaAnim.start();
Although it works fine, however alpha applies to whole image. The thing that I'm looking for instead is alpha applies from left to right. Therefore, user feels lines are drawing.
Any suggestion would be appreciated. Thanks
I fixed temporarily my problem in a bl.sht way. Please share with me your idea to fix this way.
I placed another white view (since my background is white) on top of root image and assigned it translation animation instead of using alpha animation Like this:
<View
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/White"
android:id="#+id/viCover"
android:layout_alignTop="#+id/ivRoot"
android:layout_alignBottom="#+id/ivRoot"
android:layout_alignLeft="#+id/ivRoot"
android:layout_alignRight="#+id/ivRoot"
android:layout_marginLeft="200dp"/>
and code:
ObjectAnimator transRootAnim = ObjectAnimator.ofFloat(mViCover, "translationX", 0f, 1500f);
transRootAnim.setDuration(3000);
transRootAnim.start();
Even though i didn't understand why you're not actually drawing those lines, you may want to look at this post by Romain Guy that he also made something similar (Actually almost same :))

Animate ImageView width without scaling

I'm trying to animate an ImageView so it's slowly shown from left to right.
When I asked this before I was having trouble to explain what I wanted, so this time I created the desired effect using HTML / JS:
http://jsfiddle.net/E2uDE/
What would be the best way to get this effect in Android?
I tried changing the scaleType and then applying a ScaleAnimation directly to that ImageView:
Layout:
<ImageView
android:id="#+id/graphImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:scaleType="centerCrop"
android:background="#android:color/transparent"
android:contentDescription="#string/stroom_grafiek"
/>
Java:
scale = new ScaleAnimation((float)0,
(float)1, (float)1, (float)1,
Animation.RELATIVE_TO_SELF, (float)0,
Animation.RELATIVE_TO_SELF, (float)1);
scale.setDuration(1000);
graphImage.startAnimation(scale);
But this stil scales the image.
I also tried wrapping the ImageView in a FrameLayout, hoping I could just animate the FrameLayout:
<FrameLayout
android:layout_width="70dp"
android:layout_height="fill_parent"
android:clipChildren="true"">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|left|clip_horizontal" />
</FrameLayout>
This will still try to scale my ImageView to fit inside the FrameLayout.
There are several ways to do this - one way is to simply change the clip on the canvas (i.e. the area where the view is allowed to draw) of the ImageView drawing your image. Slowly increasing the right-hand edge of the draw bounds will result in same effect as in your example link.
I have written some example code which illustrates this technique. If you download/build/run the project, clicking on the image will run the reveal animation.
Have a look at the onDraw method of the CoveredImageView class, which has the following basic structure:
#Override
protected void onDraw(Canvas canvas) {
...
canvas.getClipBounds(mRect);
mRect.right = ...;
canvas.clipRect(mRect);
...
super.onDraw(canvas);
...
invalidate();
}
The clip is adjusted and then invalidate() is called, causing onDraw() to be called again.
I have also written some code to interpolate the right clip value from the elapsed time, which does not depend on any particular version of Android. However, as a note, from Android 3.0 there is a new animation framework and a ValueAnimator class which could help perform such tasks.
You could overlap your imageview with another one, for example one with a plain white drawable. Then you can animate the overlapping imageview without worrying about scale until it has a width of 0 and remove it. For that to work you have to place your imageView in a RelativeLayout ofc.

Animating weightSum property using ObjectAnimator

Intro:
I have a LinearLayout, which contains two sub LinearLayouts, like so:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/dual_pane"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:weightSum="1.0">
<!-- Screen 1 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="#ff0000"
android:layout_weight="1">
</LinearLayout>
<!-- Screen 2 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="#ff6600"
android:layout_weight="1">
</LinearLayout>
</LinearLayout>
Initially, I want "Screen 1" to take all screen width available. Therefore, my R.id.dual_pane has it's weightSum attribute to 1.0. This works fine! if weightSum=1.0, Screen 1 occupies the whole screen!
After loading some resources, I change my R.id.dual_pane weighSum to 2.0, which results in both Screen 1 and Screen 2 taking 50% off the width of the screen. This also works perfect. When weightSum=2.0, both screens take 50% of the width.
Problem:
I would like to animate the weightSum property, so my Screen2 will slide in.
I am targeting HoneyComb, so minSDK version is 11, and I figured, using the new ObjectAnimator framework, I could easily animate this property, to get a nice smooth effect. I verified that LinearLayout indeed has getWeightSum() and setWeightSum() methods (which is required to use the ObjectAnimator, I think).
Own effort:
Here's my code to showing and hiding Screen2 using the ObjectAnimator :
private void showScreen2()
{
//Not-animated will work...
//mDualPane.setWeightSum(2.0f);
// Now try to animate the weightSum
float ws = mDualPane.getWeightSum();
ObjectAnimator anim = ObjectAnimator.ofFloat(mDualPane, "weightSum", ws, 2.0f);
anim.setDuration(5000);
anim.start();
}
private void hideScreen2()
{
//Not-animated will work...
//mDualPane.setWeightSum(1.0f);
// Now try to animate the weightSum
float ws = mDualPane.getWeightSum();
ObjectAnimator anim = ObjectAnimator.ofFloat(mDualPane, "weightSum", ws, 1.0f);
anim.setDuration(5000);
anim.start();
}
Here, my mDualPane is my root LinearLayout...
Question:
When I call these functions, nothing happens. The screen stays exactly like it was before.
Do I need to call requestLayout() on my mDualPane somewhere? Am I missing some knowledge of the ObjectAnimator? Or is it impossible to animate the weightSum property?
ALSO:
1) I don't want to mess with hard-coded widths, and animate those. For now I want 50-50 for both screens, but I might change it later. Anyway, i need to be able to set a specific ratio between the two widths.
2) I have looked at LayoutTransition combined with toggling visibility, but to no avail
I was right in the sense that I need to update the layout myself:
float ws = mDualPane.getWeightSum();
ObjectAnimator anim = ObjectAnimator.ofFloat(mDualPane, "weightSum", ws, 2.0f);
anim.setDuration(5000);
anim.addUpdateListener(this);
anim.start();
Now, I added an UpdateListener to the ObjectAnimator, which is implemented by my Activity and updates the layout:
#Override
public void onAnimationUpdate(ValueAnimator animation) {
mDualPane.requestLayout();
}
It seems strange to me, that ObjectAnimator doesn't call this itself, but anyway, this is how to get it working.
The solution is especially nice, in my opinion, since you can very nicely animate layouts sliding in, independent of screensize...

Categories

Resources