Keep view above animation of another view - android

I have an Activity with a main screen that simply has a title bar (among other things). I have another TextView below the title bar that I have animate from top to bottom into place (it starts out as View.GONE, then I animate it visible and into place after an event from the user).
This works fine and dandy, except the TextView below the title bar animates above the title bar into place. I want it to seem as if the TextView came from underneath the title bar. Both views are in a LinearLayout, so I'm not able to address the z-order like I would in a FrameLayout. Any suggestions?

I eventually solved this by encompassing the textview inside of a LinearLayout, then setting a LayoutAnimationController to the LinearLayout. This causes all the childs to be animated with respect to the parent container, which made the drop-down only to be rendered within the LinearLayout (which worked perfectly). Here is the code I used for the Animation Controller and ListView:
private void addDeleteDropAnimation() {
AnimationSet set = new AnimationSet(true);
Animation animation = new AlphaAnimation(0.0f, 1.0f);
animation.setDuration(150);
set.addAnimation(animation);
animation = new TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0.0f,Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, -1.0f,Animation.RELATIVE_TO_SELF, 0.0f
);
animation.setDuration(300);
set.addAnimation(animation);
controllerDel = new LayoutAnimationController(set, 0.5f);
vw_delLinearLayout.setLayoutAnimation(controllerDel);
}

Handler handler = new Handler();
new Thread(){
public void run(){
TextView tv = (TextView)findViewById(R.id.xx);
LayoutParams params = (LayoutParams)tv.getLayoutParams();
handler.post(new Runnable(){
public void run(){
tv.setVisible(View.Visible);
}
}
int height = params.height;
for(int i = 0; i < height + 1; i++) {
params.topMargin = i - height;
handler.post(new Runnable(){
public void run(){
tv.requestLayout();
}
}
try{
Thread.sleep(5);
}catch(InterruptedException e){
}
}
}
}.start();
you can try this.

Related

How to correctly animate stacking views one after another in Android using handler?

I have a LinearLayout with RelativeLayout children. Each RelativeLayout has a background image like a file cabinet. I am trying to animate the drawers dropping down into view one after another with a smooth delay. Everything I have tried plays all animations at once. I have this as my method for animating each drawer:
private void dropAndPause(final RelativeLayout drawer){
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
animation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.slide_down);
animation.setStartOffset(750L);
drawer.startAnimation(animation);
}
}, 1200);
}
I have also tried this:
View[] views = new View[] { ... };
// 100ms delay between Animations
long delayBetweenAnimations = 100l;
for(int i = 0; i < views.length; i++) {
final View view = views[i];
// We calculate the delay for this Animation, each animation starts 100ms
// after the previous one
int delay = i * delayBetweenAnimations;
view.postDelayed(new Runnable() {
#Override
public void run() {
Animation animation = AnimationUtils.loadAnimation(context, R.anim.your_animation);
view.startAnimation(animation);
}
}, delay);
}
Instead of View[] views, I used this:
View[] drawers = new View[] {
drawerOne, drawerTwo, drawerThree, drawerFour, drawerFive
};
Which plays, again, all of the animations at once. How can I get each "drawer"/view to slide in one at a time? Also, should I have each view as visibility GONE initially?
If you want to animate the views inside a layout, then it's much easier to use layout animations. Basically, you need to load an animation, create a LayoutAnimationController, set the delay on it, and launch the animation. Here's some sample code.
Animation animation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.slide_down);
animation.setStartOffset(750L);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.1F);
viewGroup.setLayoutAnimation(controller);
viewGroup.startLayoutAnimation();
The delay here is set as fraction of the animation duration.

Android, set button background color with animation?

I have a button that, when clicked, I would like to have the button appear to flash by switching back and forth between two background colors.
This answer uses AlphaAnimation to make a flashing button:
final Animation animation = new AlphaAnimation(1, 0); // Change alpha from fully visible to invisible
animation.setDuration(500); // duration - half a second
animation.setInterpolator(new LinearInterpolator()); // do not alter animation rate
animation.setRepeatCount(Animation.INFINITE); // Repeat animation infinitely
animation.setRepeatMode(Animation.REVERSE); // Reverse animation at the end so the button will fade back in
final Button btn = (Button) findViewById(R.id.your_btn);
btn.startAnimation(animation);
But I couldn't get it to work with background color.
Android Studio will auto-complete the following:
animation = new Animation() {
#Override
public void setBackgroundColor(int bg) {
super.setBackgroundColor(bg);
}
};
But I tried applying it to the button (with bg = Color.parseColor("#ffff9434")), but no dice.
Thank you in advance.
EDIT
Also tried the following, but it is deprecated and didn't work (from here)
Button btn = (Button)this.findViewById(R.id.btn1);
//Let's change background's color from blue to red.
ColorDrawable[] color = {new ColorDrawable(Color.BLUE), new ColorDrawable(Color.RED)};
TransitionDrawable trans = new TransitionDrawable(color);
//This will work also on old devices. The latest API says you have to use setBackground instead.
btn.setBackgroundDrawable(trans);
trans.startTransition(5000);
ETID 2
Got it working, see answer below
Got it working! Thanks to this post!
final AnimationDrawable drawable = new AnimationDrawable();
final Handler handler = new Handler();
drawable.addFrame(new ColorDrawable(Color.RED), 400);
drawable.addFrame(new ColorDrawable(Color.GREEN), 400);
drawable.setOneShot(false);
btn = (Button) view.findViewById(R.id.flashBtn);
btn.setBackgroundDrawable(drawable);
handler.postDelayed(new Runnable() {
#Override
public void run() {
drawable.start();
}
}, 100);
Works like a charm!

Android alpha and AlphaAnimation

In imageAdapter class, I set the image alpha to 0.5 handler.imageView.setAlpha(0.5f); inside a try/catch.
It's made like this, and not inside the layout xml, because previous versions of android haves int instead of float, so, in the catch, setAlpha is 128.
In the activity, I have an AlphaAnimation(float from, float to) so I can make smoother transitions when sliding between items. I've put from = 0.5f to match the initial value, and to = 1.0f to full opaque image. I really achieved a part from this. The item that is not selected shows an alpha with 0.5, but when it's selected, it's not 100% opaque, just a bit more.
Activity code:
private View antView = null; //Last view seen
...
gallery.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
if(antView != null)
setItemViewMode(antView, false);
antView = v;
setItemViewMode(v, true);
}
});
//This method is to detect the item selected, and change styles to selected and the view from before
public void setItemViewMode(View item, boolean selected) {
Animation animationImage;
ImageView img = (ImageView) item.findViewById(R.id.imageView1);
if(selected) {
animationImage = new AlphaAnimation(0.5f, 1.0f);
}
else {
animationImage = new AlphaAnimation(1.0f, 0.5f);
}
animationImage.setDuration(250);
animationImage.setFillAfter(true);
img.startAnimation(animationImage);
}
As said above, the animation occurs, but, the alpha from the selected image is not 100% opaque.
May something wrong setting the opacity inside the animation?
Find it out, someway, I thought that before adding the animation, I should put the opacity to 1.0f and then make the animation from 0.5f to 1.0f, and this worked.
So it would be:
if(selected)
animationImage = new AlphaAnimation(0.5f, 1.0f);
else
animationImage = new AlphaAnimation(1.0f, 0.5f);
img.setAlpha(1.0f);
img.startAnimation(animationImage);
try this...
public void setItemViewMode(View item, boolean selected) {
Animation animationImage;
ImageView img = (ImageView) item.findViewById(R.id.imageView1);
if(selected) {
animationImage = new AlphaAnimation(0f, 1.0f);
}
else {
animationImage = new AlphaAnimation(1.0f, 0f);
}
animationImage.setDuration(250);
animationImage.setFillAfter(true);
img.startAnimation(animationImage);
}

flashing background

I have a LinearLayout with a few Buttons and TextViews. I want my background to flash at timed intervals, say from red to white to red and so on. Right now, I am trying this code, but it gives me a null pointer exception.
LinearLayout ll = (LinearLayout) findViewById(R.layout.activity_main);
Animation anim = new AlphaAnimation(0.0f, 1.0f);
anim.setDuration(50);
anim.setStartOffset(20);
anim.setRepeatMode(Animation.REVERSE);
anim.setRepeatCount(Animation.INFINITE);
ll.startAnimation(anim); // shows null pointer exception at this line
Please help me where am I going wrong?
You have specified the wrong View id here findViewById(R.layout.activity_main). It should be something like:
findViewById(R.id.your_view_id);
Also, make sure to call setContentView(R.layout.activity_main) right after super.onCreate
EDIT:
Here is the code that allows you to change only the background color with any colors you want. It looks like AnimationDrawable.start() doesn't work if called from Activity.onCreate, so we have to use Handler.postDelayed here.
final LinearLayout layout = (LinearLayout) findViewById(R.id.layout);
final AnimationDrawable drawable = new AnimationDrawable();
final Handler handler = new Handler();
drawable.addFrame(new ColorDrawable(Color.RED), 400);
drawable.addFrame(new ColorDrawable(Color.GREEN), 400);
drawable.setOneShot(false);
layout.setBackgroundDrawable(drawable);
handler.postDelayed(new Runnable() {
#Override
public void run() {
drawable.start();
}
}, 100);
Try this
LinearLayout ll = (LinearLayout) findViewById(R.id.activity_main);
Animation anim = new AlphaAnimation(0.0f, 1.0f);
anim.setDuration(50);
anim.setStartOffset(20);
anim.setRepeatMode(Animation.REVERSE);
anim.setRepeatCount(Animation.INFINITE);
ll.startAnimation(anim);
and If activity_main is your XML file name then
setContentView(R.layout.activity_main);
and use your layout id here
LinearLayout ll = (LinearLayout) findViewById(R.id.linear_layout_id);

Add animation to an ExpandableListView

Is there a way to add animation when opening an expandable list in Android?
I want it so that when the user clicks on the expandable list, it has an animation/effect like I'm opening a sliding drawer.
It moves slow until it is completely opened.
I've spent a lot of time searching with no luck. The existing solutions are just not smooth enough - if your layout is something more complex than just 2 buttons, it becomes laggy.
So, I've created my own ListAdapter that caches the whole view into a Bitmap and then performs the animation on the cached view instead of the view itself. It works much faster.
Here it is: https://github.com/dmitry-zaitsev/ExpandableAdapter
The good news is that you don't need to rewrite a bunch of code - just wrap my ExpandableAdapter around your adapter and provide the id of the view that will act like a toggle button and the id of the view that holds the content of the second level:
new ExpandableAdapter(context, yourAdapter, R.id.switch, R.id.holder);
And that is all.
I have tried to make this work as well. I have found one solution that works for the childViews. It does not animate the actual expanding of the group though, but animates the child cells as they fill the space the expansion leaves behind.
Edit: There is a bug in collapsing, which will make some cells that should not be hidden, become hidden. This is probably related to View-recycling in the listView. I will will update when I have a solution to this.
Animating with layoutAnimation in setOnGroupClickListener
mResultList.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
if(mResultList.isGroupExpanded(groupPosition)){
mProgAdap.prepareToCollapseGroup(groupPosition);
setupLayoutAnimationClose(groupPosition);
mResultList.requestLayout();
}else{
boolean autoScrollToExpandedGroup = false;
mResultList.expandGroup(groupPosition,autoScrollToExpandedGroup);
setupLayoutAnimation();
//*/
}
//telling the listView we have handled the group click, and don't want the default actions.
return true;
}
private void setupLayoutAnimation() {
AnimationSet set = new AnimationSet(true);
Animation animation = new AlphaAnimation(0.0f, 1.0f);
animation.setDuration(50);
set.addAnimation(animation);
animation = new ScaleAnimation(1.0f, 1.0f, 0.0f, 1.0f, 0.5f, 1.0f);
animation.setDuration(50);
set.addAnimation(animation);
LayoutAnimationController controller = new LayoutAnimationController(set, 0.75f);
mResultList.setLayoutAnimationListener(null);
mResultList.setLayoutAnimation(controller);
}
private void setupLayoutAnimationClose(final int groupPosition) {
AnimationSet set = new AnimationSet(true);
Animation animation = new AlphaAnimation(1.0f, 0.0f);
animation.setDuration(50);
animation.setFillAfter(true);
animation.setFillEnabled(true);
set.addAnimation(animation);
animation = new ScaleAnimation(1.0f, 1.0f, 1.0f, 0.0f, 0.5f, 0.0f);
animation.setDuration(50);
animation.setFillAfter(true);
animation.setFillEnabled(true);
set.addAnimation(animation);
set.setFillAfter(true);
set.setFillEnabled(true);
LayoutAnimationController controller = new LayoutAnimationController(set, 0.75f);
controller.setOrder(LayoutAnimationController.ORDER_REVERSE);
mResultList.setLayoutAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
mResultList.collapseGroup(groupPosition);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
mResultList.setLayoutAnimation(controller);
}
});
We need more tweaks to make the animation only apply to the actual children of the expanded/collapsed group. Because we can't overload the correct part in the LayoutAnimationController, we need to create a special ViewGroup class. This is the same technique as in , "Can LayoutAnimationController animate only specified Views".
In the ExpandableListViewAdapter, we now need some state handling to allow or ignore animation on items in the list.
#Override
public void onGroupExpanded(int groupPos){
super.onGroupExpanded(groupPos);
int childCount = getChildrenCount(groupPos);
Log.d("EXPLIST","setting children to be expanded:" + childCount);
for(int j=0; j < getGroupCount(); j++){
for(int k=0; k < getChildrenCount(j); k++){
GoalServiceCell cell = (GoalServiceCell)getChild(j,k);
cell.expandAnimState = GoalServiceCell.ExpandAnimState.SHOULD_NOT_ANIMATE;
}
}
for(int i=0; i < childCount; i++){
GoalServiceCell cell = (GoalServiceCell)getChild(groupPos,i);
cell.expandAnimState = GoalServiceCell.ExpandAnimState.SHOULD_START_EXPAND;
}
}
public void prepareToCollapseGroup(int groupPos){
int childCount = getChildrenCount(groupPos);
for(int j=0; j < getGroupCount(); j++){
for(int k=0; k < getChildrenCount(j); k++){
GoalServiceCell cell = (GoalServiceCell)getChild(j,k);
cell.expandAnimState = GoalServiceCell.ExpandAnimState.SHOULD_NOT_ANIMATE;
}
}
for(int i=0; i < childCount; i++){
GoalServiceCell cell = (GoalServiceCell)getChild(groupPos,i);
cell.expandAnimState = GoalServiceCell.ExpandAnimState.SHOULD_START_COLLAPSIN;
}
}
#Override
public void onGroupCollapsed(int groupPos){
super.onGroupCollapsed(groupPos);
int childCount = getChildrenCount(groupPos);
for(int i=0; i < childCount; i++){
GoalServiceCell cell = (GoalServiceCell)getChild(groupPos,i);
cell.expandAnimState = GoalServiceCell.ExpandAnimState.SHOULD_NOT_ANIMATE;
}
}
And in the ViewHolder of the children.
void expandOrCollapse(GoalServiceCell cell,int position){
AnimationAverseRelativeLayout hack = (AnimationAverseRelativeLayout)master;
boolean shouldAnim = cell.expandAnimState == GoalServiceCell.ExpandAnimState.SHOULD_START_EXPAND ||
cell.expandAnimState == GoalServiceCell.ExpandAnimState.SHOULD_START_COLLAPSIN;
hack.setIfShouldAnimate(shouldAnim);
}
The GroupViews are also contained in a AnimationAverseRelativeLayout. Since I have set "shouldAnimate" to default to false, I don't need to touch them.
I had this same exact problem. And I fixed it once and for all. I open-sourced it to github.
https://github.com/tjerkw/Android-SlideExpandableListView
Basically, you include this project dependency with your Android project. And then wrap your ListAdapter into a SlideExpandableListAdapter. The wrapper will then add the slide functionality with animation to your ListView.
Hope it helps you, I'm already using it in two projects.
So what I've done is use a regular ListView and then perform the animation in onListItemClick.
The animation is similar to what I do at this link: Android animate drop down/up view proper
But only for a portion of the row view. The row view is implemented in following way in xml:
<somelayout>
<normal>
</normal>
<expanded>
</expanded>
</somelayout>
The normal is used without expand. When expand is activated the expanded is set to visible instead of gone. You need to keep control of setting it to gone again when closing (remember this is set at your convertviews which are recycled).
I can clarify further if needed, it's just quite a lot of code to put in.
That's what i did in this situations.
ObjectAnimator objectAnimator =
ObjectAnimator.ofPropertyValuesHolder(list1,
PropertyValuesHolder.ofInt("bottom",
currentlistHeight,currentlistHeight*2 ));
What this would do is that the height of the listView will get doubled and it would be animated.
If you set the current list height ZERO. this would act like a drawer.

Categories

Resources