I want to create an android project. Which there is a layout that I want it to move smoothly on another layout. I have tried to use thread in order to do this. But in the result of my code, the layout jumps to its final position and do not move smoothly from the offset to its destination.
abs1 = (AbsoluteLayout) findViewById(R.id.absoluteLayout2);
ImageButton ib1 = (ImageButton) findViewById(R.id.imageButton1);
ib1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
Runnable r = new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
try {
display(100);
display(100);
display(100);
display(100);
display(100);
display(100);
display(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void display(int i) throws InterruptedException {
AbsoluteLayout.LayoutParams param = (AbsoluteLayout.LayoutParams) abs1
.getLayoutParams();
param.x = param.x + 10;
// param.y=param.x+20;
abs1.setLayoutParams(param);
if (Thread.interrupted()) {
throw (new InterruptedException());
}
Thread.sleep(i);
}
};
r.run();
main file:
<AbsoluteLayout
android:id="#+id/absoluteLayout2"
android:layout_width="107dp"
android:layout_height="308dp"
android:layout_x="10dp"
android:layout_y="12dp"
android:background="#color/red" >
<ImageButton
android:id="#+id/imageButton1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_x="0dp"
android:layout_y="0dp"
android:background="#null"
android:src="#drawable/calendar" />
EDIT: this is available starting from API 11
Just use an ObjectAnimator for that:
ObjectAnimator moveToSide = ObjectAnimator.ofFloat(myView, "translationX", 0f, 400f);
moveToSide.setDuration(700);
moveToSide.start();
Just try it out with different float values. Now, it starts from it's original position to 400f along the X-axis.
Afterwards it will stay in this position. You could also add an AnimatorListener if you want to do some stuff on the start or at the end.
moveToSide.addListener(new AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
}
#Override
public void onAnimationCancel(Animator arg0) {
}
});
Your Runnable is actually running on Android's UI thread.
So sleep() will block UI's drawing process, show the view on final position.
Use a Thread to wrap it.
(new Thread(new Runnable() {
#Override
public void run() {
// your code
}
}
})).start();
Then, remember that updating views from non-UI thread is forbidden.
You should use runOnUiThread to update views.
runOnUiThread(new Runnable() {
#Override
public void run() {
display(100);
}
}
Maybe, use Android's Animation class is a better way to do this.
Related
In my app, I have an animation. I want to wait until the animation finish to continue the rest of the codes. I am trying to use .hasEnded as follows but doesn't work. I know there are some other technics to achieve this but I want to know what's wrong with this code. It is going into the endless loop at while loop
myplayer= AnimationUtils.loadAnimation(getApplicationContext(),R.anim.myanim1);
textView_title.setAnimation(myplayer);
while (!myplayer.hasEnded()){
}
You can use a new Thread to test the hasEnded:
Animation myplayer= AnimationUtils.loadAnimation(getApplicationContext(),R.anim.myanim1);
.....
//start the animation
Thread thread = new Thread(){
#Override
public void run() {
super.run();
boolean flag = true;
while (flag){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d(TAG, "run: " + myplayer.hasEnded());
if(myplayer.hasEnded()){
flag = false;
}
}
}
};
thread.start();
could use the following code to listen of Animation:
Animation myplayer= AnimationUtils.loadAnimation(getApplicationContext(),R.anim.myanim1);
myplayer.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
textView_title.setAnimation(myplayer);
Im rotating a LinearLayout, using an ObjectAnimator. Clicking the button causes the LinearLayout to rotate 360(degrees) with the bottom part as the Pivot.
After the Layout completes the rotation, it leaves back a 'trail'/black mark and the complete view looks odd. How do I avoid this from happening? After the Layout completes the 360 animation, I want the view to look as it did in the beginning (clean basically).
Is there a view.refresh or update command im suppose to call somewhere?
1)How do I have a clean looking view at the end?
2)When the image is is in the intermediatestate, why does the back-part appear black? How do I get that to look while(ie,color of the relative layout)?
InitialState>IntermediateState>FinalState:
MainActivity
Button bt1;
float pivotX=0f;
float pivotY=0f;
int a=0;
float width,height;
ViewGroup mContainer=null;
Thread t;
private Handler mHandler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt1 = (Button) findViewById(R.id.button1);
mContainer = (ViewGroup) findViewById(R.id.container);
bt1.setOnClickListener(this);
t=new Thread()
{
#Override
public void run()
{
try {
while(true)
{
relativeLayout.postInvalidate();
}
} catch (Exception e) {
// TODO: handle exception
}
}
};
}
#Override
public void onWindowFocusChanged(boolean hasFocus)
{
super.onWindowFocusChanged(hasFocus);
//Here you can get the size!
width = mContainer.getWidth();
height = mContainer.getHeight();
pivotX = mContainer.getPivotX()+width;
pivotY = mContainer.getPivotY()+height;
mContainer.setPivotX(pivotX);
mContainer.setPivotY(pivotY);
}
private void rotate()
{
a -=360;
ObjectAnimator rotate = ObjectAnimator.ofFloat(mContainer, View.ROTATION_X,a);
rotate.setDuration(2000);
AnimatorSet aSet = new AnimatorSet();
aSet.play(rotate);
aSet.start();
mHandler.post(new Runnable()
{
#Override
public void run()
{
b+=1;
relativeLayout.invalidate();
relativeLayout.postInvalidate();
bt1.setText(Integer.toString(b));
}
});
rotate.addListener(new AnimatorListener()
{
#Override
public void onAnimationStart(Animator animation) {
// TODO Auto-generated method stub
//relativeLayout.invalidate();
t.start();
}
#Override
public void onAnimationRepeat(Animator animation) {
// TODO Auto-generated method stub
}
#Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
//mContainer.invalidate();
//relativeLayout.invalidate();
try {
t.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void onAnimationCancel(Animator animation) {
// TODO Auto-generated method stub
}
});
}
#Override
public void onClick(View v)
{
switch(v.getId())
{
case R.id.button1:
rotate();
break;
}
}
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context=".MainActivity" >
<LinearLayout
android:id="#+id/container"
android:layout_width="fill_parent"
android:layout_height="200dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:background="#140A1F"
android:orientation="horizontal" >
</LinearLayout>
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/container"
android:layout_centerHorizontal="true"
android:layout_marginTop="80dp"
android:text="Rotate" />
</RelativeLayout>
Edit: Added a thread.
**Edit2:**** Added a handler and commented out the thread
Adding this to the code fixes the view once the animation is competed, but the intermediate stage still looks the same. Will update this once I figure that out.
rotate.addListener(new AnimatorListener()
{
#Override
public void onAnimationStart(Animator animation) {
// TODO Auto-generated method stub
relativeLayout.invalidate();
}
#Override
public void onAnimationRepeat(Animator animation) {
// TODO Auto-generated method stub
}
#Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
//mContainer.invalidate();
relativeLayout.invalidate();
}
#Override
public void onAnimationCancel(Animator animation) {
// TODO Auto-generated method stub
}
});
I have two animations xml file, i use these in java class. I want my animation repeats 1000 msec. I write this code but when i run this program, animation not repeat. I use Timer in repeatAnim() function but i think this is not work in 1000msec.
relative.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/linearLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:id="#+id/txt1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/txt1"
></TextView>
<ImageButton
android:id="#+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/pic1"
android:layout_gravity="center"/>
</LinearLayout>
SwitchClass.java:
public class SwitchClass extends Activity implements AnimationListener{
Animation animation1;
Animation animation2;
boolean frontButton=true;
ImageButton btn;
Timer timer;
TimerTask mTimerTask;
Handler handler=new Handler();
boolean repeat=true;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.relative);
animation1=AnimationUtils.loadAnimation(this, R.anim.to_middle);
animation1.setAnimationListener(this);
animation2=AnimationUtils.loadAnimation(this, R.anim.from_middle);
animation2.setAnimationListener(this);
btn=(ImageButton)findViewById(R.id.btn2);
btn.setOnClickListener(onClickListener);
repeatAnimation();
repeatAnim();
}
private OnClickListener onClickListener=new OnClickListener(){
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent=new Intent(SwitchClass.this,AnimClass.class);
startActivity(intent);
}
};
#Override
public void onAnimationEnd(Animation animation) {
// TODO Auto-generated method stub
if(animation==animation1){
if(frontButton){
btn.setImageResource(R.drawable.pic2);
}
else{
btn.setImageResource(R.drawable.pic1);
}
btn.clearAnimation();
btn.setAnimation(animation2);
btn.startAnimation(animation2);
}
else{
frontButton=!frontButton;
btn.setEnabled(true);
}
}
#Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
#Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
public void repeatAnim(){
timer=new Timer();
mTimerTask=new TimerTask(){
public void run(){
handler.post(new Runnable(){
public void run(){
repeatAnimation();
}
});
}
};
timer.schedule(mTimerTask, 1000);
}
public void repeatAnimation(){
btn.setEnabled(false);
btn.clearAnimation();
btn.setAnimation(animation1);
btn.startAnimation(animation1);
}
}
Thanks for advise.Cheers
What about to use use Handler, see below:
private int mSampleDurationTime = 1000; // 1 sec
private boolean continueToRun = true;
Handler mHandler = new Handler();
mHandler.postDelayed(mRunnable, mSampleDurationTime);
where mRunnable is your task:
private final Runnable mRunnable = new Runnable() {
//...
public void run() {
// do your stuff here, like update
// this block of code you going to reach every second
if(continueToRun == true){
mHandler.postDelayed(mRunnable, mSampleDurationTime);
}
}
...
};
First time you call postDelayed and invoke new Runnable(). After, if you want to continue,
call the same method into run()
why not just use handler.postDelayed(runnable, delay) instead of using a timer?
Also, try using animation1.startNow() after setting the animation on the button, and call btn.invalidate() after setting the animation to redraw the view
Here is the situation. My Activity is running, and I call a function to start an animation. Once this animation finishes, I need to wait for another 2 seconds, then continue the process normally. What do you suggest I do?
The OnAnimationEnd does not help my case by the time I reach the end of iteration, my process has already returned from the calling function and continued processing.
What do you think I do? Do thread.sleep (duration of animation + 2 sec)?
Thanks
EDIT:
OK I thought maybe I should explain what I am doing in code
I have the following code
Public class myclassActivity extends Activity{
..
.
.
.
public void runGame(){
player1.startAnimating();
player2.start Animating();
player3.startAnimating();
updateStatus();
runGame();
}
}
So as you can see my activity keeps calling startAnimating for each player. In which some work and then animation for 1 second is done.
I don't want player2.startAnimation to start untill the player1.startAnimation is completed and so on for the rest of the code.
Currently what happens is that the code executes fully and rerun again while the animation is still running. Pleasee any help on this?
observe this code it is help full you.
public class PlayersActivity extends Activity {
ImageView I1,I2;
Button B;
Animation T1,T2;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
I1=(ImageView)findViewById(R.id.i1);
I2=(ImageView)findViewById(R.id.i2);
B=(Button)findViewById(R.id.b1);
B.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
T1=new TranslateAnimation(0,100,0,0);
T1.setDuration(1000);
I1.startAnimation(T1);
T1.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
#Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
#Override
public void onAnimationEnd(Animation animation) {
T2=new TranslateAnimation(0,100,0,0);
T2.setDuration(1000);
T2.setStartOffset(2000);
I2.startAnimation(T2);
T2.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
#Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
#Override
public void onAnimationEnd(Animation animation) {
T1.setStartOffset(2000);
I1.startAnimation(T1);
}
});
}
});
}
});
}
}
Suppose you will start this two methods after completed player3, you are placing player3 onAnimationEnd(){ updateStatus(); runGame();}
Use postDelayed function to run something after exact delay. For example (2 sec delay):
LinearLayout.postDelayed(new Runnable() {
public void run() {
//Do something
}
}, 2000);
how about passing caller instance by
player1.startAnimating(this)
and then call method like
myclassActivity#animationFinished(this)
on finishing animation of player1/2? then
void animationFinished(Player p) {
if (p==player1) {
player2.start();
} else if (p==player2) {
player3.start();
}
}
or something
I've got an activity in which several Views animate. The animations are triggered when a RelativeLayout containing a few images is clicked. It's set up in onCreate() like this:
mContainer.setOnClickListener(new ContainerClicked());
And the ContainerClicked() class looks like this:
private class ContainerClicked implements OnClickListener {
#Override
public void onClick(View arg0) {
Log.i(TAG, "TEST!");
mSomeButton.setOnClickListener(null);
mSomeButton.setEnabled(false);
mAnotherButton.setOnClickListener(null);
mAnotherButton.setEnabled(false);
mYetAnotherButton.setOnClickListener(null);
mYetAnotherButton.setEnabled(false);
mContainer.setOnClickListener(null);
if (mLogo.getVisibility() == View.VISIBLE)
new AnimateToParty().execute();
else
new AnimateFromParty().execute();
}
}
This works, and animates everything just how I want it.
AnimateToParty() looks like this:
private class AnimateToParty extends AsyncTask<Void, Integer, Void> {
#Override
protected void onProgressUpdate(final Integer... values) {
final View theView = findViewById(values[0]);
if (!(values[0] == mBackgroundImage.getId() || values[0] == mContainer
.getId())) {
final Animation animation = AnimationUtils.loadAnimation(
DashboardActivity.this, values[1]);
animation.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation arg0) {
}
#Override
public void onAnimationRepeat(Animation arg0) {
}
#Override
public void onAnimationEnd(Animation arg0) {
theView.setVisibility(View.INVISIBLE);
}
});
theView.startAnimation(animation);
} else if (values[0] == mBackgroundImage.getId()) {
TransitionDrawable transition = (TransitionDrawable) theView
.getBackground();
transition.startTransition(getResources().getInteger(
android.R.integer.config_mediumAnimTime));
} else {
TranslateAnimation animation = new TranslateAnimation(0, 0, 0,
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-60, getResources().getDisplayMetrics()));
animation.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation arg0) {
}
#Override
public void onAnimationRepeat(Animation arg0) {
}
#Override
public void onAnimationEnd(Animation arg0) {
LayoutParams lp = (LayoutParams) mContainer
.getLayoutParams();
lp.bottomMargin = 0;
RelativeLayout parent = (RelativeLayout) mContainer
.getParent();
mSomeButton.setVisibility(View.GONE);
mAnotherButton.setVisibility(View.GONE);
mYetAnotherButton.setVisibility(View.GONE);
mLogo.setVisibility(View.GONE);
// mContainer.setLayoutParams(lp);
// This caused a visible flicker, so I went with the solution below.
parent.removeView(mContainer);
parent.addView(mContainer, lp);
}
});
animation.setDuration(1000);
mContainer.startAnimation(animation);
}
}
#Override
protected Void doInBackground(Void... arg0) {
try {
publishProgress(mContainer.getId());
publishProgress(mLogo.getId(), R.anim.slide_out_up);
Thread.sleep(100);
publishProgress(mSomeButton.getId(), R.anim.slide_out_left);
Thread.sleep(110);
publishProgress(mAnotherButton.getId(), R.anim.slide_out_left);
Thread.sleep(120);
publishProgress(mYetAnotherButton.getId(), R.anim.slide_out_left);
Thread.sleep(130);
publishProgress(mBackgroundImage.getId());
Thread.sleep(550);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
mContainer.setOnClickListener(new LighterClicked());
}
}
The class above animates some buttons and the logo out of the way, and then reveals the container. In order to keep it there, I change it's layoutparams. Just changing them produces a visible flicker where the container jumps 60 dip up for about one frame (the animation doesn't seem to be quite finished), before settling where I want it. I read somewhere to remove it from its parent and put it back in, and this does not produce the same flicker. However, now the rebinding of the onclicklistener does not work!
I've tried just about everything, and I just now noticed that every click that didn't "go through" fires if I press the home button and open the application again.
Is there a better way to avoid the "flicker"? A better way to do the animations? (I'm quite new at animating views) Why do the click-events fire when I reopen the application?
To avoid the flicker you are seeing, you have to call clearAnimation() at the start of onAnimationEnd
#Override
public void onAnimationEnd(Animation arg0) {
theView.clearAnimation()
...
}