I've applied a Rotate animation to a button using ObjectAnimator, while the rotation seems to work; the pivot point still remains the top left corner of the button.
MainActivity
Button bt1;
float pivotX=0f;
float pivotY=0f;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt1 = (Button) findViewById(R.id.button1);
pivotX = bt1.getX() + (float)bt1.getWidth();// 500;// bt1.getHeight() ;
pivotY = bt1.getY() + (float)bt1.getHeight();// 500;// bt1.getWidth();
bt1.setPivotX(pivotX);
bt1.setPivotY(pivotY);
bt1.setOnClickListener(this);
}
private void rotate()
{
ObjectAnimator rotate = ObjectAnimator.ofFloat(bt1, View.ROTATION_X,360);
rotate.setDuration(2000);
AnimatorSet aSet = new AnimatorSet();
aSet.play(rotate);
aSet.start();
}
#Override
public void onClick(View v)
{
switch(v.getId())
{
case R.id.button1:
rotate();
break;
}
}
Edit:
bt1.getX and bt1.getY return 0. Will update once I know why.
Edit: This doesnt seem to work either.
#Override
public void onWindowFocusChanged(boolean hasFocus)
{
// TODO Auto-generated method stub
super.onWindowFocusChanged(hasFocus);
//Here you can get the size!
width = bt1.getWidth();
height = bt1.getHeight();
}
yea bt1.getWidth() can't get result but 0 in onCreate, because bt1 was not measured yet.you can have a try follow below:
button.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout(){
//here you can get size
width = button.getWidth();
height = button.getHeight();
}
});
getX() in OnCreate always give you a zero - it is not "implemented" on view
you have to wait for it. I use this loop to wait for definitely non-zero values:
new Thread(new Runnable() {
public void run() {
int count = 0;
do {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d(TAG, "checkin... count="+count);
count++;
} while (!(playStopButton.getWidth() > 0) && count < 100);
runOnUiThread(new Runnable() {
public void run() {
//here get X, get width etc
}
});
}
}).start();
Related
I created a simple app, just want when I click a button, the imageview will travel to another position.
Below is the code, but it seems that when I click the button, the imageview always begin with the original position, not the real position. Is there any problem with my code?
public class MainActivity extends Activity{
private ImageView iv;
private Button bt;
private AnimatorSet mAniSet;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ddd);
iv = (ImageView) this.findViewById(R.id.imageView1);
bt = (Button) this.findViewById(R.id.button1);
mAniSet = new AnimatorSet();
bt.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
int pointOnScreen[] = new int[2];
iv.getLocationOnScreen(pointOnScreen);
ObjectAnimator AniTranslationX = ObjectAnimator.ofFloat(iv, View.TRANSLATION_X, pointOnScreen[0]+100);
mAniSet.playTogether(AniTranslationX);
mAniSet.setTarget(iv);
mAniSet.setDuration(200).start();
}
});
}
}
If you create a ObjectAnimator.ofFloat(Object, Property, values) and there is only one value, so the origin of the animation will be 0f.
You can find the source into the class android.animation.KeyFrameSet and the following method:
public static KeyframeSet ofFloat(float... values) {
boolean badValue = false;
int numKeyframes = values.length;
FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
if (numKeyframes == 1) {
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
if (Float.isNaN(values[0])) {
badValue = true;
}
} else {
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]);
for (int i = 1; i < numKeyframes; ++i) {
keyframes[i] =
(FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);
if (Float.isNaN(values[i])) {
badValue = true;
}
}
}
if (badValue) {
Log.w("Animator", "Bad value (NaN) in float animator");
}
return new FloatKeyframeSet(keyframes);
}
You can see, with only one value, the start of the animation is 0f (keyframes[0]).
If you put 2 values, your animation will start from the first value and stop at the second:
ObjectAnimator AniTranslationX = ObjectAnimator.ofFloat(iv, View.TRANSLATION_X, pointOnScreen[0], pointOnScreen[0] + 100);
With 3 or more values, the animation will reach all these values over the time of the animation.
So, I'm experimenting trying to create a circular reveal on API level 21 on a TextView but I keep getting this error. At first I thought it had something to do with the lifecycle of the fragment I was attempting it but then I just tried the same thing in an activity and it still wouldn't work.
Here's the code:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Window w = getWindow();
w.setFlags(
WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
w.setStatusBarColor(Color.parseColor("#0277bd"));
setContentView(R.layout.activity_main);
TextView tv = (TextView) findViewById(R.id.text);
int a = (tv.getLeft() + tv.getRight()) / 2;
int b = (tv.getTop() + tv.getBottom()) / 2;
int radius = tv.getWidth();
Animator anim = ViewAnimationUtils.createCircularReveal(tv, a, b, 0, radius);
anim.start();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
return super.onCreateOptionsMenu(menu);
}
}
It's still early days so I can't really find any answers about this. Any ideas?
You're getting the error because the view you passed in hasn't been measured and laid out on the screen yet. ViewAnimationUtils.createCircularReveal needs the target view to be measured to calculate the animation. You'll also find that your variables a and b are always 0.
If you want to experiment, create the animation and start it within a button click listener. Here's an example using your code:
Button button = (Button) findViewById(R.id.your_button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
TextView tv = (TextView) findViewById(R.id.text);
int a = (tv.getLeft() + tv.getRight()) / 2;
int b = (tv.getTop() + tv.getBottom()) / 2;
int radius = tv.getWidth();
Animator anim = ViewAnimationUtils.createCircularReveal(tv, a, b, 0, radius);
anim.start();
}
});
You can use Runnable to do the animation. The Runnable will run after the view's creation. No need to post delay.
view.post(new Runnable()
{
#Override
public void run(){
//create your anim here
}
});
Or you can do this.
tv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
tv.getViewTreeObserver().removeGlobalOnLayoutListener(this);
} else {
tv.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
Animator anim = ViewAnimationUtils.createCircularReveal(tv, a, b, 0, radius);
anim.start();
}
});
Adding GlobalLayoutListener to wait for the view to be inflated worked for me.
Or you can do this.
tv.postDelayed(new Runnable() {
#Override
public void run() {
//start your animation here
}
}, 1000);
I have a TextView showing integer value. Integer value is transferred from previous activity, and I want to add nice animation. I want to if for example int value is 73, I want textView to increase shown number by 1 until 73, so it would be 1-2-3-4-5...etc etc.
How can I do this?
The best solution in my opinion is to use this method :
public void animateTextView(int initialValue, int finalValue, final TextView textview) {
ValueAnimator valueAnimator = ValueAnimator.ofInt(initialValue, finalValue);
valueAnimator.setDuration(1500);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
textview.setText(valueAnimator.getAnimatedValue().toString());
}
});
valueAnimator.start();
}
Here is a simple function to animate the text of a textView according to an initial and final value
public void animateTextView(int initialValue, int finalValue, final TextView textview) {
DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator(0.8f);
int start = Math.min(initialValue, finalValue);
int end = Math.max(initialValue, finalValue);
int difference = Math.abs(finalValue - initialValue);
Handler handler = new Handler();
for (int count = start; count <= end; count++) {
int time = Math.round(decelerateInterpolator.getInterpolation((((float) count) / difference)) * 100) * count;
final int finalCount = ((initialValue > finalValue) ? initialValue - count : count);
handler.postDelayed(new Runnable() {
#Override
public void run() {
textview.setText(String.valueOf(finalCount));
}
}, time);
}
}
I think this project in github is what you want: https://github.com/sd6352051/RiseNumber
The RiseNumberTextView extends TextView and use the ValueAnimator to implement the rising number effect.
This is a Kotlin code for incrementing from initial value to final value over a duration of time. Here I have used duration of 5 sec.
fun animateTextView(initialValue: Int, finalValue: Int, textView: TextView) {
val valueAnimator = ValueAnimator.ofInt(initialValue, finalValue)
valueAnimator.duration = 5000 // 5 sec
valueAnimator.addUpdateListener { valueAnimator -> textView.text = valueAnimator.animatedValue.toString() }
valueAnimator.start()
}
use this code in Utilities and call the method accordingly with required parameters.
try this code..showing increment value with animation
public class MainActivity extends Activity implements AnimationListener {
private TextView textView;
AlphaAnimation fadeIn, fadeOut;
private static int count = 0, finalValue = 20;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.demo);
textView = (TextView) findViewById(R.id.textView);
fadeIn = new AlphaAnimation(0.0f, 1.0f);
fadeOut = new AlphaAnimation(1.0f, 0.0f);
fadeIn.setDuration(1000);
fadeIn.setFillAfter(true);
fadeOut.setDuration(1000);
fadeOut.setFillAfter(true);
fadeIn.setAnimationListener(this);
fadeOut.setAnimationListener(this);
textView.startAnimation(fadeIn);
textView.startAnimation(fadeOut);
}
#Override
public void onAnimationEnd(Animation arg0) {
// TODO Auto-generated method stub
Log.i("mini", "Count:" + count);
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
textView.setText("" + count);
}
});
if (count == finalValue) {
textView.setText("" + finalValue);
} else {
++count;
textView.startAnimation(fadeIn);
textView.startAnimation(fadeOut);
}
}
#Override
public void onAnimationRepeat(Animation arg0) {
// TODO Auto-generated method stub
}
#Override
public void onAnimationStart(Animation arg0) {
// TODO Auto-generated method stub
}
}
i want to touch button and drag into other button position you can get clear idea by this image.
Guiding Image
Please help me
I Also Found This very helpful.
Touch and drag image in android
but i want to drag to other button position not some were else on screen.i don't have any idea how i would detect button is entered in other button dimensions.
So far i am doing is just animation but i don't want just straight forward moving button by click.
i want user to move by himself button to other button position.
Code
public class AnimationActivity extends Activity implements OnClickListener {
public Button btn_a1, btn_a2;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mainsec);
btn_a1 = (Button) findViewById(R.id.btn_a1);
btn_a2 = (Button) findViewById(R.id.btn_a2);
btn_a1.setOnClickListener(this);
btn_a2.setOnClickListener(this);
}
#Override
public void onClick(final View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.btn_a1: {
int direction = -1;
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
RelativeLayout.LayoutParams absParams = (RelativeLayout.LayoutParams) btn_a1
.getLayoutParams();
final float xDelta = (displaymetrics.widthPixels / 2)
- absParams.leftMargin - (btn_a1.getWidth() / 2);
final Animation animation = new TranslateAnimation(0, xDelta
* direction, 0, 0);
AnimationListener animationOutListener = new AnimationListener() {
public void onAnimationEnd(Animation animation) {
btn_a2.setBackgroundDrawable(R.id.blank);// Unselect
}
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
btn_a2.setBackgroundDrawable(R.id.red);// Select
}
};
animation.setAnimationListener(animationOutListener);
animation.setDuration(1000);
btn_a2.startAnimation(animation);
break;
}
case R.id.btn_a2: {
int direction = 1;
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
RelativeLayout.LayoutParams absParams = (RelativeLayout.LayoutParams) btn_a1
.getLayoutParams();
final float xDelta = (displaymetrics.widthPixels / 2)
- absParams.leftMargin - (btn_a1.getWidth() / 2);
final Animation animation = new TranslateAnimation(0, xDelta
* direction, 0, 0);
AnimationListener animationOutListener = new AnimationListener() {
public void onAnimationEnd(Animation animation) {
btn_a1.setBackgroundDrawable(R.id.blank);// Unselect
}
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
btn_a1.setBackgroundDrawable(R.id.red);// Select
}
};
animation.setDuration(1000);
btn_a1.startAnimation(animation);
break;
}
}
}
How about this:
You would have to evaluate the buttons parentViews onTouchEvents, and if you hit it, you can start the onClick method associated with the button, or when you lift your finger, what ever suits your app.
But while finger down/move you can just change the buttons coordinates and trigger a redraw ont he parent view.
You might have to create a new View that supports moving Buttons. I dont know if you can do that inside of a layout.
I am doing a project using TranslateAnimation in Android. In that I am translating images successfully but I have to add onClickListener to the images. That means I have click the images during translating and get their values but I am getting the onClick action on the images.
I am using following code:
public class SampleGame extends Activity implements OnClickListener {
int x10, x20, y10, y20;
ImageView img;
Button animation;
Handler transHandler;
RelativeLayout layout;
Random rand;
int mSpeedX, mSpeedY;
int width, height;
Thread thread;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
layout = (RelativeLayout) findViewById(R.id.layout);
animation = (Button) findViewById(R.id.animation);
animation.setOnClickListener(this);
rand = new Random();
width = getWindow().getWindowManager().getDefaultDisplay().getWidth() - 20;
height = getWindow().getWindowManager().getDefaultDisplay().getHeight() - 70;
x10 = width - rand.nextInt(width);
y10 = height;
x20 = width;
y20 = height - rand.nextInt(height);
thread = new Thread();
img.setOnClickListener(this);
}
public void onPause() {
super.onPause();
thread = null;
}
#Override
public void onClick(View v) {
if (v.equals(img)) {
Log.e("img clicked :", "yaaaaaaaaa");
}
if (v.equals(animation)) {
animation.setVisibility(View.INVISIBLE);
callTransform();
}
}
public void callTransform() {
if (thread != null) {
thread = new Thread() {
public void run() {
// Log.e("X1 value :",String.valueOf(x10));
// Log.e("X2 value :",String.valueOf(x20));
// Log.e("Y1 value :",String.valueOf(y10));
// Log.e("Y2 value :",String.valueOf(y20));
transformAnimation(x10, x20, y10, y20, img, 4000);
try {
Thread.sleep(4000);
} catch (Exception e) {
}
// Message msg=transHandler.obtainMessage();
// transHandler.sendMessage(msg);
x10 = x20;
y10 = y20;
if (x10 == width) {
x20 = width - rand.nextInt(width);
y20 = 0;
} else if (y10 == 0) {
x20 = 0;
y20 = height - rand.nextInt(height);
} else if (x10 == 0) {
x20 = width - rand.nextInt(width);
y20 = height;
} else if (y10 == height) {
x20 = width;
y20 = height - rand.nextInt(height);
}
callTransform();
}
};
thread.start();
}
}
public void transformAnimation(int xFrom, int xTo, int yFrom, int yTo, final ImageView image, int time) {
TranslateAnimation anim = new TranslateAnimation(xFrom, xTo, yFrom, yTo);
anim.setDuration(time);
image.setAnimation(anim);
}
}
and I tried the following example also - 2D-Tutorial Example.
But in this also I didn't onClick action for images.
So how to get the onClick action on image during translation?
or
Is there any other way to translate the image with on click action?
Thanks in Advance.
during animation the object remains in its original position but it animates translation so you would need to update the Layout Parameters manually during animation