I want to set a background drawable to 1st element of list view, also to other elements of the list view I want to set the same drawable but it should be little faded. I dont want to use two images for this.
I tried using Alpha Animation for this:
In getView of my List View i used This:
Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.alpha_anim);
if (position == 0) {
list_row_layout.setBackgroundResource(R.drawable.bg_image);
} else {
list_row_layout.setBackgroundResource(R.drawable.bg_image);
animation.setDuration(0);
animation.setFillAfter( true );
if (list_row_layout != null){
list_row_layout.startAnimation(animation);
}
}
and here is my alpha_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="0.0"
android:toAlpha="0.5"
android:duration="1000" />
The problem is it is working fine, but the animation gets applied to 0th element also.
I tried cancelling the animation if(position == 0) but its not working.
I need to know can we apply Alpha animation to each ListRow element separately?
Check out the ListViewAnimation which contains the AlphaAnimation for the list of items in ListView.
User AlphaAnimation class as below to apply alpha effects on your ListView
private void setAlphaAdapter() {
AnimationAdapter animAdapter = new AlphaInAnimationAdapter(mAdapter);
animAdapter.setAbsListView(getListView());
getListView().setAdapter(animAdapter);
}
Why animate it? Have you tried setAlpha ?
Oh, and about the first element, add setAlpha(1f) for pos == 0. I think it might have something to do with reusing the listelements...
Related
I am currently working on adding a income animation for RecyclerView items. I want it just likes the Google+ Android App. Here is my code snippets:
anim/up_from_bottom.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="#android:anim/decelerate_interpolator">
<translate
android:fromXDelta="0%" android:toXDelta="0%"
android:fromYDelta="60%" android:toYDelta="0%"
android:duration="500" />
</set>
and in the Adapter class I add the function startAnimation(itemHolder.itemView, position); in the funcitononBindViewHolder
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
...
startAnimation(holder.rootView, position);
}
the startAnimation() is like this:
protected void startAnimation(View view, int position) {
if (position > lastPosition) {
Animation animation = AnimationUtils.loadAnimation(mContext, R.anim.up_from_bottom);
view.startAnimation(animation);
lastPosition = position;
}
}
It seems looks like the Google+ Android App's list animation, but it has a bug, when I scroll fast, it animate not perfect, such as it seems that the first position and the current postion perform the animation at the same time.
I just want the animation like Google+, how can I fix it, or there has any other way.
I hava try recyclerview-animators, it's a great lib, but I still do what I want.
Any help please! Thanks!
Your "bug" occurs when you scroll fast because the animation on the viewholder is still running when it is scrolled out of the display and you are binding a new animation to the viewholder when the recyclerview recycles it.
You should override onViewDetachedFromWindow and clear the animation on the view in the method.
This will ensure that any animation that is running on the view will be cleared before it is sent to the recycler for resuse, and you can safely run a new animation on the view.
recently I wrote a function.it's about a refresh button in each list item. what I want is click the button or List Item, the refresh button starts rotate. stops when the request finished.
I use animation as follows:
<?xml version="1.0" encoding="UTF-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fillAfter="true"
android:fromDegrees="0"
android:interpolator="#android:anim/linear_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="infinite"
android:toDegrees="358" />
and some source code are here:
public void refresh(View v) {
Animation rotation = AnimationUtils.loadAnimation(mContext,
R.anim.rotate);
rotation.setFillAfter(true);
v.startAnimation(rotation);
}
public void completeRefresh(View v) {
v.clearAnimation();
}
when the request finished, I call notifyDataSetChanged() to refresh the LiseView.
the problem is that the button was indeed rotating. but when I click it the second time. it's rotating but a little fuzzy. just like this:
any suggestions? thanks a lot.
What is most likely happening on your second (and subsequent clicks) is that the animation is running on it again.
In your current implementation, try using setTag(...) like this:
public void refresh(View v) {
if(v.getTag() != null && (boolean)v.getTag()) {
//do nothing, since we are setting the tag to be true once pressed
} else {
//this view hasn't been clicked yet, show animation and set tag
v.setTag(true);
Animation rotation = AnimationUtils.loadAnimation(mContext, R.anim.rotate);
rotation.setFillAfter(true);
v.startAnimation(rotation);
}
}
In your Adapter, you should keep track of which list items are being animated (I'm assuming multiple items can be clicked at the same time). Once you know that the 'request' is finished, you can update the adapter with the correct items and then call notifyDataSetChanged()
Is there any way to animate the elements of a RecyclerView when I scroll it?
I took a look at DefaultItemAnimator and RecyclerView.ItemAnimator, but that animations seems to be only called if the dataset has changed, please correct me if I am wrong.
I'm a little confused about RecyclerView.ItemAnimator.animateMove() when is it called? I put some breakpoints into that class but none of them stops my app.
However back to my question how can I animate the RecyclerView? I want that some elements have another opacity, depended on some custom rules.
I did some more reaseach it seems that animation move is exactly that what I'm looking for. That methods are called from dispatchLayout(). Here is the javadoc of that method:
Wrapper around layoutChildren() that handles animating changes caused by layout.
Animations work on the assumption that there are five different kinds of items
in play:
PERSISTENT: items are visible before and after layout
REMOVED: items were visible before layout and were removed by the app
ADDED: items did not exist before layout and were added by the app
DISAPPEARING: items exist in the data set before/after, but changed from
visible to non-visible in the process of layout (they were moved off
screen as a side-effect of other changes)
APPEARING: items exist in the data set before/after, but changed from
non-visible to visible in the process of layout (they were moved on
screen as a side-effect of other changes)
The overall approach figures out what items exist before/after layout and
infers one of the five above states for each of the items. Then the animations
are set up accordingly:
PERSISTENT views are moved ({#link ItemAnimator#animateMove(ViewHolder, int, int, int, int)})
REMOVED views are removed ({#link ItemAnimator#animateRemove(ViewHolder)})
ADDED views are added ({#link ItemAnimator#animateAdd(ViewHolder)})
DISAPPEARING views are moved off screen
APPEARING views are moved on screen
So far I'm looking for PERSISTENT, DISAPPEARING and APPEARING, but that methods are never called because of this line here:
boolean animateChangesSimple = mItemAnimator != null && mItemsAddedOrRemoved
&& !mItemsChanged;
mItemsAddedOrRemoved is simply always false so none of that callback are ever reached. Any idea how to set set flag correctly?
I ended in using an OnScrollListener and animating it in a custom animate() method. In my case that code takes just 2ms so that is no problem for the 60fps.
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(int newState) {
if(newState == RecyclerView.SCROLL_STATE_IDLE) {
// special handler to avoid displaying half elements
scrollToNext();
}
animate();
}
#Override
public void onScrolled(int dx, int dy) {
animate();
}
});
I did it this way. Might help someone. I don't know whether it's the best way to do it but works fine for me.
UPDATE:
To fix fast scrolling behaviour, override onViewDetachedFromWindow method of the adapter and call clearAnimation on the animated view (in this case, holder.itemView.clearAnimation() ).
up_from_bottom.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="#android:anim/decelerate_interpolator">
<translate
android:fromXDelta="0%" android:toXDelta="0%"
android:fromYDelta="100%" android:toYDelta="0%"
android:duration="400" />
</set>
down_from_top.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="#android:anim/decelerate_interpolator">
<translate
android:fromXDelta="0%" android:toXDelta="0%"
android:fromYDelta="-100%" android:toYDelta="0%"
android:duration="400" />
</set>
And finally put this code in onBindViewHolder of recyclerView. Create a field called lastPosition and initialize it to -1.
Animation animation = AnimationUtils.loadAnimation(context,
(position > lastPosition) ? R.anim.up_from_bottom
: R.anim.down_from_top);
holder.itemView.startAnimation(animation);
lastPosition = position;
The good solution is to animate holder in adapter in onBindViewHolder method.
Snippet taken from Material Test project Slidenerd:
#Override
public void onBindViewHolder(ViewHolderBoxOffice holder, int position) {
Movie currentMovie = mListMovies.get(position);
//one or more fields of the Movie object may be null since they are fetched from the web
holder.movieTitle.setText(currentMovie.getTitle());
//retrieved date may be null
Date movieReleaseDate = currentMovie.getReleaseDateTheater();
if (movieReleaseDate != null) {
String formattedDate = mFormatter.format(movieReleaseDate);
holder.movieReleaseDate.setText(formattedDate);
} else {
holder.movieReleaseDate.setText(Constants.NA);
}
int audienceScore = currentMovie.getAudienceScore();
if (audienceScore == -1) {
holder.movieAudienceScore.setRating(0.0F);
holder.movieAudienceScore.setAlpha(0.5F);
} else {
holder.movieAudienceScore.setRating(audienceScore / 20.0F);
holder.movieAudienceScore.setAlpha(1.0F);
}
if (position > mPreviousPosition) {
AnimationUtils.animateSunblind(holder, true);
} else {
AnimationUtils.animateSunblind(holder, false);
}
mPreviousPosition = position;
here is a link
I would like to know if there is a simple way to add a view (a button) to a RelativeLayout, with some kind of scale animation.
I extended a class from Button and did something like this:
public class MyButton extends Button {
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
ScaleAnimation anim = new ScaleAnimation(0,1,0,1);
anim.setDuration(1000);
anim.setFillAfter(true);
this.startAnimation(anim);
}
Then tried to add this button to a view and it didn't work. Please help!
In your activity, use instead:
parentview.addView(myButton);
Then animate the button with this:
Animation animation = AnimationUtils.loadAnimation(getBaseContext(), R.anim.slide_right_in);
animation.setStartOffset(0);
myButton.startAnimation(animation);
This is an example of slide_right_in.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="100%p" android:toXDelta="0" android:duration="800"/>
</set>
In addition,
This is a activity play animation function I wrote:
public Animation PlayAnim( int viewid, Context Con, int animationid, int StartOffset )
{
View v = findViewById(viewid);
if( v != null )
{
Animation animation = AnimationUtils.loadAnimation(Con, animationid );
animation.setStartOffset(StartOffset);
v.startAnimation(animation);
return animation;
}
return null;
}
You can call this like this:
PlayAnim(R.id.bottombar, (Context) this, R.anim.slide_right_in, 0);
Where:
1st parameter is the id of the view you want to apply the animation on.
2nd paramenter isThe context retrieved inside your activity.
3rd parameter is the desired animation that you put inside your anim resource folder or from android predefined animations.
4rd paremeter is the animation startoffset.
I tested your animated button implementation and it works correctly. There must be some other problem. Probably the way you add the button to the layout.
To add your button to the relative layout use code like this.
RelativeLayout rl = (RelativeLayout)findViewById(R.id.rl);
MyButton b1 = new MyButton(Main.this);
b1.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
rl.addView(b1);
Or you can inflate the button from layout. To do this create layout mybtn.xml containing your button implementation:
<?xml version="1.0" encoding="utf-8"?>
<PACKAGE_OF_MYBUTTON_HERE.MyButton
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
To add it to your layout call:
RelativeLayout rl = (RelativeLayout)findViewById(R.id.rl);
Button b = (Button)getLayoutInflater().inflate(R.layout.mybtn, rl, false);
rl.addView(b);
There might be a problem with proper positioning of your view when you add it to the relative layout. Just add code like this before calling rl.addView(b1) (the code snippet adds new button below someOtherView).
LayoutParams lp = new LayoutParams(b.getLayoutParams());
lp.addRule(RelativeLayout.BELOW, someOtherView.getId());
b.setLayoutParams(lp);
You can try adding this to your code just before adding view.I guess this code would work for any view changes. In my case was switching 2 views with animation.
TransitionManager.beginDelayedTransition(layoutlocation);//layoutlocation is parent layout(In my case relative layout) of the view which you gonna add.
Hope it works.Took 2 days for me to make this work.
It's not always necessary to use animation class to get actual animation. We can provide a delay when adding views to layout using handler as shown.
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
Animation fadeanimation = new AlphaAnimation(0,1);
fadeanimation.setDuration(position*60+100);
child.setAnimation(fadeanimation);
linearLayout.addView(child);
}
}, position*60);
I trying to move a image from one place to other using animation,but after moving it coming back to original position, how to stop it to the moved position itself.
to let the image in the last place of the animation , try this :
TranslationAnimation ta = new TranslateAnimation(fromX, toX, 0, 0);
ta.setDuration(1000);
ta.setFillAfter(true); // this will let the image in the last place of the Animation
imageView.startAnimation(ta);
After an Animation is done, use the method setFillAfter(true), to make the last animation state persist:
If fillAfter is true, the transformation that this animation performed will persist when it is finished.
Animation.setFillAfter/Before - Do they work/What are they for?
If you need to do something more specific, you could also set an animation listener and move your object at the end of the animation:
animation1.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
//change according to your needs
myView.setX(0);
}
#Override
public void onAnimationRepeat(Animation animation) { }
});
Finally got a way to work around,the right way to do this is setFillAfter(true),
if you want to define your animation in xml then you should do some thing like this
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/decelerate_interpolator"
android:fillAfter="true">
<translate
android:fromXDelta="0%"
android:toXDelta="-100%"
android:duration="1000"/>
</set>
you can see that i have defined filterAfter="true" in the set tag,if you try to
define it in translate tag it won't work,might be a bug in the framework!!
and then in the Code
Animation anim = AnimationUtils.loadAnimation(this, R.anim.slide_out);
someView.startAnimation(anim);
See this blog post for a solution:
// first set the view's location to the end position
view.setLayoutParams(...); // set to (x, y)
// then animate the view translating from (0, 0)
TranslationAnimation ta = new TranslateAnimation(-x, -y, 0, 0);
ta.setDuration(1000);
view.startAnimation(ta);
I'm sure you would have found the answer by now (I just did... so I am posting for others). Android seems to have officially shifted to a new animation framework called "Property Animation". This has been available since Honeycomb (3.0). This will essentially solve your problem as it animates the actual property values.
DEV GUIDE:
http://developer.android.com/guide/topics/graphics/prop-animation.html