I have tried to understand from other questions what to do but I am stuck.
I am using animation to animate a move made by a player (card game).
Problem is that while the animation is happening it continues and starts the next player's move.
This the object that does the animation
final class MyAnimation implements AnimationListener {
private ImageView animationSource;
private ImageView animationTarget;
private int animationDuration;
private int animationDelay;
private int cardResource;
MyAnimation(ImageView animationSource, ImageView animationTarget, int cardResource, int animationDuration,
int animationDelay){
this.animationSource = animationSource;
this.animationTarget = animationTarget;
this.cardResource = cardResource;
this.animationDuration = animationDuration;
this.animationDelay = animationDelay;
}
public void animate(){
int sourceCoords[] = {0,0};
int targetCoords[] = {0,0};
int xDelta;
int yDelta;
animationSource.getLocationOnScreen(sourceCoords);
animationTarget.getLocationOnScreen(targetCoords);
xDelta = targetCoords[0] - sourceCoords[0];
yDelta = targetCoords[1] - sourceCoords[1];
TranslateAnimation cardDealingAnimation = new TranslateAnimation(0, xDelta, 0, yDelta);
cardDealingAnimation.setAnimationListener(this);
cardDealingAnimation.setDuration(animationDuration);
cardDealingAnimation.setStartOffset(animationDelay);
animationSource.startAnimation(cardDealingAnimation);
}
#Override
public void onAnimationEnd(android.view.animation.Animation animation) {
animationTarget.setImageResource(cardResource);
animationTarget.setVisibility(View.VISIBLE);
inAnimation = false;
completionMonitor.notifyAll();
}
#Override
public void onAnimationRepeat(android.view.animation.Animation animation) {
}
#Override
public void onAnimationStart(android.view.animation.Animation animation) {
inAnimation = true;
}
}
and the code that invokes it:
private static void animate(final ImageView animationSource, final ImageView animationTarget, final int cardResource,
final int animationDuration, final int animationDelay)
{
synchronized(completionMonitor){
runOnUiThread(new Runnable(){
#Override
public void run() {
MyAnimation anim = (new CardAnimator()).new MyAnimation(animationSource,animationTarget, cardResource,
animationDuration, animationDelay);
anim.animate();
}
});
}
synchronized(completionMonitor){
try {
completionMonitor.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I effectively need it to wait until the animation completes before returning.
I've tried using synchronize just can't get it right.
It either freezes on me or crashes.
Related
I wrote a little STT-functionality, with a floating button that is pulsating after being clicked on to notify that the app is listening. This works quite well so far with the one annoying behavior that my floating button does not return to its original size in some cases.
The animation increases and decreases the size of the button, and I guess it gets stuck in the increased state, hence the randomness of this behavior. I just can't figure out how to catch that and set the size to the original one.
Action Listener of my Button:
private View.OnTouchListener setVoiceButtonOnClick()
{
return new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
if(!voiceButton.isInitialized())
voiceButton.initAnimationValues();
voiceButton.setPressed(true);
listen();
}
return true;
}
};
}
My Button extends FloatingActionButton, and does the following:
public class FloatingVoiceButton extends FloatingActionButton
{
public static final float DEFAULT_ANIMATION_FACTOR = 1.2f;
private boolean isInitialized = false;
private int originalHeight;
private int originalWidth;
private boolean isAnimationRunning;
private ObjectAnimator animator;
public FloatingVoiceButton(Context context)
{
super(context);
}
public void initAnimationValues()
{
isInitialized = true;
isAnimationRunning = false;
originalHeight = getMeasuredHeight();
originalWidth = getMeasuredWidth();
animator = ObjectAnimator.ofPropertyValuesHolder(
this,
PropertyValuesHolder.ofFloat("scaleX", DEFAULT_ANIMATION_FACTOR),
PropertyValuesHolder.ofFloat("scaleY", DEFAULT_ANIMATION_FACTOR));
animator.setDuration(200);
animator.setRepeatCount(ObjectAnimator.INFINITE);
animator.setRepeatMode(ObjectAnimator.REVERSE);
}
public boolean isInitialized()
{
return isInitialized;
}
public void resetButtonSize()
{
setMeasuredDimension(originalWidth, originalHeight);
}
public boolean isAnimationRunning()
{
return isAnimationRunning;
}
public void animate(boolean doAnimation)
{
isAnimationRunning = doAnimation;
if(doAnimation)
animator.start();
else
{
animator.end();
setPressed(false);
resetButtonSize();
//destroyDrawingCache(); tried these without success
//postInvalidate();
}
}
}
Finally I am controlling the button the start and end of the animation with my RecognitionListener:
public class InputVoiceRecognitionListener implements RecognitionListener
{
private EditText targetEditText;
private String originalContent;
private final String DELIMITER = "\n\n";
private FloatingVoiceButton button;
public InputVoiceRecognitionListener(EditText editText, FloatingVoiceButton button)
{
targetEditText = editText;
originalContent = editText.getText().toString();
this.button = button;
}
#Override
public void onReadyForSpeech(Bundle params)
{
button.animate(true);
}
#Override
public void onBeginningOfSpeech()
{
originalContent = targetEditText.getText().toString();
}
#Override
public void onRmsChanged(float rmsdB)
{}
#Override
public void onBufferReceived(byte[] buffer)
{}
#Override
public void onEndOfSpeech()
{
if(button.isAnimationRunning())
button.animate(false);
}
#Override
public void onError(int error)
{
if(button.isAnimationRunning())
button.animate(false);
}
#Override
public void onResults(Bundle results)
{
setRecognizedText(results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION));
}
#Override
public void onPartialResults(Bundle partialResults)
{
setRecognizedText(partialResults.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION));
}
#Override
public void onEvent(int eventType, Bundle params)
{
}
private void setRecognizedText(ArrayList<String> matches)
{
String result = "";
if(matches != null)
result = matches.get(0);
if((originalContent.trim()).length() > 0)
{
if(!originalContent.endsWith("\n\n"))
result = originalContent + DELIMITER + result;
else result = originalContent + result;
}
targetEditText.setText(result);
targetEditText.setSelection(result.length());
}
}
EDIT
This did it for me:
resettingAnimator = ObjectAnimator.ofPropertyValuesHolder(
this,
PropertyValuesHolder.ofFloat("scaleX", 1.0f),
PropertyValuesHolder.ofFloat("scaleY", 1.0f));
resettingAnimator.setDuration(0);
resettingAnimator.setRepeatCount(1);
and calling resettingAnimator.start(); when I finish my main animation.
Simple solution to this problem is that you define another animation after stopping your repeating one.
I just can't figure out how to catch that and set the size to the original one.
You, that is View, does know what is the "original" size, its the size of the scale factor 1f. So after stopping repeating animation just make another animations to set scale to 1f
PropertyValuesHolder.ofFloat("scaleX", 1f)
PropertyValuesHolder.ofFloat("scaleY", 1f))
This animation will run always, but will not be visible if your button is already at "normal" size.
With this in mind I would recommend that you use some other flag than isAnimationRunning(), either by some state (ex. selected) of your Fab, or some manually set arbitrary boolean.
I am using the WallpaperService class to set a live wallpaper on the device.
I want to implement security on the system screen (to prevent screenshot or recording) where the 'Set Wallpaper' button shows up by the android system.
So far, I have found one method of SurfaceView class - surfaceview.setSecure(boolean value)
But, I am not able to get the instance of the SurfaceView inside my class.
Please suggest some workaround to get the instance of this class.
My Code-
public class LiveWallpaperService extends WallpaperService {
private int mDeviceWidth, mDeviceHeight;
private int mAnimationWidth, mAnimationHeight;
#Override
public Engine onCreateEngine() {
Movie movie = null;
// Some Code here
return new GIFWallpaperEngine(movie);
}
private class GIFWallpaperEngine extends Engine {
private final int frameDuration = 24;
private SurfaceHolder holder;
private final Movie movie;
private boolean visible;
private final Handler handler;
private final Runnable drawGIF = new Runnable() {
public void run() {
draw();
}
};
public SurfaceView getSurfaceView(){
// How to find the SurfaceView object here?
}
GIFWallpaperEngine(Movie movie) {
this.movie = movie;
handler = new Handler();
}
#Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
this.holder = surfaceHolder;
}
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.onSurfaceChanged(holder, format, width, height);
mDeviceWidth = width;
mDeviceHeight = height;
}
private void draw() {
if (movie != null) {
try {
if (visible) {
Canvas canvas = holder.lockCanvas();
canvas.save();
final float scaleFactorX = mDeviceWidth / (mAnimationWidth * 1.f); //608 is image width
final float scaleFactorY = mDeviceHeight / (mAnimationHeight * 1.f);
// Adjust size and position to fit animation on the screen
canvas.scale(scaleFactorX, scaleFactorY); // w,h Size of displaying Item
movie.draw(canvas, 0, 0); // position on x,y
canvas.restore();
holder.unlockCanvasAndPost(canvas);
movie.setTime((int) (System.currentTimeMillis() % movie.duration()));
handler.removeCallbacks(drawGIF);
handler.postDelayed(drawGIF, frameDuration);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
#Override
public void onVisibilityChanged(boolean visible) {
this.visible = visible;
if (visible) {
handler.post(drawGIF);
} else {
handler.removeCallbacks(drawGIF);
}
}
#Override
public void onDestroy() {
super.onDestroy();
handler.removeCallbacks(drawGIF);
}
}
}
I am new to Android development and currently I am implementing Live wallpaper application.So, My question is How I can change live wallpaper when new live wallpaper is selected from the application.currently I am setting only one live wallpaper from my application but issue is that when I am selecting wallpaper from my application to set as wallpaper it is not change and display previously selected wallpaper.And when i am restarting my device then it will display.I am using Glide library to display Gif image.
Here this my WallpaperService class
public class GifPaperService extends WallpaperService {
static final String TAG = "gifService";
static final Handler gifHandler = new Handler();
int position;
boolean visible;
ImageAdapter img = new ImageAdapter();
Integer[] mThumb = img.mThumbIds;
#Override
public void onCreate() {
super.onCreate();
Log.v("Helllo", "...");
}
#Override
public Engine onCreateEngine() {
try {
return new GifEngine();
} catch (IOException e) {
Log.w(TAG, "Error creating engine", e);
stopSelf();
return null;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v("Hello..", ".....");
return super.onStartCommand(intent, flags, startId);
}
class GifEngine extends Engine {
private final Movie gif;
private final int duration;
private final Runnable runnable;
float scaleX;
float scaleY;
int when;
long start;
GifEngine() throws IOException {
MyPreferenceActivity myPref = new MyPreferenceActivity(getApplicationContext());
Log.i("Imageis... ", "Position.." + myPref.getGifImage());
position = myPref.getGifImage();
InputStream is = getResources().openRawResource(mThumb[position]);
Log.i("Imageposition...", "...." + mThumb[position]);
if (is == null) {
throw new IOException("Unable to open whoa.gif");
}
try {
gif = Movie.decodeStream(is);
duration = gif.duration();
} finally {
is.close();
}
when = -1;
runnable = new Runnable() {
#Override
public void run() {
animateGif();
}
};
}
#Override
public void onDestroy() {
super.onDestroy();
gifHandler.removeCallbacks(runnable);
}
#Override
public void onVisibilityChanged(boolean visible) {
super.onVisibilityChanged(visible);
if (visible) {
animateGif();
} else {
gifHandler.removeCallbacks(runnable);
}
}
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.onSurfaceChanged(holder, format, width, height);
scaleX = width / (1f * gif.width());
scaleY = height / (1f * gif.height());
animateGif();
}
#Override
public void onOffsetsChanged(float xOffset, float yOffset,
float xOffsetStep, float yOffsetStep,
int xPixelOffset, int yPixelOffset) {
super.onOffsetsChanged(
xOffset, yOffset,
xOffsetStep, yOffsetStep,
xPixelOffset, yPixelOffset);
animateGif();
}
void animateGif() {
tick();
SurfaceHolder surfaceHolder = getSurfaceHolder();
Canvas canvas = null;
try {
canvas = surfaceHolder.lockCanvas();
if (canvas != null) {
gifCanvas(canvas);
}
} finally {
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
gifHandler.removeCallbacks(runnable);
if (isVisible()) {
gifHandler.postDelayed(runnable, 1000L / 25L);
}
}
void tick() {
if (when == -1L) {
when = 0;
start = SystemClock.uptimeMillis();
} else {
long diff = SystemClock.uptimeMillis() - start;
when = (int) (diff % duration);
}
}
void gifCanvas(Canvas canvas) {
canvas.save();
canvas.scale(scaleX, scaleY);
gif.setTime(when);
gif.draw(canvas, 0, 0);
canvas.restore();
}
#Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
stopSelf();
gifHandler.removeCallbacks(runnable);
}
}
}
Activity class for setting wallpaper
setWallpaper.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (Build.VERSION.SDK_INT > 15) {
Intent intent = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT, new ComponentName(mContext, GifPaperService.class));
startActivity(intent);
}
}
});
ImageAdapter:
public class ImageAdapter extends BaseAdapter {
static WallpaperInfo info;
private Context mContext;
public ImageAdapter() {
}
public int getCount() {
return mThumbIds.length;
}
public Object getItem(int position) {
return mThumbIds[position];
}
public long getItemId(int position) {
return 0;
}
public ImageAdapter(Context c) {
mContext = c;
}
public View getView(final int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null){
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(200, 200));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(3, 3, 3, 3);
imageView.setMaxHeight(300);
imageView.setMaxWidth(300);
imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MyPreferenceActivity myPref = new MyPreferenceActivity(mContext);
myPref.setGifImage(position);
Intent intent = new Intent(mContext, FullScreenImage.class);
intent.putExtra("imageID", mThumbIds[position]);
/*intent.putExtra(EXTRA_LIVE_WALLPAPER_INTENT, intent);
intent.putExtra(EXTRA_LIVE_WALLPAPER_SETTINGS, info.getSettingsActivity());
intent.putExtra(EXTRA_LIVE_WALLPAPER_PACKAGE, info.getPackageName());*/
mContext.startActivity(intent);
}
});
Animation anim = AnimationUtils.loadAnimation(mContext.getApplicationContext(), R.anim.fly);
imageView.setAnimation(anim);
anim.start();
}
else{
imageView = (ImageView) convertView;
}
imageView.setImageResource(mThumbIds[position]);
return imageView;
}
public Integer[] mThumbIds = {
R.drawable.gpp1, R.drawable.gpp2,
R.drawable.gpp3,R.drawable.gpp4,
R.drawable.gpp5,R.drawable.gpp6,
R.drawable.gpp7,R.mipmap.h8,
R.mipmap.h9,R.mipmap.h10,
R.mipmap.h11,R.drawable.gp3,
R.drawable.gp2,R.drawable.gp,
R.drawable.onehalloween
};
}
If anyone know what is the problem.Tell me.
Thank in advance
For destroying previous wallpaper and setting new wallpaper,You have to Clear previous wallpaper like this,
In Your setWallpaper button click event use this code,
setWallpaper.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (Build.VERSION.SDK_INT > 16) {
WallpaperManager wallpaperManager = WallpaperManager.getInstance(getApplicationContext());
try {
wallpaperManager.clear();
} catch (IOException e) {
e.printStackTrace();
}
Intent intent = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT, new ComponentName(mContext, GifPaperService.class));
Log.i("Intent....", "...." + intent);
startActivity(intent);
}
}
});
This is works for me...
I want to change my Relative layout's background every 10 seconds with fade in/fade out animation.
So I found
//Transitiondrawable
TransitionDrawable transition = (TransitionDrawable) viewObj.getBackground();
transition.startTransition(transitionTime);
But it supports only 2 Drawable and I want to add more
Is there any way to do this?
First implement MyAnim.java class as below:
public class MyAnim extends Animation {
private final RelativeLayout view;
private int targetBackGround;
public MyAnim(RelativeLayout view, int tagetBackGroundColor) {
this.view = view;
this.targetBackGround = tagetBackGroundColor;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
view.setBackgroundColor(targetBackGround);
}
public void setColor(int color) {
this.targetBackGround = color;
}
}
Then add below code to your activity and call that animateBackground() method wherever you want:
private MyAnim backgroundAnim;
private int i;
private void animateBackground(){
final RelativeLayout animLay = (RelativeLayout) findViewById(R.id.animLay);
final int colors[] = new int[]{Color.RED, Color.CYAN, Color.DKGRAY, Color.GREEN, Color.MAGENTA};
backgroundAnim = new MyAnim(animLay, colors[i]);
backgroundAnim.setDuration(1000);
animLay.startAnimation(backgroundAnim);
backgroundAnim.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
if (i == colors.length - 1) {
i = 0;
} else {
i++;
}
backgroundAnim.setColor(colors[i]);
animLay.startAnimation(backgroundAnim);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
}
You can create your own loop, something like:
int delayBetweenAnimations = 10000;
for (int i = 0; i < yourImagesArray.length ; i++) {
int delay = i * delayBetweenAnimations;
yourImageview.postDelayed(new Runnable() {
#Override
public void run() {
//set your image and animation here
}
}, delay);
}
Another way is to use recursive animation:
#Override
public void onAnimationEnd(Animator animation) {
if(check_if_you_Still_want to_loop){
//rerun your animation
}
}
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
}
}