I have been trying to get frame animation to work recently.
I have struggled through the incorrect documentation example and have it working in an example application via the using onWindowFocusChanged to implement the start method.
My problem now lies in the fact I want to use it on a view that is controlled by getView in an array adapter.
Should this be possible?
ie
public View getView(int position, View convertView, ViewGroup parent)
{
ImageView myImage =(ImageView)proximityView.findViewById(R.id.imgUserImage);
myImage.setBackgroundResource(R.drawable.animation);
AnimationDrawable frameAnimation = (AnimationDrawable) myImage.getBackground();
frameAnimation.start();
}
Posting the start function inside a separate runnable has helped me, though I still wouldn't guarantee it to work in all cases. Try this first.
View v = convertView;
final ImageView downloadButton = (ImageView) v.findViewById(R.id.imageview);
downloadButton.setBackgroundResource(R.anim.your_animation);
AnimationDrawable spinningImage = ((AnimationDrawable)downloadButton.getBackground());
downloadButton.post(new Runnable() {
#Override
public void run() {
AnimationDrawable spinningImage = ((AnimationDrawable)
downloadButton.getBackground());
spinningImage.start();
}
});
EDIT
Additionally since this is in a ListAdapter the problem could be your ListView not invalidating its children. In your main activity try running:
_listView.post(new Runnable(){
public void run(){
_listView.invalidateViews();
}
});
When you want the contents updated. Also maybe disable your caches.
_listView.setAnimationCacheEnabled(false);
_listView.setDrawingCacheEnabled(false);
I have listviews in a View Pager, and found that animations only started once the listview gained focus (touch eg). A solution I found to get by this is:
listView.requestFocus();
Related
I'm making my own custom view and having trouble accessing the layout object immediately after initializing it.
I understand the documentation says layout can be null. But is there a certain event which I can override which will tell me when it's available? I've seen answers on SO which recommend adding a ViewTreeObserver (here)
It seems weird to me that I would need a separate class to know when the layout is available. Is there another way?
From what I understood, there exist no such method which you can override to know when the layout is available. If you find ViewTreeObserver difficult, you can try posting a runnable in the UI Thread i.e.,
view.post(new Runnable() {
#Override
public void run() {
int height = view.getHeight();
int width = view.getWidth();
}
});
Basically, the initialization of the layouts occurs in onCreate() so it would be better if you try the below code in onResume() whether the custom layout is available or not.
if the custom layout is custom_layout.xml then try the below code
LayoutInflater inflater=getLayoutInflater();
View view=inflater.inflate(R.layout.custom_layout,null);
if(view!=null)
{
//Place your code over here
}
I'm getting height and width of a view, inflated in the getView() method. It's a grid item.
Usually I use post() on the view to get the size, after it was attached to the layout. But it returns 0.
final View convertViewFinal = convertView;
convertView.post(new Runnable() {
#Override
public void run() {
doSomethingWithConvertView(convertViewFinal);
}
});
...
doSomethingWithConvertView(View v) {v.getWidth(); /*returns 0*/};
How do I get the size?
While using a viewTreeObserver definitely works, I have found that calling measurements requirements on inflated views can be done reliably using a runnable from the activity's view. i.e.
someActivityInstance.getWindow().getDecorView().post(new Runnable() {
#override
public void run() {
// someMeasurements
}
});
The thing is that convertview most likely is not drawn on the phone screen yet, so you have to wait until it is ready.
You need to use a ViewTreeObserver, to know exactly when the view has been drawn.
Check this answer for more info:
When Can I First Measure a View?
You probably is calling this at onCreate or onStart or onResume, methods which runs before layout measure.
But there is a lot of work arounds, this is one good option:
ViewTreeObserver vto = rootView.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
v.getWidth();//already measured...
}
});
Where rootView may be any viewGroup in a higher level than the one you want the width.
But be aware that this listner may run more than once.
I am trying to add a View to a RelativeLayout in my OnClickListener.
montrolButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// myParent is a relative layout
// newChild is an ImageView
myParent.addView(newChild);
requestLayout();
}
});
I have looked at the HierarchyViewer, I don' see my new child being added.
Can you please tell me if I miss anything?
I just tried the very same code and it works as it should. There could be an issue with your variable myParent which is not the element you expect it to be.
Also I did not have to call requestLayout() for the added view to appear on the screen.
Possibly try to just explicitly get another part of your view and add it there to see what is happening. Also just to try, you may do this:
RelativeLayout rv = (RelativeLayout) this.findViewById(R.id.right3);
ProgressBar iv = new ProgressBar(this);
rv.addView(iv);
to see if there is anything wrong with your image view instead of myParent
In any case it works if both elements are OK - there is nothing else to do in an activity.
Do you set the layout attributes of the new view (image view)?
I'm working on a game that requires drawing to SurfaceView's
Canvas. I'm using SurfaceHolder to obtain Canvas to draw to, and
perform drawing in a separate thread. Everything I draw displays
correctly except for this one animation.
Here is the animation definition (it is in res/drawable/
my_animation.xml:
and here is how I draw it to the Canvas:
AnimationDrawable ad = (AnimationDrawable)getResources().getDrawable(R.drawable.my_animation);
ad.draw(canvas);
ad.start();
but only the first frame ever appears on the screen.
What am I missing?
Thank you
If I get the reference right, you have to assign your AnimationDrawable to an ImageView as the example from http://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html demonstrates:
// Load the ImageView that will host the animation and
// set its background to our AnimationDrawable XML resource.
ImageView img = (ImageView)findViewById(R.id.spinning_wheel_image);
img.setBackgroundResource(R.drawable.spin_animation);
// Get the background, which has been compiled to an AnimationDrawable object.
AnimationDrawable frameAnimation = (AnimationDrawable) img.getBackground();
// Start the animation (looped playback by default).
frameAnimation.start()
In your case you did not assign your AnimationDrawable to any view so I suppose that's why it does not get updated. So you have to call AnimationDrawable.getFrame(int) manually.
If you are already using a separate thread why don't you involve also the code for your animation? This would render your code more consistent in my opinion.
Although this is an old question, i run into this problem too and figure out a walkaround, so i just post it here in case anyone searching about.
```java
final AnimationDrawable animationDrawable = ...;
final View v = new View(this) {
#Override
protected void onDraw(Canvas canvas) {
animDrawable.draw(canvas);
}
};
animationDrawable.setCallback(new Callback() {
#Override
public void unscheduleDrawable(Drawable who, Runnable what) {
v.removeCallbacks(what);
}
#Overridew
public void scheduleDrawable(Drawable who, Runnable what, long when) {
v.postDelayed(what, when - SystemClock.uptimeMillis());
}
#Override
public void invalidateDrawable(Drawable who) {
v.postInvalidate();
}
});
```
Animated drawables of all kinds (Transition, etc.) need a Callback to schedule redrawals. As zhang demonstrates, it is a simple interface for posting Runnables.
To support animated drawables in a custom view, you need two things:
pass your View to your animated Drawable's setCallback. Even base View implements Drawable.Callback, so there's no need to write your own wrapper.
override verifyDrawable to also return true for your animated Drawable.
As to why anyone would need that - I have just implemented animated drawable support in RecyclerView.ItemDecorations, how cool is that :-)
You are working with Canvas means, you are coding in low level. In low level u have to do everything. working with View (ImageView) means, it is high level.In ImageView already defined in low level on canvas how to deal with AnimationDrawable.
Lars Blumberg's answer is correct but the documentation is incorrect; you also need to take into account this: animation start issue
When I use the Gallery widget, how do I get the images to say scale up & glow on being selected and scaled down & un-glow on being unselected?
All tutorials I've seen have this effect but I'm not able to see it...
Is there some kind of an animation that I have to attach to the Gallery?
Hope this is helpful. I manage to "simulate" the shrink/grow solution with the Gallery widget. Since they removed the getScale(), things get a little bit complicated. I think that this it's not the best solution at all, but at least I can live with it.
What I have found is that Gallery manages the focus EXTREMELY BAD. So, the first approach was to add a focus change listener on the ImageView displayed, but no luck there. Focus is a MESS there... in terms that, the selected image it's not the currently focused view. I have sent a mail to android-developers mailing list about some error on API doc (regarding the focusSearch()method and some focus contants).
Here's my solution to this problem:
Build an animation resource to 'grow' the image:
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="1.0"
android:toXScale="1.10"
android:fromYScale="1.0"
android:toYScale="1.10"
android:duration="300"
android:pivotX="50%"
android:pivotY="50%"
android:interpolator="#android:anim/accelerate_decelerate_interpolator"
android:fillAfter="false"/>
If you don't get what that means then you should proceed to read this
That will be our 'grow' effect, and you will need to save it in: res/anim/grow.xml or whatever name it suites you (but always in res/anim dir).
You can follow the resource guide from here to create a Gallery view. The ImageAdapter builds an ImageView every time that the Gallery object calls getView(). One workaround you could implement is adding a line to the getView() method that identifies a View with a position, this way:
...
i.setId(position);
...
With that line added to the getView() method of the ImageAdpater object, you can then unequivocally identify that view within a listener, for instance:
g.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected (AdapterView<?> parent, View v, int position, long id) {
Animation grow = AnimationUtils.loadAnimation(YourActivity.this, R.anim.grow);
View sideView = parent.findViewById(position - 1);
if (sideView != null)
((ImageView)sideView).setLayoutParams(new Gallery.LayoutParams(150, 100));
sideView = parent.findViewById(position + 1);
if (sideView != null)
((ImageView)sideView).setLayoutParams(new Gallery.LayoutParams(150, 100));
v.startAnimation(grow);
v.setLayoutParams(new Gallery.LayoutParams(170, 150));
}
public void onNothingSelected (AdapterView<?> parent) {
System.out.println("NOTHING SELECTED");
}
});
NOTE: You may notice that all the values from animation and from layout parameters has been choosen by me at hand. This is because i'm not going to clean code for you. And, this is just a workaround the BAD focus issue with this widget or the android view system. If focus were OK, then, all you need to do is set a focus change listener that makes the gros/shrink when it got focus/unfocused.
I hope this may help you to find a way around for your problem,
Regards,
New EDIT: This is the listener I have set, I also added the line i.clearAnimation() in the getView() method:
private class SelectListener implements AdapterView.OnItemSelectedListener {
private Animation grow;
private int last;
public SelectListener() {
grow = AnimationUtils.loadAnimation(RouteGallery.this, R.anim.grow);
last = 0;
}
public void onItemSelected (AdapterView<?> parent, View v, int position, long id) {
View sideView = parent.findViewById(last);
if (sideView != null && last != position)
sideView.clearAnimation();
v.startAnimation(grow);
last = position;
}
public void onNothingSelected (AdapterView<?> parent) {
}
}
You need to use an ImageSwitcher. The ImageSwitcher has methods for setting the in and out animations (when image is selected and deselected, or selected and replaced).
The following link has a good tutorial on how to use it in conjunction with the Gallery.
I implemented a similar animation like this:
final Animation shrink = AnimationUtils.loadAnimation(activity, R.anim.shrink);
shrink.setFillAfter(true);
gallery.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
// This iterates through the views which are currently displayed on screen.
for (int k=0; k<gallery.getChildCount(); k++){
// Do whatever else you want, here.
// This is how you get a particular element of a view
ImageView background = (ImageView) gallery.getChildAt(k).findViewById(R.id.menu_item_background);
//clear animation
gallery.getChildAt(k).clearAnimation();
}
// Scale the selected one
view.startAnimation(shrink);
}
#Override
public void onNothingSelected(AdapterView<?> adapterView) {}
});