Animating a TextView height increasing - android

Could someone please post a simple example of how to animate a TextView growing in height from 0dp to a dynamic value?
I would like to increase the height of a textview, but allow the user to SEE it like an animation. The only condition is I know my max height is variable and not known at run time. The maximum I want to allow is 100dp.
I've tried performing a simple for loop such as:
runOnUiThread(new Runnable() {
public void run() {
LayoutParams params = myTextView.getLayoutParams();
int myMaxHeightValue = 100;
for (int x=0; x<myMaxHeightValue; x++) {
params.height = getDensityPixels(x);
myTextView.setLayoutParams(params);
Thread.Sleep(300);
}
}
});
public void getDensityPixels(int value) {
float density = getResources().getDisplayMetrics.display;
return (int) (value * density + 0.5f);
}
Can anyone provide just a simple example where I can provide the MAX height and watch the textview grow from 0dp height to the MAX dp height? When I use the code above, it does indeed increase to the max height of 100dp, but the screen locks while it is sizing rather than SHOWING me the increase as it occurs.
Any help is greatly appreciated!

Never use thread to perform UI/View animations. Android provide so many options for animation, like ObjectAnimator, ValueAnimator, View Animator
An example, as per your requirement.
private void animateHeight() {
TextView myTextView=null;
int maxInDp = 100;
int maxInPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
maxInDp, mLauncher.getResources().getDisplayMetrics());
ObjectAnimator.ofInt(this, "btnHeight", maxInPx).setDuration(300).start(); // for better animation change duration , and set interpolator.
}
public int btnHeight = 0;
public int getBtnHeight() {
return btnHeight;
}
public void setBtnHeight(int height) {
btnHeight = height;
LayoutParams params = myTextView.getLayoutParams();
params.height = btnHeight;
myTextView.setLayoutParams(params);
}

You are locking your Main thread by running your worker thread on it. To update your UI while doing work in the background, use an AsyncTask. This tutorial explains how to do it nicely.
Basically, your AsyncTask will look something like this (example from above tutorial)
public class DoSomethingTask extends AsyncTask<Void, String, Void> {
private static final String TAG = "DoSomethingTask";
private static final int DELAY = 5000; // 5 seconds
private static final int RANDOM_MULTIPLIER = 10;
#Override
protected void onPreExecute() {
Log.v(TAG, "starting the Random Number Task");
super.onPreExecute();
}
#Override
protected void onProgressUpdate(String... values) {
//HERE is where you will be doing your UI updates
Log.v(TAG, "reporting back from the Random Number Task");
updateResults(values[0].toString());
super.onProgressUpdate(values);
}
#Override
protected Void doInBackground(Void... params) {
//HERE is where you will be doing your work (your loop)
Log.v(TAG, "doing work in Random Number Task");
String text="";
while (true) {
if (isCancelled()) {
break;
}
int randNum = (int) (Math.random() * RANDOM_MULTIPLIER);
text = String.format(getString(R.string.service_msg), randNum);
//This is how you tell your thread to update the UI
publishProgress(text);
try {
Thread.sleep(DELAY);
} catch (InterruptedException e) {
Log.v(TAG, "Interrupting the Random Number Task");
}
}
return null;
}
}

Related

spinningwheel animation not accurate

To gain experience in android I'm making a decisionmaking app. I'm trying to add a spinning wheel (wheel of fortune like). I have an animation that works fine (just need some little tweaking but fine for now). The problem I'm having is to detect where the wheel has stopped. If I look at the rotation and match it to precalculated values it makes sense, but visually it seems off.
For example:
Begin state is always like this. I tap it and it starts to rotate.
It stops rotating at red (visually), but in the model it says 51, hence my model detects it stopped rotating at yellow:
Cur pos and Prev pos is not currently implemented. Rnd pos is the relative number of degrees it needs to rotate (relative to 0). Rnd rot is number of extra rotations it has to make before stopping. True pos is the absolute number of degrees it has to rotate. Total time: the time the animation takes. Corner: number of degrees one piece has.
SpinWheel method in activity:
private void spinWheel() {
Roulette r = Roulette.getInstance();
r.init(rouletteItemsDEBUG);
r.spinRoulette();
final int truePos = r.getTruePosition();
final long totalTime = r.getTotalTime();
final ObjectAnimator anim = ObjectAnimator.ofFloat(imgSpinningWheel, "rotation", 0, truePos);
anim.setDuration(totalTime);
anim.setInterpolator(new DecelerateInterpolator());
anim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
imgSpinningWheel.setEnabled(false);
}
#Override
public void onAnimationEnd(Animator animation) {
imgSpinningWheel.setEnabled(true);
txtResult.setText(Roulette.getInstance().getSelectedItem().getValue());
Log.d(TAG, Roulette.getInstance().toString());
Log.d(TAG, imgSpinningWheel.getRotation() + "");
Log.d(TAG, imgSpinningWheel.getRotationX() + "");
Log.d(TAG, imgSpinningWheel.getRotationY() + "");
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
anim.start();
}
Roulette.java:
public class Roulette {
private static Roulette instance;
private static final long TIME_IN_WHEEL = 1000; //time in one rotation (speed of rotation)
private static final int MIN_ROT = 5;
private static final int MAX_ROT = 6;
private static final Random rnd = new Random();
private RouletteItem currentItem;
private RouletteItem[] rouletteItems;
private NavigableMap<Integer, RouletteItem> navigableMap;
private int randomRotation;
private int randomPosition;
private int truePosition;
private int corner;
private long totalTime;
private Roulette() {
}
public void init(RouletteItem[] rouletteItems) {
this.rouletteItems = rouletteItems;
navigableMap = new TreeMap<>();
for (int i = 0; i < getNumberOfItems(); i++) {
navigableMap.put(i * 51, rouletteItems[i]);
}
}
public void spinRoulette() {
if (rouletteItems == null || rouletteItems.length < 2) {
throw new RouletteException("You need at least 2 rouletteItems added to the wheel!");
}
calculateCorner();
calculateRandomPosition();
calculateRandomRotation();
calculateTruePosition();
calculateTotalTime();
}
/**
* Pinpoint random position in the wheel
*/
private void calculateRandomPosition() {
randomPosition = corner * rnd.nextInt(getNumberOfItems());
}
/**
* Calculates the points one RouletteItem has
*/
private void calculateCorner() {
corner = 360 / getNumberOfItems();
}
/**
* Calculates the time needed to spin to the chosen random position
*/
private void calculateTotalTime() {
totalTime = (TIME_IN_WHEEL * randomRotation + (TIME_IN_WHEEL / 360) * randomPosition);
}
/**
* Calculates random rotation
*/
private void calculateRandomRotation() {
randomRotation = MIN_ROT + rnd.nextInt(MAX_ROT - MIN_ROT);
}
/**
* Calculates the true position
*/
private void calculateTruePosition() {
truePosition = (randomRotation * 360 + randomPosition);
}
//getters and to string omitted
}
The map is used to map rouletteItems to a range of degrees.
My guess is that the animation takes too long or something like that. But I don't really see how to fix it. Anyone who does?
Thanks in advance!
Um, doesn't Java implement rotation in radians rather than degrees?
That could lead to a offset between the visual rotation graphic and the number from the maths. Perhaps check by replacing all the assumed degree calculations (ie x/360) with radian calcs (ie. x/(2*pi))?

Best way to animate rectangle in Android

I want to animate a rectangle filled with one opaque color. The attributes I will be animating is the translation, and the width of the active menu item.
I know how to animate things, but in this case, I want it to do no layouts on the view, since my animation will occur inside a LinearLayout, and it will not exceed it's size.
The Blue line on top of my layout is what I will be animating. It will go horizontally to the left and right, while changing it's width, so that it fits on the selected menu item.
I usually work with animations on the margin, but it consumes a lot of processing to re-calculate bounds on the layout process.
Any suggestions on how to do that?
That depends entirely on what API level you're targetting, if you're only targeting >3.0 then ObjectAnimator and ValueAnimator or the nicer ViewPropertyAnimator are your best friend, they let you do simple things like "move the X value of this 100dp while increasing the width by a factor of two, in 300ms".
If you're targeting a lower API level check out NineOldAndroids which brings that functionality over to all versions of Android.
To do what you want to do it'd be something along the lines of:
myImageView.scaleXBy(FACTOR_NEEDED_FOR_NEW_WIDTH);
and that's all to it.
As a sidenote: It looks like you might be attempting to replicate a ViewPager's indicator, in which case you should be using an actual indicator.
I had to animate the Margin and the Width of the view, because there was no way out, since I'm using android version >=8.
Here is my two classes that can do this:
MarginAnimation class:
public class MarginAnimation extends Animation{// implements AnimationListener{
public static String TAG = "MarginAnimation";
protected View animatingView;
protected int fromMarginLeft = 0;
protected int fromMarginTop = 0;
protected int toMarginLeft = 0;
protected int toMarginTop = 0;
protected LayoutParams layoutParam;
public MarginAnimation(View v, int toMarginLeft, int toMarginTop) {
this.toMarginLeft = toMarginLeft;
this.toMarginTop = toMarginTop;
this.animatingView = v;
// Save layout param
layoutParam = (LayoutParams) animatingView.getLayoutParams();
// Save current margins as initial state
saveCurrent();
// Set the listner to be self object
// setAnimationListener(this);
}
public MarginAnimation(View v, int fromMarginLeft, int toMarginLeft, int fromMarginTop, int toMarginTop) {
this.fromMarginLeft = fromMarginLeft;
this.toMarginLeft = toMarginLeft;
this.fromMarginTop = fromMarginTop;
this.toMarginTop = toMarginTop;
this.animatingView = v;
// Save layout param
layoutParam = (LayoutParams) animatingView.getLayoutParams();
// Set the listner to be self object
// setAnimationListener(this);
}
protected void saveCurrent(){
fromMarginLeft = layoutParam.leftMargin;
fromMarginTop = layoutParam.topMargin;
}
long lastTime = 0;
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
// long thisTime = System.nanoTime();
// if(lastTime != 0)
// Log.e(TAG, ((thisTime - lastTime) / 1000) + "delta Anim.");
// lastTime = thisTime;
layoutParam.leftMargin = (int)(fromMarginLeft + (toMarginLeft - fromMarginLeft) * interpolatedTime);
layoutParam.topMargin = (int)(fromMarginTop + (toMarginTop- fromMarginTop) * interpolatedTime);
animatingView.setLayoutParams(layoutParam);
}
#Override
public boolean willChangeBounds() {
return false;
}
}
MarginAndWidthAnimation class:
public class MarginAndWidthAnimation extends MarginAnimation{
public static String TAG = "MarginAndWidthAnimation";
int toWidth;
int fromWidth;
public MarginAndWidthAnimation(View v, int toMarginLeft, int toMarginTop, int toWidth) {
super(v, toMarginLeft,toMarginTop);
this.toWidth = toWidth;
// Log.i(TAG, "++F: "+this.fromWidth+" T: "+this.toWidth);
}
protected void saveCurrent(){
super.saveCurrent();
// fromWidth = animatingView.getWidth();
fromWidth = layoutParam.width;
// Log.i(TAG, "F: "+fromWidth+" T: "+toWidth);
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
layoutParam.width = (int)(fromWidth + (toWidth - fromWidth) * interpolatedTime);
// Log.i(TAG, "F: "+fromWidth+" T: "+toWidth+" S: "+layoutParam.width);
super.applyTransformation(interpolatedTime, t);
}
}

Animate ProgressBar update in Android

I am using a ProgressBar in my application which I update in onProgressUpdate of an AsyncTask. So far so good.
What I want to do is to animate the progress update, so that it does not just "jump" to the value but smoothly moves to it.
I tried doing so running the following code:
this.runOnUiThread(new Runnable() {
#Override
public void run() {
while (progressBar.getProgress() < progress) {
progressBar.incrementProgressBy(1);
progressBar.invalidate();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
The problem is that the progress bar does not update its state until it finished its final value (progress variable). All states in between are not displayed on the screen. Calling progressBar.invalidate() didn't help either.
Any ideas? Thanks!
I used android Animation for this:
public class ProgressBarAnimation extends Animation{
private ProgressBar progressBar;
private float from;
private float to;
public ProgressBarAnimation(ProgressBar progressBar, float from, float to) {
super();
this.progressBar = progressBar;
this.from = from;
this.to = to;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
float value = from + (to - from) * interpolatedTime;
progressBar.setProgress((int) value);
}
}
and call it like so:
ProgressBarAnimation anim = new ProgressBarAnimation(progress, from, to);
anim.setDuration(1000);
progress.startAnimation(anim);
Note: if from and to value are too low to produce smooth animation just multiply them by a 100 or so. If you do so, don't forget to multiply setMax(..) as well.
The simplest way, using ObjectAnimator (both Java and Kotlin):
ObjectAnimator.ofInt(progressBar, "progress", progressValue)
.setDuration(300)
.start();
where progressValue is integer within range 0-100 (the upper limit is set to 100 by default but you can change it with Progressbar#setMax() method)
You can also change the way how values are changing by setting different interpolator with setInterpolator() method. Here is visualization of different interpolators: https://www.youtube.com/watch?v=6UL7PXdJ6-E
I use an ObjectAnimator
private ProgressBar progreso;
private ObjectAnimator progressAnimator;
progreso = (ProgressBar)findViewById(R.id.progressbar1);
progressAnimator = ObjectAnimator.ofInt(progreso, "progress", 0,1);
progressAnimator.setDuration(7000);
progressAnimator.start();
Here is an improved version of #Eli Konky solution:
public class ProgressBarAnimation extends Animation {
private ProgressBar mProgressBar;
private int mTo;
private int mFrom;
private long mStepDuration;
/**
* #param fullDuration - time required to fill progress from 0% to 100%
*/
public ProgressBarAnimation(ProgressBar progressBar, long fullDuration) {
super();
mProgressBar = progressBar;
mStepDuration = fullDuration / progressBar.getMax();
}
public void setProgress(int progress) {
if (progress < 0) {
progress = 0;
}
if (progress > mProgressBar.getMax()) {
progress = mProgressBar.getMax();
}
mTo = progress;
mFrom = mProgressBar.getProgress();
setDuration(Math.abs(mTo - mFrom) * mStepDuration);
mProgressBar.startAnimation(this);
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
float value = mFrom + (mTo - mFrom) * interpolatedTime;
mProgressBar.setProgress((int) value);
}
}
And usage:
ProgressBarAnimation mProgressAnimation = new ProgressBarAnimation(mProgressBar, 1000);
...
/* Update progress later anywhere in code: */
mProgressAnimation.setProgress(progress);
ProgressBar().setProgress(int progress, boolean animate)
Android has taken care of that for you
A Kotlin way of doing this
import kotlinx.android.synthetic.main.activity.*
progressBar.max = value * 100
progressBar.progress = 0
val progressAnimator = ObjectAnimator.ofInt(progressBar, "progress", progressBar.progress, progressBar.progress + 100)
progressAnimator.setDuration(7000)
progressAnimator.start()
I just wanted to add an extra value for those who want to use Data Binding with a progress bar animation.
First create the following binding adapter:
#BindingAdapter("animatedProgress")
fun setCustomProgressBar(progressBar: ProgressBar, progress: Int) {
ObjectAnimator.ofInt(progressBar, "progress", progressBar.progress, progress).apply {
duration = 500
interpolator = DecelerateInterpolator()
}.start()
}
And then use it in the layout which contains the ViewModel that reports the status updates:
<ProgressBar
android:id="#+id/progress_bar_horizontal"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:indeterminate="false"
android:max="100"
app:animatedProgress="#{viewModel.progress ?? 0}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
The ViewModel itself will report the status with the following LiveData:
private val _progress = MutableLiveData<Int?>(null)
val progress: LiveData<Int?>
get() = _
EDIT: While my answer works, Eli Konkys answer is better. Use it.
if your thread runs on the UI thread then it must surrender the UI thread to give the views a chance to update. Currently you tell the progress bar "update to 1, update to 2, update to 3" without ever releasing the UI-thread so it actually can update.
The best way to solve this problem is to use Asynctask, it has native methods that runs both on and off the UI thread:
public class MahClass extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
while (progressBar.getProgress() < progress) {
publishProgress();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
progressBar.incrementProgressBy(1);
}
}
AsyncTask might seem complicated at first, but it is really efficient for many different tasks, or as specified in the Android API:
"AsyncTask enables proper and easy use of the UI thread. This class
allows to perform background operations and publish results on the UI
thread without having to manipulate threads and/or handlers."
You could try using a handler / runnable instead...
private Handler h = new Handler();
private Runnable myRunnable = new Runnable() {
public void run() {
if (progressBar.getProgress() < progress) {
progressBar.incrementProgressBy(1);
progressBar.invalidate();
h.postDelayed(myRunnable, 10); //run again after 10 ms
}
};
//trigger runnable in your code
h.postDelayed(myRunnable, 10);
//don't forget to cancel runnable when you reach 100%
h.removeCallbacks(myRunnable);
Simple Kotlin solution
if (newValue != currentValue) {
ObjectAnimator.ofInt(bar, "progress", currentValue, newValue)
.setDuration(500L) // ms
.start()
}
Even simpler:
ObjectAnimator.ofInt(bar, "progress", currentValue, newValue).apply {
duration = 500L
start()
}
Here is an improved version of a.ch. solution where you can also use rotation for circular ProgressBar. Sometimes it's required to set constant progress and change only rotation or even both progress and rotation. It is also possible to force clockwise or counter clockwise rotation. I hope it will help.
public class ProgressBarAnimation extends Animation {
private ProgressBar progressBar;
private int progressTo;
private int progressFrom;
private float rotationTo;
private float rotationFrom;
private long animationDuration;
private boolean forceClockwiseRotation;
private boolean forceCounterClockwiseRotation;
/**
* Default constructor
* #param progressBar ProgressBar object
* #param fullDuration - time required to change progress/rotation
*/
public ProgressBarAnimation(ProgressBar progressBar, long fullDuration) {
super();
this.progressBar = progressBar;
animationDuration = fullDuration;
forceClockwiseRotation = false;
forceCounterClockwiseRotation = false;
}
/**
* Method for forcing clockwise rotation for progress bar
* Method also disables forcing counter clockwise rotation
* #param forceClockwiseRotation true if should force clockwise rotation for progress bar
*/
public void forceClockwiseRotation(boolean forceClockwiseRotation) {
this.forceClockwiseRotation = forceClockwiseRotation;
if (forceClockwiseRotation && forceCounterClockwiseRotation) {
// Can't force counter clockwise and clockwise rotation in the same time
forceCounterClockwiseRotation = false;
}
}
/**
* Method for forcing counter clockwise rotation for progress bar
* Method also disables forcing clockwise rotation
* #param forceCounterClockwiseRotation true if should force counter clockwise rotation for progress bar
*/
public void forceCounterClockwiseRotation(boolean forceCounterClockwiseRotation) {
this.forceCounterClockwiseRotation = forceCounterClockwiseRotation;
if (forceCounterClockwiseRotation && forceClockwiseRotation) {
// Can't force counter clockwise and clockwise rotation in the same time
forceClockwiseRotation = false;
}
}
/**
* Method for setting new progress and rotation
* #param progress new progress
* #param rotation new rotation
*/
public void setProgressAndRotation(int progress, float rotation) {
if (progressBar != null) {
// New progress must be between 0 and max
if (progress < 0) {
progress = 0;
}
if (progress > progressBar.getMax()) {
progress = progressBar.getMax();
}
progressTo = progress;
// Rotation value should be between 0 and 360
rotationTo = rotation % 360;
// Current rotation value should be between 0 and 360
if (progressBar.getRotation() < 0) {
progressBar.setRotation(progressBar.getRotation() + 360);
}
progressBar.setRotation(progressBar.getRotation() % 360);
progressFrom = progressBar.getProgress();
rotationFrom = progressBar.getRotation();
// Check for clockwise rotation
if (forceClockwiseRotation && rotationTo < rotationFrom) {
rotationTo += 360;
}
// Check for counter clockwise rotation
if (forceCounterClockwiseRotation && rotationTo > rotationFrom) {
rotationTo -= 360;
}
setDuration(animationDuration);
progressBar.startAnimation(this);
}
}
/**
* Method for setting only progress for progress bar
* #param progress new progress
*/
public void setProgressOnly(int progress) {
if (progressBar != null) {
setProgressAndRotation(progress, progressBar.getRotation());
}
}
/**
* Method for setting only rotation for progress bar
* #param rotation new rotation
*/
public void setRotationOnly(float rotation) {
if (progressBar != null) {
setProgressAndRotation(progressBar.getProgress(), rotation);
}
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
float progress = progressFrom + (progressTo - progressFrom) * interpolatedTime;
float rotation = rotationFrom + (rotationTo - rotationFrom) * interpolatedTime;
// Set new progress and rotation
if (progressBar != null) {
progressBar.setProgress((int) progress);
progressBar.setRotation(rotation);
}
}
}
Usage:
ProgressBarAnimation progressBarAnimation = new ProgressBarAnimation(progressBar, 1000);
// Example 1
progressBarAnimation.setProgressAndRotation(newProgress, newRotation);
// Example 2
progressBarAnimation.setProgressOnly(newProgress);
// Example 3
progressBarAnimation.setRotationOnly(newRotation);
Similar with Kotlin on the UI thread
activity?.runOnUiThread {
ObjectAnimator.ofInt(binding.progressAudio, "progress", currentPosition)
.setDuration(100)
.start();
}
val animator = ValueAnimator.ofInt(0, 10)
animator.duration = 2000 //set duration in milliseconds
animator.addUpdateListener {
progressbar.progress = Integer.parseInt(animator.animatedValue.toString())
}
animator.start()
My solution with custom ProgressBar. You can specify animation (animationLength) legth and "smoothness" (animationSmoothness) using attributes (when you use it in XML layout)
AnimatedProgressBar.java
public class AnimatedProgressBar extends ProgressBar {
private static final String TAG = "AnimatedProgressBar";
private static final int BASE_ANIMATION_DURATION = 1000;
private static final int BASE_PROGRESS_SMOOTHNESS = 50;
private int animationDuration = BASE_ANIMATION_DURATION;
private int animationSmoothness = BASE_PROGRESS_SMOOTHNESS;
public AnimatedProgressBar(Context context) {
super(context);
init();
}
public AnimatedProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
obtainAnimationAttributes(attrs);
init();
}
public AnimatedProgressBar(Context context, AttributeSet attrs, int theme) {
super(context, attrs, theme);
obtainAnimationAttributes(attrs);
init();
}
private void obtainAnimationAttributes(AttributeSet attrs) {
for(int i = 0; i < attrs.getAttributeCount(); i++) {
String name = attrs.getAttributeName(i);
if (name.equals("animationDuration")) {
animationDuration = attrs.getAttributeIntValue(i, BASE_ANIMATION_DURATION);
} else if (name.equals("animationSmoothness")) {
animationSmoothness = attrs.getAttributeIntValue(i, BASE_PROGRESS_SMOOTHNESS);
}
}
}
private void init() {
}
#Override
public synchronized void setMax(int max) {
super.setMax(max * animationSmoothness);
}
public void makeProgress(int progress) {
ObjectAnimator objectAnimator = ObjectAnimator.ofInt(this, "progress", progress * animationSmoothness);
objectAnimator.setDuration(animationDuration);
objectAnimator.setInterpolator(new DecelerateInterpolator());
objectAnimator.start();
}}
values/attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="AnimatedProgressBar">
<attr name="animationDuration" format="integer" />
<attr name="animationSmoothness" format="integer" />
</declare-styleable>
</resources>

How to make the "code execution" waiting for the main thread?

I need to achieve the following: animation starts, wait until it is finished and then continue with the code execution. The problem is how to "pause" the code execution while the main thread is running. OnAnimationEnd() methods are not suitable.
I can use postDelayed(Runnable r, long milliseconds) and to put all my code in the runnable, but I am not sure it is the best way to do this. Also tried with thread.sleep(), this.wait(), and another instance of thread with runnable threadnew.sleep(), but I don't see the desired behavior: it seems that wait and sleep stop the animation and the code execution, not just the code execution.
public boolean onLongClick (View v)
{
if((v==textView2)&&(androidturn == false)&&(animationongoing == false))
{
androidturn = true;
animationongoing = true;
L.startAnimation(inFromRightAnimation);
L.postDelayed(new Runnable() {
public void run() {
L.clearAnimation();
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.FILL_PARENT, FrameLayout.LayoutParams.FILL_PARENT);
params.gravity = 0x50;
params.height =710;
L.setLayoutParams(params);
//L.layout(0,top,800,bottom);
animationongoing = false;
}
}, 500);
//here I need to stop the code execution for 500ms for animation to finish
imageButton1.setBackgroundResource(R.color.Red);
imageButton1.playSoundEffect(0);
try an AsyncTask
here's an example it won't block the ui thread
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
/*setProgressPercent(progress[0]);*/
}
protected void onPostExecute(Long result) {
/* call continute method here */
}
}
sr: http://developer.android.com/reference/android/os/AsyncTask.html
Separate the part to run after into its own method, then call it immediately or in the callback as appropriate.
public boolean onLongClick (View v)
{
if((v==textView2)&&(androidturn == false)&&(animationongoing == false))
{
androidturn = true;
animationongoing = true;
inFromRightAnimation.setAnimationListener(new Animation.AnimationListener()
{
// Other listeners omitted.
public void onAnimationEnd(Animation anim) {
L.clearAnimation();
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.FILL_PARENT, FrameLayout.LayoutParams.FILL_PARENT);
params.gravity = 0x50;
params.height =710;
L.setLayoutParams(params);
//L.layout(0,top,800,bottom);
animationongoing = false;
styleImageButton();
}
});
L.startAnimation(inFromRightAnimation);
}
else
{
styleImageButton();
}
}
private void styleImageButton()
{
imageButton1.setBackgroundResource(R.color.Red);
imageButton1.playSoundEffect(0);
}
In async code, you want to avoid forcing code to wait.
EDIT: I fixed my code to use onAnimationEnd.

Duration problem in a set of TranslateAnimation in Android

I have to animate an image as per (x,y) from one point to another point, then that point to another point and so on. I have around 300 points. For that I am using the following code.
/** code starts **/
public class CircleAnimation extends Activity implements OnPreparedListener {
/** Called when the activity is first created. */
ImageView imv1;
int totalAnimTime = 0;
double[][] points = {{258.8505,143.2875,67},
{259.642, 143.3665,120},
{260.429, 142.992,240},
{259.257, 139.3575,180},
......................
......................
{255.1335,146.8135,67},
{255.1395,146.794,67},
{255.0635,146.7785,67},
{254.9045,146.797,1200}
};
int j=0;
double loc[] = new double[2];
double x1 = 0,y1 = 0,x2 = 0,y2 = 0,anim_end=0, xstart=258.8505, ystart=143.2875, xnow, ynow;
protected boolean _active = true;
protected int _animTime = 66;
int k=1;
double xFactor = 1.779167, yFactor = 1.5;
private int displayWidth, displayHeight;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
imv1 = (ImageView)findViewById(R.id.imv1);
try{
LaunchInAnimation();
}catch(Exception e){
e.printStackTrace();
}
}
class LocalAnimationListener implements AnimationListener {
public void onAnimationEnd(Animation animation){
imv1.post(mLaunchSecondAnimation);
k = k ++;
}
public void onAnimationRepeat(Animation animation)
{
}
public void onAnimationStart(Animation animation)
{
}
};
private Runnable mLaunchSecondAnimation = new Runnable(){
public void run(){
LaunchInAnimation();
}
};
LocalAnimationListener MyAnimationListener = new LocalAnimationListener();
public void LaunchInAnimation() {
//animation
if(k<points.length) {
if(k==0) {
x1 = xstart;
y1 = ystart;
anim_end=1;
} else {
x1 = points[k-1][0];
y1 = points[k-1][1];
}
x2 = points[k][0];
y2 = points[k][1];
_animTime = (int) (points[k][2]);
TranslateAnimation translateAnimation = new TranslateAnimation((float)x1, (float)x2, (float)y1, (float)y2);
translateAnimation.setDuration(_animTime);
translateAnimation.setFillBefore(true);
translateAnimation.setFillAfter(true);
translateAnimation.setAnimationListener(MyAnimationListener);
imv1.startAnimation(translateAnimation);
totalAnimTime += _animTime;
}
}
}
/** code ends **/
To complete all the animations it should take totalAnimTime, but it is taking less time to complete. Moreover this time is varying from one device to another device. For this, I facing problem to synchronize other event. What is the problem in this code? Is there any other better way to control this type animation.
I was messing with this variance in performance myself, and then I switched to OpenGL to do all my rendering and have since found everything much smoother and simpler once you understand what you're doing.
If you feel OpenGL/SurfaceView is a little too dense for what you're asking for, try using Canvas?
Should be much easier with one of those because they're more stable from device to device. XML animations are simply tricking you into thinking they're animations, their actual X/Y don't ever really change. They have to "flicker" from their original X/Y to the "next step X/Y" right before drawn if I'm correct....

Categories

Resources